简体   繁体   中英

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.

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, ie 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, eg 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, ie 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.

You want batch build where you can select the different builds you'd like run.

在此输入图像描述

You can map this to a keyboard shortcut with Tools -> Options -> Keyboard then search for Build.BatchBuild

In my opinion it's unwise to combine platforms and SKUs in your configuration names. In your case, I recommend to stick with Debug and Release project configurations only. Your solution should have one project for SKU A and a separate project for SKU B (sharing any common files). Each project can then target x86 and x64 platforms in addition to its two build configurations. You can then add as many solution configurations as you care to manage without making the individual project configurations any more complex.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM