The problem with the solution architecture of Visual Studio is that you cannot customize it, since it’s not a msbuild file (I hope the MSBuild team change this.) This means for any non-trivial build, you are likely to implement your own root build file in order to support custom targets (for testing, deploying, etc). This subjects you to the vagaries and nuances of msbuild that you’re normally shielded from by Visual Studio.
A problem I ran into was with C# projects (.csproj) that were referencing a C++ project (.vcxproj). For 32-bit builds, a csproj uses the platform ‘x86′, while a vcxproj used ‘Win32′. Hence if you attempt to build your csproj file, you will get an error like:
C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\Microsoft.Cpp.InvalidPlatform.Targets(23,7): error MSB8007: The Platform for project ‘blah.vcxproj’ is invalid. Platform=’x86′. You may be seeing this message because you are trying to build a project without a solution file, and have specified a non-default Platform that doesn’t exist for this project. [C:\dev\spike\blah.vcxproj]
So you need to find a way to map x86->Win32 for vcxproj only. Luckily, there is the somewhat cryptic and barely documented task
AssignProjectConfiguration. I’m not going to pretend I really understand how it works, but from the docs, and some peeking under the hood, I kludged together the following working solution:
<Target Name="PrepProjectConfiguration" BeforeTargets="PrepareForBuild" Condition="'$(Platform)' == 'x86'"> <AssignProjectConfiguration CurrentProjectConfiguration="$(Configuration)" CurrentProjectPlatform="$(Platform)" ProjectReferences="@(ProjectReference)" ResolveConfigurationPlatformUsingMappings="true"> <Output TaskParameter="AssignedProjects" ItemName="ProjectReferenceWithConfiguration" /> </AssignProjectConfiguration> <ItemGroup> <ProjectReference Remove="@(ProjectReferenceWithConfiguration)" /> </ItemGroup> <Message Text=" regular reference %(ProjectReference.Identity)" /> <Message Text="re-mapped reference %(ProjectReferenceWithConfiguration.Identity) - %(ProjectReferenceWithConfiguration.Configuration)|%(ProjectReferenceWithConfiguration.Platform)" /> </Target>
To explain this:
- Why wire up before the target
PrepareForBuild? Running msbuild with detailed output indicated this was a decent enough place to plop this in.
- Why the condition for x86? I’m at a loss as to why, but this task behaves differently for x64. Anyway, we only need to solve this problem for x86.
- You’ll notice I have to remove the output of
ProjectReferenceitem group. Without this, the csproj will attempt to build the vcxproj twice, once for Win32 and again for x86.