If you are using MSBuild 4.0 (i.e. Visual Studio 2010) then you can now use a new technique that I outline at MSBuild: Extending the solution build
Over the past few months I have noticed a need by many people to place some specific steps into the process that is used when MSBuild is invoked on solution files. When people research this topic they quickly discover that the Visual Studio Solution file is NOT in the MSBuild format. MSBuild is able to consume these files, but you are not able to actually extend the process used for the solution as a whole.
Recently there was an entry at the MSDN MSBuild Forum related to this issue. So I figured I'd put my two cents into the discussion as well.
For some background, when MSBuild needs to build a solution file, it is converted in memory to an MSBuild project file. If you have the envrionment variable msbuildemitsolution set to the value of 1. Then this file will be written out to a file. The file name will be SOLUTION_NAME.sln.proj.
Ok, previously there was another entry on the MSDN Forum about how to set an Envrionment variable using MSBuild. To let you know where I'm going with this, I'd like to have MSBuild be responsible for creating this file and for me to add steps before and after the building of my solution. The task to create the envrionment variable is shown below, this was written by Keith Hill and is at the previous link
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
namespace Sedodream.MSBuild
{
///
/// Taken from http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=73225&SiteID=1
/// Written by Keith Hill
///
public class SetEnvVar : Task
{
private string _variable;
private string _value;
[Required]
public string Variable
{
get { return _variable; }
set { _variable = value; }
}
[Required]
public string Value
{
get { return _value; }
set { _value = value; }
}
public override bool Execute()
{
Environment.SetEnvironmentVariable(_variable, _value);
return true;
}
}
}
You can download this file at the bottom of this entry (SetEnvVar.cs).
So we need to take this file and create an assembly from it. Make sure to add Microsoft.Build.Framework and Microsoft.Build.Utilities to your project's references. Oh yeah you could skip this part of the process if you just make sure to set that envrionment variable, but that's no fun.
After you create this assembly place in a known location. I called this assembly Sedodream.MSBuild.dll and placed it in a folder named tasks one folder above the solution I was trying to build.
Now that we are done with that we need to create the msbuild file that will do the rest of the work for us.
The whole file is shown below and can be downloaded at the end of this blog (DreamCatcher_SlnBuild.proj)
<Project InitialTargets="SetMSBuildEmit"
DefaultTargets="BuildSolution"
xmlns=http://schemas.microsoft.com/developer/msbuild/2003>
<PropertyGroup>
<SharedTasksDir>..\tasks\SharedTasksDir>
<EnvAssemblyFilename>Sedodream.MSBuild.dllEnvAssemblyFilename>
<BuildSolutionDir>.\BuildSolutionDir>
PropertyGroup>
<ItemGroup>
<SlnFiles Include="$(BuildSolutionDir)*.sln"/>
ItemGroup>
<UsingTask AssemblyFile="$(SharedTasksDir)$(EnvAssemblyFilename)" TaskName="SetEnvVar"/>
<Target Name="SetMSBuildEmit">
<SetEnvVar Variable="msbuildemitsolution" Value="1"/>
Target>
<Target Name="BuildSolution" DependsOnTargets="SetMSBuildEmit">
<MSBuild Projects="@(SlnFiles)" Targets="Build"/>
<CreateItem Include="*.sln.proj">
<Output TaskParameter="Include" ItemName="SolutionMSBuildFiles"/>
CreateItem>
<MSBuild Projects="$(MSBuildProjectFile)"
Targets="DoBuildSolution"
Properties="@(SolutionMSBuildFiles->'theSolution=%(Filename)%(Extension)')"/>
Target>
<PropertyGroup>
<DoBuildSolutionDependsOn>
BeforeDoBuildSolution;
CoreBuildSolution;
AfterDoBuildSolution
DoBuildSolutionDependsOn>
PropertyGroup>
<Target Name="DoBuildSolution" DependsOnTargets="$(DoBuildSolutionDependsOn)" />
<Target Name="BeforeDoBuildSolution">
<Message Text="*****Before building your solution*****" Importance="high"/>
Target>
<Target Name="CoreBuildSolution">
<MSBuild Projects="$(theSolution)" Targets="Build"/>
Target>
<Target Name="AfterDoBuildSolution">
<Message Text="###After building your solution######" Importance="high"/>
Target>
Project>
Now all you need to do is to place this file into the folder that contains your solution and call msbuild on it with:
>msbuild.exe DreamCatcher_SlnBuild.proj /t:BuildSolution
The DefaultTargets is set to BuildSolution so you can take that off actually.
The are many advantages to this solution like:
1) You extend the solution build process in similar ways as extending the project build proces
2) You can re-use any existing MSBuild tasks
3) You can add more steps to the build process easily
4) You can place this file into source control and all team members can use it.
If you need more info please let me know, I would explain further now but I'm not feeling very well currently.
Sayed Ibrahim Hashimi
I'm getting a 404 when I try to download the SetEnvVar.cs file
the DreamCatcher_SlnBuild.proj works fine
Cheers,
Steve C.
Sayed Ibrahim Hashimi
since the build process executes within one appdomain (save for tasks explicitly made for running in their own), I store the data in a singleton (static), and use a set of tasks that can set/get this data. Seems to work.
Using this I can also run a task once at the start of the solution build and a task at the end.
Check it out here:
http://mawi.org/ManagingTheSolutionBuildOfMSBuild.aspx
Feedback welcome!
Best regards!
There is under VS an action :
right click on your solution
select "batch build"
click "select all"
click "clean"
this performs a global clean of all projects.
I have no idea of what does VS is doing when you use this function. But i wonder : if there is a button thtat allow you to clean all projects, then there must be a way to do the same thing, but for an other target, like "DoSomething All". Then maybe we can also do :
"DoSomething All" + "Build All"
A kind of "pre solution build event".
The tip you gave is a bit "crapy", maybe not easily intergrated under VS, so i was wondering if you were aware of this "Clean All" button under VS and based in this, if you have any idea of how can this be implemented...
Sorry, maybe my post is not very clear.
Elise
Thanks,
Nabeel.
Has this changed with VS2008? I'm getting "ASPNETCOMPILER : error ASPRUNTIME: The precompilation target directory (C:\Build\Source\TempBuildDir\) cannot be in the same tree as the source application directory (C:\PRTBuild\Source\)." When I try to compile a solution file using this method. It used to work (and still does) for a similar VS2005 solution file.
It's been a couple of years since I looked at MSBuild, but most of it's coming back to me. Any ideas on what I should be looking at to alter?
Thanks!
-John
Comments are closed.