Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to configure a VS2012 solution for x86 and x64 simultaneously

We have a VS2012 .NET 4 product that has 2 different SKU's A and B which we currently build for x86 only. We also have the usual Configurations Debug and Release meaning we have 4 configurations currently.

  • DebugA
  • DebugB
  • ReleaseA
  • ReleaseB

Looking into one of the .csproj files it looks something like this

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'DebugA|x86' ">
    <OutputPath>..\bin\DebugA\</OutputPath>
</PropertyGroup> 
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseA|x86' ">
    <OutputPath>..\bin\ReleaseA\</OutputPath>
</PropertyGroup> 
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'DebugB|x86' ">
    <OutputPath>..\bin\DebugB\</OutputPath>
</PropertyGroup> 
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseB|x86' ">
    <OutputPath>..\bin\ReleaseB\</OutputPath>
</PropertyGroup>

Obviously adding x64 would double this from 4 to 8 different combinations, and VS also seems to add AnyCPU platform configs whenever it feels like it. Ensuring that all 8 are correctly configureed in 30+ projects takes a lot of clicking around in VS, and it is really easy to make mistakes.

I have read a few other SO questions where the problem of multi targeting is solved, and one of the suggestions for including different referencs for different platforms involved using ${Platform} in the reference path. I figured I could do something similar for my project config, so I tried this when trying to do multi-platform:

<PropertyGroup Condition=" '$(Configuration)' == 'DebugA' Or '$(Configuration)' == 'DebugB' ">
     <OutputPath>..\bin\${Platform}\${Configuration}\</OutputPath>
</PropertyGroup> 
<PropertyGroup Condition=" '$(Configuration)' == 'ReleaseA' Or '$(Configuration)' == 'ReleaseB' ">
     <OutputPath>..\bin\${Platform}\${Configuration}\</OutputPath>
</PropertyGroup> 

Which, in theory, should give me what I need for all 8 different combinations with just two blocks. But looking in VS now I can't see neitehr x86 nor x64 as available build platforms for the project. It looks as if the only way VS actually stores the build platforms is by encoding them as the freaking conditions on the propertygroups? Say it aint so...

Is there no way to make a "nice" looking multi platform .csproj that will work well with VS?

Could I create the .csprojs and then decide NOT to edit them in VS, trusting that msbuild will use the correct platforms, even though VS can't show any platforms in the property windows of the individual projects?

Edit:

It seems the queston was a bit confusing: to be clear, I want to know how to set up, maintain and overview the configuration of projects, and the build configuration of my solution, when there are many projects and eight combinations of config|platform. I know how to do this manually, but not without losing my mind or making a mistake on one of 200+ property pages.

like image 203
Anders Forsgren Avatar asked Apr 10 '13 08:04

Anders Forsgren


People also ask

How do I change a platform target from x86 to a CPU?

Select x86 in the Copy settings from drop-down list box. Click OK. In the Configuration Manager dialog, be sure the box in the Build column is checked for all projects in the solution. Click Close.

How do I change from x86 to x64 in Visual Studio?

To configure a project to target a different platformOn the menu bar, choose Build > Configuration Manager. In the Active solution platform list, choose a platform for the solution to target, and then choose the Close button.

What is x86 and x64 in Visual Studio?

Compiling for Any CPU is always an option, as you point out. That will allow the application to run as a 32-bit application (x86) on a 32-bit machine, and as a 64-bit application (x64) on a 64-bit machine.

How do I add solution configuration in Visual Studio?

In the Active solution configuration drop-down list, choose New. The New Solution Configuration dialog box opens. In the Name text box, enter a name for the new configuration. To use the settings from an existing solution configuration, in the Copy settings from drop-down list, choose a configuration.


1 Answers

If you don't mind having to change the project files manually once then you could put all the shared configuration in a configuration file and reference that from each project. In order to do that you need to first create your configuration file. This file is just a normal MsBuild file with all the information that you want to share between all the projects (like the build configurations). The file will look roughly like this:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="3.5"
         DefaultTargets="Build"
         xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <PropertyGroup>
        <!-- VS information -->
        <ProductVersion>9.0.30729</ProductVersion>
        <SchemaVersion>2.0</SchemaVersion>

        <!-- Default configuration -->
        <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
        <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
        <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
        <FileAlignment>512</FileAlignment>

        <!-- Project directories -->
        <AppDesignerFolder>Properties</AppDesignerFolder>
        <OutputPath>$(SolutionDir)\..\build\bin\$(Platform)\$(Configuration)\</OutputPath>
        <IntermediateOutputPath>$(SolutionDir)\..\build\temp\bin\obj\$(AssemblyName)\$(Platform)\$(Configuration)\</IntermediateOutputPath>

        <!-- Build configuration -->
        <ErrorReport>prompt</ErrorReport>
        <WarningLevel>4</WarningLevel>
        <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
    </PropertyGroup>
    <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
        <DebugSymbols>true</DebugSymbols>
        <DebugType>full</DebugType>
        <Optimize>false</Optimize>
        <DefineConstants>TRACE;DEBUG;CODE_ANALYSIS</DefineConstants>
    </PropertyGroup>
    <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
        <DebugType>pdbonly</DebugType>
        <Optimize>true</Optimize>
        <DefineConstants>TRACE;CODE_ANALYSIS</DefineConstants>
    </PropertyGroup>
    <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
        <DebugSymbols>true</DebugSymbols>
        <DebugType>full</DebugType>
        <Optimize>false</Optimize>
        <DefineConstants>TRACE;DEBUG;CODE_ANALYSIS</DefineConstants>
    </PropertyGroup>
    <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
        <DebugType>pdbonly</DebugType>
        <Optimize>true</Optimize>
        <DefineConstants>TRACE;CODE_ANALYSIS</DefineConstants>
    </PropertyGroup>
    <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
        <DebugSymbols>true</DebugSymbols>
        <DebugType>full</DebugType>
        <Optimize>false</Optimize>
        <DefineConstants>TRACE;DEBUG;CODE_ANALYSIS</DefineConstants>
    </PropertyGroup>
    <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
        <DebugType>pdbonly</DebugType>
        <Optimize>true</Optimize>
        <DefineConstants>TRACE;CODE_ANALYSIS</DefineConstants>
    </PropertyGroup>
    <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
  • The first PropertyGroup defines the overall constants, i.e. constants that are used by all projects for all build configurations. As you can see for the OutputPath you can use build variables like $(Platform) and $(Configuration) to determine the location of the binaries etc. etc.
  • The first PropertyGroup also has a bunch of settings normally defined by visual studio, e.g. ProductVersion. Technically you don't have to move those but moving them does reduce the clutter in your project files should you care about that.
  • The following sections define the different settings for the different build configurations.

