4

MSDN describes how to create a batch build, but does not provide a way to automate different batches (and one click solution for the GUI)

This question describes conditionally invoking a second build but doesn't appear to suffice for more than two sequential configurations

This question addresses the same situation, but again only for two configurations


In my test case, each configuration:

  • defines its own MACROS (which impact source code)
  • is applicable to multiple projects (class libraries). The projects are interdependent and require a specific build order in the context of the current configuration

I would like visual studio to build multiple configurations sequentially with a single build command.

Can child configurations be nested under a parent configuration, and be executed sequentially by visual studio when the parent configuration is built?


UPDATE : ATTEMPTED SOLUTION 1 [2016-03-11]

In response to Stijn's suggested answer I've tried the following:

Setup DotNetFramework 4.5 WinForms solution with 3 test projects and with 6 Configurations:

  • CORE_DEBUG
  • CORE_RELEASE
  • EXTENDED_DEBUG
  • EXTENDED_RELEASE
  • Debug
  • Release

The Debug Configuration must:

  • NOT trigger it's own configuration build (i.e. 'Debug')
  • must trigger the CORE_DEBUG and EXTENDED_DEBUG Configurations in sequence

I've added the following modified target to the first project's project file:

<Target Name="AfterBuild" Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">

Building with the 'Debug' Configuration now, causes an EXTENDED_RELEASE build to trigger. Having a look at the solution file, I see that Visual Studio decided to automatically link 'Debug' to 'EXTENDED_RELEASE':

    {4F9706AA-26A9-483C-81C4-22E301C54C89}.Debug|Any CPU.ActiveCfg = EXTENDED_RELEASE|Any CPU
    {4F9706AA-26A9-483C-81C4-22E301C54C89}.Debug|Any CPU.Build.0 = EXTENDED_RELEASE|Any CPU

Removing the above two lines from the solution file doesn't help, since Visual Studio just regenerates them. In summary this now has two undesirable outcomes:

  1. Visual Studio executes a 'Debug' build for Project1
  2. Visual Studio then executes an 'EXTENDED_RELEASE' for Project2 and Project3

Conclusion: While this approach can work, it also (first) performs debug and release configuration builds respectively. Visual Studio also lists all 6 Configurations in the build menu (we only want Debug and Release to be visible, and behind the scenes Debug must trigger CORE_DEBUG and EXTENDED_DEBUG, and Release must trigger CORE_RELEASE and EXTENDED_RELEASE)


UPDATE : ATTEMPTED SOLUTION 2 [2016-03-16]

Moving on to a makefile project solution: I've created a makefile project as specified by stijn's answer below, and it worked perfectly!

Conclusion : This is the preferred solution in my opinion because it gives the user the most power and ability to control exactly how the build(s) must be executed and how the configurations must be handled.

Community
  • 1
  • 1
Fortmann
  • 433
  • 6
  • 20

1 Answers1

3

The principle of the second SO question can be adjusted to build more than one configuration/platform sequentially by just invoking MsBuild multiple times. For instance:

<Target Name="AfterBuild" Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
  <MSBuild Projects="$(MySolution)" Properties="Configuration=Release;Platform=x86"/>
  <MSBuild Projects="$(MySolution)" Properties="Configuration=Debug;Platform=x64"/>
  <MSBuild Projects="$(MySolution)" Properties="Configuration=Release;Platform=x64"/>
</Target>

This can be cleaned up by using item batching, removing the condition and instead automatically determining which config is invoked and then only building the others etc but that's a bit out of scope here.

I'm not really convinced doing this in an AfterBuild target is the best way though, because then you'd need to adjust one of your 'normal' projects to also trigger a build of everything else. An alternative is to add a MakeFile Project to your solution, set up it's dependencies so that it comes last in the build order (at least if that is what you need), and set it's command line to invoke msbuild in a way similar as described above. You can even keep all logic in the same project file: set the 'Build Command Line' to

