Fixing csproj builds that reference vcxproj files using AssignProjectConfiguration task

Written by Troy on August 25, 2012 Categories: Uncategorized Tags: , , , , , , , , , , ,

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 AssignedProjects from the ProjectReference item group. Without this, the csproj will attempt to build the vcxproj twice, once for Win32 and again for x86.

Happy building!

8 Comments

8 Comments

  • Samer Adra says:

    Thanks, this was very valuable to me! I don’t know why such hackery is required for something as simple as a C# project referencing a C++ project!

    I did have to add a bit to your solution before it would work for me.

    true
    true

    Basically just copied that from what the Microsoft Common targets were doing, to get it to actually build the references.

    -Samer

  • Samer Adra says:

    The XML snippet from my previous comment got displayed as “true\r\ntrue”, so let me try again…

    <ItemGroup>
    <ProjectReferenceWithConfiguration>
    <BuildReference Condition=”‘%(ProjectReferenceWithConfiguration.BuildReference)’ == ””>true</BuildReference>
    <ReferenceOutputAssembly Condition=”‘%(ProjectReferenceWithConfiguration.ReferenceOutputAssembly)’ == ””>true</ReferenceOutputAssembly>
    </ProjectReferenceWithConfiguration>
    </ItemGroup>

  • Troy says:

    Thanks for sharing, Samer!

  • Siro says:

    do you include this in the csproj or in the vcxproj?

    • troy says:

      Hi Siro, this goes in your csproj, to correctly invoke the build of your reference with the correct platform (x86)

  • Ronan Danno says:

    I have a similar problem, when building a managed C++ project, which references C# projects. I specify Platform=Win32 in my msbuild command line, which is OK for my C# project alone, or for a vcxproj with no reference to a csproj.

    I tried to insert the mentioned code block in both my vcxproj and my csproj, replacing “x86″ with “Win32″, but without success. This is probably because msbuild does not go through the same tasks/targets when building a vcxproj or a csproj.

    Maybe a hint:
    Looking into the detailed log, when it builds my vcxproj, it goes through the “ResolveProjectReferences” task, which sets the following property to its project references:
    SetPlatform = Platform=x86
    (I don’t see similar things when building with Platform=x64).
    Hence it fails with a message similar to yours:

    C:\Program Files (x86)\MSBuild\12.0\bin\Microsoft.Common.CurrentVersion.targets(617,5): error : The OutputPath property is not set for project ‘blah.csproj’. Please check to make sure that you have specified a valid combination of Configuration and Platform for this project. Configuration=’Release’ 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 Configuration or Platform that doesn’t exist for this project. [e:\some\path\blah\blah.csproj]

    Any idea?…

    • Ronan Danno says:

      I found a workaround to my problem above by adding this line in the first PropertyGroup (the one with no condition) in my csproj:
      Win32

      To have this to work, I also had to specify the attribute TreatAsLocalProperty=”Platform” in my Project root node, as follows:

      Without this attribute, Platform is considered a global variable, and cannot be overridden by PropertyGroup ‘s inside my csproj (see https://msdn.microsoft.com/en-us/library/ms171458.aspx#Anchor_4)

      Strangely, the IDE displays an “x86″ platform for this project, but editing it in the IDE does not alter the compiling behavior (ie compiling with Platform “x86″ or “Win32″ will actually compile “Win32″)

      Hope it can help sby else!

  • Ronan Danno says:

    XML snippets were removed from my previous comment, so let me try again:

    Add the following line in the first PropertyGroup (the one with no condition) in the csproj:
    <Platform Condition=” ‘$(Platform)’ == ‘x86′ “>Win32</Platform>

    And specify the attribute TreatAsLocalProperty=”Platform” in the Project root node, as follows:
    <Project DefaultTargets=”Build” xmlns=”http://schemas.microsoft.com/developer/msbuild/2003″ ToolsVersion=”12.0″ TreatAsLocalProperty=”Platform”>

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>