blogs.conchango.com

welcome to the conchango blogging site
Welcome to blogs.conchango.com Sign in | Join | Help
in Search

James Dawson's Blog

Using Visual Studio Solution Files with MSBuild

As previously discussed by Simon, there are issues with pointing MSBuild at a Visual Studio solution file to build your project assemblies - the alternatives are to either build each of the projects individually (using <MSBuild/> tasks) or to call VS itself to build the solution (the SDC Build Tools project has a custom task to easily do this).

The former approach causes some maintenance headaches by requiring the MSBuild script to be updated anytime a project is added or removed from the solution - whereas the latter option means you must have Visual Studio installed (which was supposed to be one of the benefits of using MSBuild) and can also result in some referencing issues the first time you build a solution after project changes.

In order to try and get the best of boths worlds, I started thinking about dynamically generating an MSBuild script with all the tasks needed to build each VS project referenced by the targetted .sln file (i.e. the first of the above approaches, but with all the leg-work automated).  My preferred tool for such things (since being introduced to it by Howard) is the excellent CodeSmith .

By running the template below prior to calling MSBuild, the tasks needed to build all the Solution's projects are written to a .targets file that can be <Import'd by the main MSBuild script - in my case this 2-step process is wrapped by a simple batch file that gets called by CruiseControl.


<%--
Description: Generates an MSBuild script to build each of the Visual Studio
             projects found within the specified Visual Studio Solution file.
%>
<%@ CodeTemplate Language="C#" TargetLanguage="Text" Src="" Inherits="" Debug="False" Description="Generate MSBuild actions from Solution file" %>

<%@ Property Name="SolutionFile" Type="System.String" Default="" Optional="False" Category="Strings" Description="VS.NET Solution file to process" %>

<%@ Import Namespace="System.Diagnostics" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.Text.RegularExpressions" %>

<%
if ( !File.Exists(this.SolutionFile) )
{
    throw new ArgumentException("ERROR:\nUnable to find the VS.NET Solution file:\n" + this.SolutionFile);
}
else
{
    this.SolutionFile = Path.GetFullPath(this.SolutionFile);
}
%>
<?xml version="1.0" encoding="utf-8" ?>
<Project DefaultTargets="Build" xmlns="
http://schemas.microsoft.com/developer/msbuild/2003">
    <Target Name="BuildProjects">
<%
string contents;
using ( StreamReader sr = new StreamReader(this.SolutionFile) )
{
    contents = sr.ReadToEnd();
}

// The regular expression below extracts the project information from
// the relevant part of the solution file - the format of which seems to
// be the same in VS 2003 & 2005
Regex regex = new Regex("^Project\\(.*\\s=\\s\"(?<projectName>.*)\",\\s\"(?<projectPath>.*)\",");
MatchCollection matches = regex.Matches(contents);
if ( matches.Count > 0 )
{
    foreach ( Match match in matches )
    {
        string projectName = match.Groups["projectName"].Value;
        string projectPath = match.Groups["projectPath"].Value;
        Trace.WriteLine( string.Format("ProjectName: {0}\nProjectPath: {1}", projectName, projectPath) );
       
        // Make sure that the reference in the .sln file is really a project
        // and not just a Solution Folder
        if ( projectName != projectPath && projectPath.EndsWith("proj") )
        {
        %>
            <MSBuild Projects="<%=Path.Combine(Path.GetDirectoryName(this.SolutionFile),projectPath)%>" Targets="Clean;Rebuild" />
        <%
        }
    }
}
else
{
    throw new ApplicationException( string.Format("ERROR:\nThe specified Solution file contains no projects:\n{0}", this.SolutionFile) );
}
%>
    </Target>
</Project>

<script runat="template">
</script>

 

Published 22 July 2005 19:56 by james.dawson

Comments

No Comments
Anonymous comments are disabled
Powered by Community Server (Personal Edition), by Telligent Systems