Search code examples
visual-studio-2010visual-studiovisual-studio-2012msbuildmsbuild-task

How can I create a cycle of compiling my project with incrementing of some option?


I wrote a C# template for creating of the .Net extensions for AutoCAD. Before, for each AutoCAD version it is was necessary to point the individual referenses set, the output directory, the target .Net Framework Platform, etc. Exist many versions of AutoCAD: AutoCAD 2009, 2010, ..., 2015. Now my template do it instead of me. My csproj-file has the CAD_Year property:

<PropertyGroup>
  <CAD_Year>2013</CAD_Year>
  <Min_Year>2009</Min_Year>
  <Max_Year>2015</Max_Year>
</PropertyGroup>

When I change CAD_Year value (manually edit this option in the csproj-file) - all settings of my project do change too according target AutoCAD version. It works fine.

But I need to compile my code for all versions of AutoCAD always... It is inconvenient to change the CAD_Year every time for this... :(((

How can I create the cycle of compiling my project for the versions Min_Year, ..., Max_Year when I press the Rebuild Solution menu item?


Solution

  • If you add this to your project file:

    <ItemGroup>
      <CADYears Include="2013;2014;2015"/>
    </ItemGroup>
    
    <Target Name="BatchRebuild">
      <Msbuild Projects="$(MsBuildThisFile)" Targets="Rebuild" Properties="CAD_Year=%(CADYears.Identity)"/>
    </Target>
    

    and call

    msbuild <path_to_projectfile> /t:BatchRebuild
    

    on the commandline, it will build path_to_projectfile 3 times each with a different CAD_Year property.

    To get this invoked by VS is trickier since you need to override the Rebuild target, but this for instance works for VS2013 (Actualrebuild target was copied from the Rebuild target in C:\Program Files (x86)\MSBuild\12.0\Bin\Microsoft.Common.CurrentVersion.targets):

    <ItemGroup>
      <CADYears Include="2013;2014;2015"/>
    </ItemGroup>
    
    <Target Name="ActualRebuild"
            Condition=" '$(_InvalidConfigurationWarning)' != 'true' "
            DependsOnTargets="$(RebuildDependsOn)"
            Returns="$(TargetPath)"/>
    
    <Target Name="BatchRebuild">
      <Msbuild Projects="$(MsBuildThisFile)" Targets="ActualRebuild" Properties="CAD_Year=%(CADYears.Identity)"/>
    </Target>
    
    <Target Name="Rebuild">
      <Msbuild Projects="$(MsBuildThisFile)" Targets="BatchRebuild"/>
    </Target>
    

    Edit Since the template system in VS tries to copies ItemGroups it finds in the project root (which seems like a bug to me, or at the least a very annoying feature) you can work around that by using a property and converting it into an item when needed:

    <PropertyGroup>
      <CADYears>2013;2014;2015<CADYears/>
    </PropertyGroup>
    
    <Target Name="BatchRebuild">
      <ItemGroup>
        <CADYearsItem Include="$(CADYears)"/>
      </ItemGroup>
      <Msbuild Projects="$(MsBuildThisFile)" Targets="Rebuild" Properties="CAD_Year=%(CADYearsItem .Identity)"/>
    </Target>
    

    Note: in the project you posted in the link you are invoking the Rebuild target in the Afterbuild target. I didn't try it, but that will almost certainly lead to infinite recursion. So you should stick to a solution like posted above with a seperate target.