How can I use a single Visual Studio solution to build both x86 and x64 at the same time?

35,991

Solution 1

We do something similar to build core assemblies for .NET Compact Framework.

Try this:

<Target Name="AfterBuild">
    <MSBuild Condition=" '$(Platform)' == 'x86' " Projects="$(MSBuildProjectFile)" Properties="Platform=x64;PlatFormTarget=x64" RunEachTargetSeparately="true" />
</Target>

Solution 2

Importing a project in such manner works for me in Visual Studio 2010:

TestProject64.vcxproj

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="TestProject.vcxproj" />
  <ItemGroup Label="ProjectConfigurations">
    <ProjectConfiguration Include="Release|x64">
      <Configuration>Release</Configuration>
      <Platform>x64</Platform>
    </ProjectConfiguration>
  </ItemGroup>
  <PropertyGroup Label="Globals">
    <ProjectGuid>{B7D61F1C-B413-4768-8BDB-31FD464AD053}</ProjectGuid>
  </PropertyGroup>
</Project>

TestProject64.vcxproj.filters

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="TestProject.vcxproj.filters" />
</Project>

TestProject.vcxproj has two configurations defined inside: Release|x86 and Release|x64. As you can see, TestProject64.vcxproj has only the Release|x64 configuration. Defining of at least one configuration in TestProject64.vcxproj is necessary, otherwise Visual Studio will not be able to add TestProject64.vcxproj to a solution.

Now it's possible to include both TestProject.vcxproj and TestProject64.vcxproj to the same solution and build Release|x86 and Release|x64 at the same time.

Solution 3

I think the best way of doing this is to invoke MSBuild from the command line. It shouldn't need editing of MSBuild files. Just run

msbuild myproj.sln /p:Configuration="Debug|Win32"
msbuild myproj.sln /p:Configuration="Debug|x64"

I assume that if a developer is using Visual Studio then they'll only be generating the DLL files so they can debug with them, and that you have a separate build process if you're actually deploying the DLL files.

Solution 4

For C++, and if it's a project whose files/settings don't change often, one way to do it is create two projects within the solution, with both projects referring to the same source files. Then, in x64 builds, set one project to build 64-bit and the other 32-bit. (In x86 builds, set one as 32-bit and turn off the other.)

We've been using this for a while and it works fine.

Of course, you have to be careful that any changes you make to one are also made to its copy. i.e. if you add/remove a file or change its build setting, you have to do it in two places. Source-code changes still only need to be done once, because there's still only one copy of each source file.

And, of course, you may decide that doing this is more complex/risky than switching away from using the IDE. In our case it's worked really well, though.

Share:
35,991
PeteVasi
Author by

PeteVasi

Updated on December 30, 2020