msbuild $(MsBuildThisFile) /t:CustomBuild /p:Configuration=$(Configuration);Platform=$(Platform)

so building the project will 'recurse' and make it call itself again with the same properties as called with by VS, but executing the CustomBuild target where you can then build your other projects/solutions to taste.

EDIT re: update You're almost there, but you have to go to Configuration Manager and make sure the configurations are setup properly to begin with. From the start:

  • create new solution, add 3 projects
  • right-click solution, select Configuration Manager
  • in the Active solution configuration combobox select new
  • enter CORE_DEBUG for name, select DEBUG under Copy settings from and make sure the Create new project configurations is checked like this
  • repeat for other configurations
  • for EXTENDED_RELEASE for instance, it should now look like enter image description here
  • you probably did most of this already, but somehow Debug got assigned to EXTENDED_RELEASE somehow so that is one thing you should fix; you could do that by editing the solution manually but instead of removing lines you'd have to edit them to be correct else VS just adds them again, as you noticed

Now open first project in a text editor and near the end of the file where AfterBuild is already inserted but commented out, add

<ItemGroup>
  <Configurations Condition="'$(Configuration)'=='Debug'" Include="CORE_DEBUG;EXTENDED_DEBUG" />
  <Configurations Condition="'$(Configuration)'=='Release'" Include="CORE_RELEASE;EXTENDED_RELEASE" />
  <Projects Include="$(SolutionDir)WindowsFormsApplication1.csproj;$(SolutionDir)WindowsFormsApplication2.csproj;$(SolutionDir)WindowsFormsApplication3.csproj" />
</ItemGroup>
<Target Name="AfterBuild" Condition="'@(Configurations)' != ''">
  <Message Text="Projects=@(Projects) Configuration=%(Configurations.Identity)" />
  <MSBuild Projects="@(Projects)" Targets="Build" Properties="Configuration=%(Configurations.Identity)" />
</Target>

you might need to adjust the paths to the projects. This will build CORE_DEBUG and EXTENDED_DEBUG for Debug builds, and likewise for Release builds. AfterBuild is skipped when the Configurations ItemGroup is empty, i.e. when not building Debug or Release which is exactly the point.

EDIT re: makefile

You can specify multiple commands for the makefile commandline. Click the arrow next to the 'Build Command Line' box and select '' To be sure you have everything right, Configuration Manager has to be set up to only build the makefile project for Debug/Release like:enter image description here

and the makefile project's commandline looks like enter image description here

Alternatively, and I'd prefer this myself, you create an msbuild file with the same content as above:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <Configurations Condition="'$(Configuration)'=='Debug'" Include="CORE_DEBUG;EXTENDED_DEBUG" />
    <Configurations Condition="'$(Configuration)'=='Release'" Include="CORE_RELEASE;EXTENDED_RELEASE" />
    <Projects Include="$(SolutionDir)WindowsFormsApplication1.csproj;$(SolutionDir)WindowsFormsApplication2.csproj;$(SolutionDir)WindowsFormsApplication3.csproj" />
  </ItemGroup>
  <Target Name="Build" Condition="'@(Configurations)' != ''">
    <Message Text="Projects=@(Projects) Configuration=%(Configurations.Identity)" />
    <MSBuild Projects="@(Projects)" Targets="Build" Properties="Configuration=%(Configurations.Identity)" />
  </Target>
</Project>

and your makefile command then invokes that file like

msbuild /path/to/msbuildfile /t:Build /p:Configuration=Debug;SolutionDir=$(SolutionDir)
Community
  • 1
  • 1