Once you have defined the configuration file, say it's called BaseConfigurations.targets, then you have to edit your project files. Unfortunately you'll have to go through all the project files, but you'll only need to do this once. After you have linked the configuration file you can from then on change all the shared configurations by changing the configuration file.

A normal project file will look roughly like this:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ProjectGuid>{33017F71-5A1C-4113-9041-4DD3F58921D0}</ProjectGuid>
    <OutputType>Library</OutputType>
    <AppDesignerFolder>Properties</AppDesignerFolder>
    <RootNamespace>MyProject</RootNamespace>
    <AssemblyName>MyProject</AssemblyName>
    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
    <FileAlignment>512</FileAlignment>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <DebugSymbols>true</DebugSymbols>
    <DebugType>full</DebugType>
    <Optimize>false</Optimize>
    <OutputPath>bin\Debug\</OutputPath>
    <DefineConstants>DEBUG;TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <DebugType>pdbonly</DebugType>
    <Optimize>true</Optimize>
    <OutputPath>bin\Release\</OutputPath>
    <DefineConstants>TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
  <ItemGroup>
    <Reference Include="System" />
    <Reference Include="System.Core" />
    <Reference Include="System.Xml.Linq" />
    <Reference Include="System.Data.DataSetExtensions" />
    <Reference Include="Microsoft.CSharp" />
    <Reference Include="System.Data" />
    <Reference Include="System.Xml" />
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Class1.cs" />
    <Compile Include="Properties\AssemblyInfo.cs" />
  </ItemGroup>
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
       Other similar extension points exist, see Microsoft.Common.targets.
  <Target Name="BeforeBuild">
  </Target>
  <Target Name="AfterBuild">
  </Target>
  -->
</Project>

In order to link the configuration file you will need to:

  • Remove from the first PropertyGroup the that are already defined in your configuration file
  • Add the line <SolutionDir Condition="'$(SolutionDir)' == '' or '$(SolutionDir)' == '*undefined*'">$(MSBuildProjectDirectory)\..</SolutionDir>. This is not necessary if you only build from Visual Studio (because Visual Studio automatically defines the SolutionDir variable) but it is necessary if you also want to build your project via MsBuild. This line also assumes that each project is in it's own subdirectory and that the solution file is one directory up from each project file, i.e. your structure is something like:

    source
        MyProject
            MyProject.csproj
        MySolution.sln 
    
  • Just below the first PropertyGroup add the following line <Import Project="$(SolutionDir)\BaseConfiguration.targets" />. This indicates to MsBuild (and thus Visual Studio) that you want to import the configuration file.

  • Remove the build configurations
  • At the end of the file remove the line <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />. This is defined in your configuration file and is thus no longer needed.

After all this your project file should look something like:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
  <PropertyGroup>
    <SolutionDir Condition="'$(SolutionDir)' == '' or '$(SolutionDir)' == '*undefined*'">$(MSBuildProjectDirectory)\..</SolutionDir>
    <ProjectGuid>{33017F71-5A1C-4113-9041-4DD3F58921D0}</ProjectGuid>
    <OutputType>Library</OutputType>
    <RootNamespace>MyProject</RootNamespace>
    <AssemblyName>MyProject</AssemblyName>
  </PropertyGroup>
  <Import Project="$(SolutionDir)\BaseConfiguration.targets" />
  <ItemGroup>
    <Reference Include="System" />
    <Reference Include="System.Core" />
    <Reference Include="System.Xml.Linq" />
    <Reference Include="System.Data.DataSetExtensions" />
    <Reference Include="Microsoft.CSharp" />
    <Reference Include="System.Data" />
    <Reference Include="System.Xml" />
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Class1.cs" />
    <Compile Include="Properties\AssemblyInfo.cs" />
  </ItemGroup>
  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
       Other similar extension points exist, see Microsoft.Common.targets.
  <Target Name="BeforeBuild">
  </Target>
  <Target Name="AfterBuild">
  </Target>
  -->
</Project>

Notes:

  • If you follow this approach Visual Studio should recognize all the different build configurations and allow you to select the right one. Note that you may need to go into the 'Configuration Manager' for the solution in order to include or exclude projects from a specific solution configuration.
  • If you follow this approach it is no longer possible to change any of the globally defined properties through the property page for a project. You will have to make the change in the configuration file, which will then be reflected in the properties for every single project.
  • If you are using Visual Studio 2010 or earlier then if you make changes to the configuration file you will need to reload the solution (if you have it open) because Visual Studio 2010 does not detect changes to include files. Visual Studio 2012 should be able to detect changes to include files.
like image 75
Petrik Avatar answered Nov 15 '22 00:11

Petrik