Comments

  • PeteVasi
    PeteVasi over 3 years

    I've got an x86 Visual Studio solution with many project files in it. Some of the DLL files are designed to work as plug-ins to other applications on a user's system.

    We're expanding some of the DLL files to be able to support 64-bit applications. I'd like to set up the solution/projects so that just hitting "Build" will build both the x86 and x64 versions of those DLL files. The solution contains both C++ and C# projects.

    I realize that "Batch Build" is capable of building both, though it would be more convenient if developers could just click the same button as they have previously and have all of the output DLL files generated.

    Here are a couple of the modifications that I've tried to a test project, but that I haven't gotten to work:

    I've tried modifying the <Target Name="AfterBuild"> to try:

    <Target Name="AfterBuild" Condition=" '$(Platform)' == 'x86' ">
      <PropertyGroup>
        <Platform>x64</Platform>
        <PlatformTarget>x64</PlatformTarget>
      </PropertyGroup>
      <CallTarget Targets="Build"/>
    </Target>
    

    But that results in the following error:

    C:\Windows\Microsoft.NET\Framework\v3.5\Microsoft.Common.targets(565,5): error MSB4006: There is a circular dependency in the target dependency graph involving target "Build".

    I think my conditions will prevent infinite recursion, but I understand how MSBuild could not see it that way.

    I've also tried:

    <Project DefaultTargets="MyBuild86;MyBuild64" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
    ...
    <Target Name="MyBuild86">
      <PropertyGroup>
        <Platform>x86</Platform>
        <PlatformTarget>x86</PlatformTarget>
      </PropertyGroup>
      <CallTarget Targets="Build"/>
    </Target>
    <Target Name="MyBuild64">
      <PropertyGroup>
        <Platform>x64</Platform>
        <PlatformTarget>x64</PlatformTarget>
      </PropertyGroup>
      <CallTarget Targets="Build"/>
    </Target>
    

    But my DefaultTargets appears to be ignored from within the Visual Studio IDE.

    Last, I've tried creating a separate project that imports the first project:

    <?xml version="1.0" encoding="utf-8"?>
    <Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
      <PropertyGroup>
        <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
        <Platform>x64</Platform>
        <PlatformTarget>x64</PlatformTarget>
        <ProductVersion>9.0.30729</ProductVersion>
        <SchemaVersion>2.0</SchemaVersion>
        <OutputPath>..\$(Configuration)\x64\</OutputPath>
        <ProjectGuid>{A885CAC3-2BBE-4808-B470-5B8D482CFF0A}</ProjectGuid>
      </PropertyGroup>
      <Import Project="BuildTest.csproj" />
    </Project>
    

    And this so far has shown the most promise. However, Visual Studio seems to ignore my OutputPath setting from this new project and instead outputs the EXE/DLL file to the path specified in the original project. There isn't any PropertyGroup block that I can see that is being executed in the original project to override this, so I'm not sure what's happening.

  • PeteVasi
    PeteVasi over 14 years
    Yes, I've been working with the MSBuild files (manually editing the *.csproj anyway). I still haven't been able to get it to work.
  • PeteVasi
    PeteVasi over 14 years
    Yes, there's a separate build process when deploying the DLLs that can handle whatever command-line goodness and packaging that we need. But I want the developer machines running just Visual Studio to be able to easily hit "Build" and then be able to test both the x86 and x64 plugins. (Also slightly relevant, not everything in the solution needs an x64 version. The configuration app can remain 32-bit only.)
  • the_mandrill
    the_mandrill over 14 years
    For that particular use case I can't think of any other way of doing it than to set up a custom build rule that calls msbuild to build the other architecture.
  • PeteVasi
    PeteVasi over 14 years
    I've been toying with various custom build rules to try to get this to work, but haven't quite gotten there yet. I've modified my original question to include all of my attempts.
  • PeteVasi
    PeteVasi over 14 years
    Seems to work quite well, thanks. Now to figure out something similar for the C++ projects...
  • Woodman
    Woodman over 8 years
    Worked well for C++ project. Just changed target platform in condition from 'x86' to 'Win32'
  • nelsonjchen
    nelsonjchen almost 8 years
    YMMV, but for me, C++ project references weren't reloaded and static libraries linking related targets were not re-run and thus linking was broken. Alas, I guess I am going back with the equivalent of the dual msbuild call.
  • NN_
    NN_ almost 6 years
    @crazysim What is the solution you used in the end ? Thanks.
  • nelsonjchen
    nelsonjchen almost 6 years
    @NN_ I honestly don't remember what I did and why and what for. It might have been building Deviare, a an alternative to Microsoft Detours. From reading what I wrote, I probably configured my continuous integration system to just do two msbuild commands, Win32 then x64, and giving up on the dream of a single msbuild command. In other words, basically the answer below: stackoverflow.com/a/1575053/286021
  • NN_
    NN_ almost 6 years
    What did you do in VS ? Do you have 2 projects or one project which invokes build for other platform ?
  • NN_
    NN_ almost 6 years
    I just used the same technique from above and it works. The only thing C++ missing is AfterBuild target but it is can be workarounded: <Target Name="Build64" AfterTargets="Build"> <MSBuild Condition="'$(Platform)'=='Win32'" Projects="$(MSBuildProjectFile)" Properties="Platform=x64;PlatFormTarget=x64" RunEachTargetSeparately="true" /> </Target> </Project>
  • NN_
    NN_ almost 6 years
    The only problem with this solution is that you cannot build 32bit and 64bit in parallel.
  • Peter Mortensen
    Peter Mortensen over 4 years
    Can you elaborate a little bit?
  • Paul B.
    Paul B. over 4 years
    Add a new VisualC++/Other/Malkefile project to your solution. Go to the project properies and Set the project's build command line to call cmd that contailnt two lines above.