stijn
  • 34,664
  • 13
  • 111
  • 163
  • Thanks @stijn, I've tried both AfterBuild in the csproj file, and a makefile but unfortuantely both do not work for me (unable to conditionally invoke the required platform - the "build" target simply doesn't trigger from MSBuild's recursive invocation (I did double check conditions), the makefile project does not allow me to specify multiple project files - if i specify a solution file instead then it does not allow me to pass on targets to projects, and does not allow target definitions in the solution file). I spend 10 hours on it and gave up - will just have to build twice, manually. – Fortmann Mar 09 '16 at 17:55
  • I've used things like this myself without any of the problems you mention so maybe you're just lacking the msbuild experience/knowledge: it definitley is doable. If you edit your question and state clearly what platforms/configurations/targets you want built, and a (shortified) example of your solution/project/directory structure I can post a full working sample. – stijn Mar 09 '16 at 19:41
  • I've updated my question with the first attempt and its results (based on your first suggestion) - perhaps you can spot the problem? – Fortmann Mar 11 '16 at 09:57
  • see update; tested it here from scratch to make sure it works and it does – stijn Mar 12 '16 at 09:25
  • That is much better - VS now builds both Configurations for all 3 projects. However! - It undesirably still builds Debug first, or Release first! Why can we not disable that action and skip directly to our specific configuration builds? – Fortmann Mar 14 '16 at 15:57
  • As a workaround I've simply set the output path for each Projects' "Debug" and "Release" builds to the temp obj folder. I would really like to see a way to tell VS to build exactly only what it should (i.e. there should be only 6 builds, 3 per project) – Fortmann Mar 14 '16 at 16:00
  • Unfortunately the usage of the Configuration and Project include directives, now also causes these non-code items to be shown as items in the solution explorer :/ There seems to be no end to the unexpected and unwanted results of the best that Microsoft has to offer – Fortmann Mar 14 '16 at 17:00
  • I'm not following: you want 3 builds per projec so I assume that's debug/core_debug/extended_debug? Then why do you say it shouldn't build debug first? Or else If you don't want debug or release builds why don't you just delete those configurations and then have e.g. core_debug trigger extended_debug? – stijn Mar 14 '16 at 19:51
  • 1
    Anyway, problem is you're swimming against the stream here - VS is one config/platform or else batch build. Anything more is usually done by writing extensions or command line msbuild. The latter, if all you want is basically single-click builds of multiple configs, is then the easiest imo: create a seperate msbuid file which does just that, and invoke it as an external tool (to which you can also bind a keyboard shortcut), see Tools->external tools... – stijn Mar 14 '16 at 19:55
  • Hi Stijn, There must only be 4 Configurations: CORE_DEBUG, EXTENDED_DEBUG, CORE_RELEASE and EXTENDED_RELEASE. I do NOT want the default Debug or Release build at all. There are 3 projects. The 4 builds must apply to all 3 projects. The only reason why I "need" the debug configuration is because Visual studio needs an entry point (a 'handle') in order to invoke the other builds that I want (CORE_DEBUG and EXTENDED_DEBUG). In other words, I want to run "Debug" and VS must do nothing with it, except invoke CORE_DEBUG and EXTENDED_DEBUG – Fortmann Mar 15 '16 at 11:51
  • yes, doing everything oneself (properly and without unwanted Microsoft automation) seems necessary the moment a requirement doesn't fit the microsoft cookie cutter mold. – Fortmann Mar 15 '16 at 11:56
  • True - what it comes down to is selecting both configs manually and building them manually. However, I dislike having not-applicable build options available for the next developer who comes along. It should be simple and automated. If I go with a custom build command, then the default build (from the IDE) is now an invalid, but available option to the next developer. – Fortmann Mar 15 '16 at 11:59
  • *I want to run "Debug" and VS must do nothing with it, except invoke CORE_DEBUG and EXTENDED_DEBUG* then adding a makefile project which is only active for Debug/Release builds is probably the way to go, while in configuration manager you disable builds of the other projects for Debug/Release (actually then you can just get rid of those configurations for the actual projects all together) – stijn Mar 15 '16 at 15:00
  • I've tried the makefile solution again, and updated my question. Still not working :( – Fortmann Mar 16 '16 at 15:42
  • PERFECT!! - The multiple msbuild commands was the last missing link I needed. This now does _exactly_ what was needed. Thank you! – Fortmann Mar 16 '16 at 17:16