I'm trying to edit my project file to enable me to have a project that builds multiple build configs at once. I've done this using a batching approach and using the MSBuild task (see below).
If I run the script, I get an this error:
Error 103 The OutputPath property is not set for project "ThisMSBuildProjectFile.csproj". Please check to make sure that you have specified a valid combination of Configuration and Platform for this project. Configuration='Debug' Platform='AnyCPU'.
I get this if I add or omit the OutputPath from the MSBuild task. If used the VS2010 debugger to step through the script and the MSBuild Task is called - the debugger steps into the file again and then steps into OutputPath, so afaik, it should pick that value up, no?
Any help for this would be greatly appreciated - it's driving me crazy. Thanks, Paul.
ThisMSBuildProjectFile.csproj (surplus stuff taken out):
<?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build"> <!-- Only Import normal targets if not building multiple projects --> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" Condition="'$(Configuration)|$(Platform)' != 'AllBuild|AnyCPU' "/> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == '' "> <DebugType>pdbonly</DebugType> <Optimize>true</Optimize> <OutputPath>C:\Folder\Etc\Output\$(Configuration)\</OutputPath> <OutDir>C:\Folder\Etc\Output\$(Configuration)\</OutDir> <BaseOutputPath>C:\Folder\Etc\Output\$(Configuration)\</BaseOutputPath> <DefineConstants>TRACE</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> </PropertyGroup> <!-- Common --> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <Platform>AnyCPU</Platform> <!-- Repeated properties from above here (including, of course, OutputPath) --> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <!-- Repeated properties from above here (including, of course, OutputPath) --> </PropertyGroup> <ItemGroup> <Projects Include="C:\Folder\Etc\ThisMSBuildProjectFile.csproj" /> </ItemGroup> <!-- Call this project file again, but with a different configuration - if this was working, this would call multiple build configs --> <Target Name="Build" Condition="'$(Configuration)|$(Platform)' == 'AllBuild|AnyCPU' "> <Message Text="hm!"/> <!-- Tried thiswith and without the OutputPath property - makes no difference. --> <MSBuild Projects="@(Projects)" Properties="Configuration=Debug;OutputPath=C:\Folder\Etc\Output\" ToolsVersion="4.0" Condition="'$(Configuration)|$(Platform)' == 'AllBuild|AnyCPU' "/> </Target> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'AllBuild|AnyCPU' "> <!-- Repeated properties from above here (including, of course, OutputPath) --> </PropertyGroup> <!-- Project files --> <ItemGroup> <Reference Include="System" /> <Reference Include="System.Core" /> </ItemGroup> <ItemGroup> <Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Blah\Blah.cs" /> </ItemGroup>
You can use MSBuild to build multiple projects faster by running them in parallel. To run builds in parallel, you use the following settings on a multi-core or multiple processor computer: The -maxcpucount switch at a command prompt. The BuildInParallel task parameter on an MSBuild task.
Visual Studio determines the build order and calls into MSBuild separately (as needed), all completely under Visual Studio's control. Another difference arises when MSBuild is invoked with a solution file, MSBuild parses the solution file, creates a standard XML input file, evaluates it, and executes it as a project.
To build a specific target of a specific project in a solution. At the command line, type MSBuild.exe <SolutionName>. sln , where <SolutionName> corresponds to the file name of the solution that contains the target that you want to execute.
It is important to realize that when you use a "MSBuild" task, a new child MSBuild process will be started. The implication of this is that any items and properties you define in the parent MSBuild process will not be automatically passed to/visible from the child MSBuild process unless you explicitely pass them via Properties
attribute on MSBuild
element (as in <MSbuild Properties="..." />
).
To answer your question, I wrote the following self-contained example that runs a child MSBuild project for all the specified configurations:
First, create a directory for your MSBuild experiment (for example I used C:\temp\msbuildtest
)
In this directory, create the first file, main.proj
:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build" ToolsVersion="4.0"> <ItemGroup> <ConfigList Condition=" '@(ConfigList)' == '' and $(Config) != '' " Include="$(Config.Split('+'))" /><!-- parse all requested configurations into a list --> <ConfigList Condition=" '@(ConfigList)' == '' " Include="Debug" /><!-- if no configurations were specified, default to Debug --> </ItemGroup> <!-- Build the child project for each requested configuration. --> <Target Name="Build"> <MSBuild Projects="$(MSBuildProjectDirectory)\child.proj" Properties="Configuration=%(ConfigList.Identity);OutputPath=$(MSBuildProjectDirectory)\bin\%(ConfigList.Identity)" Targets="Build" /> </Target> </Project>
In the same directory, create the second file, child.proj
(in your case this would be the actual C# project you're trying to build, but because I'm trying to illustrate my point, I am using a simple child project that instead of running C# compiler just prints values of properties :-) )
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build" ToolsVersion="4.0"> <Target Name="Build"> <Message Text="Building configuration $(Configuration) with output path $(OutputPath)" Importance="High" /> </Target> </Project>
Now you can run the example. First the default, if you don't explicitly specify configurations to build:
C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\msbuild main.proj > (cut the noise) > Build: > Building configuration Debug with output path C:\temp_c\d\bin\Debug
And then explicitly specified multiple configurations:
C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\msbuild main.proj /property:Config=Debug+Release+Staging+Production > (cut the noise) > Build: > Building configuration Debug with output path C:\temp_c\d\bin\Debug > Build: > Building configuration Release with output path C:\temp_c\d\bin\Release > Build: > Building configuration Staging with output path C:\temp_c\d\bin\Staging > Build: > Building configuration Production with output path C:\temp_c\d\bin\Production
You should be able to adapt this technique to your situation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With