C++ Native Multi-Targeting

C++ Native Multi-Targeting

Rate This
  • Comments 24

Hello, my name is Li Shao. I am a Software Design Engineer in Test on the C++ team. For the past two years, I have been part of the team working on migrating the C++ build system from VCBuild to MSBuild as well as the new project system which is also built on top of MSBuild. You can see one of my earlier blogs about the task work that we have done. In this blog, I am going to give an overview of the Native Multi-targeting feature. I hope you will find it useful.

 

Multi-targeting is the ability to use the current version of Visual Studio to build your application with a different set of installed tools or Frameworks. In VS2010, C++ applications support two types of Multi-targeting: Native Multi-targeting and Managed Multi-targeting. For more details on Managed Multi-targeting, please visit this blog post by one of my colleagues, Pavan Adharapurapu.

Native Multi-targeting

 

VS2010 can support building against VS2008 toolsets if VS2008 is installed on the same machine. Soma has mentioned this feature in his blog some time ago. This feature enables the C++ customers to use VS2008 toolsets while working in the VS2010 environment. Note that your application created with earlier versions of Visual Studio will need to be converted to the VS2010 version.

 

Why Native Multi-targeting?

An important scenario for C++ customers (let’s call them “large C++ shops” here) is that they develop and build their applications in Visual Studio and then ship the applications to their respective customers. These customers, however, maybe using different versions of Visual Studio for development. Given that, the “large C++ shops” have to keep multiple versions of Visual Studio and multiple versions of the project files, so that they can build binaries targeting different versions of the toolset.

 

With the native Multi-targeting feature, once the “large C++ shops” migrated their applications to VS2010, they have the ability to use VS2010 to target any versions of the toolset theoretically. This eliminates the need to maintain multiple versions of project files and the development work can be done all within VS2010, as long as the targeted toolsets are installed on the same machine.

 

How to enable native Multi-targeting?

The Multi-Targeting feature is available both when building from the IDE and building on the command line. Below is a screen shot of the native Multi-targeting settings on the property page: Platform Toolset controls which version of the toolsets you want to target: v100 targets VS2010 and v90 targets the VS2008 level toolsets and libraries.

 

 

The Platform toolset version is v100 by default for both newly created projects and projects converted to VS2010. In both cases, the “PlatformToolset” property is not written to the project file. There are a couple of ways you can re-target to different PlatformToolset (v90 is used as an example below):

 

For single project, you can choose your targeted platform toolset to be v90 in the property page, the “PlatformToolset” property will be written to your project file as the following:

 

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

    <ConfigurationType>Application</ConfigurationType>

    <UseDebugLibraries>true</UseDebugLibraries>

    <CharacterSet>Unicode</CharacterSet>

    <PlatformToolset>v90</PlatformToolset>

</PropertyGroup>

 

 

 

In order to re-target multiple projects at once, you can multi-select them in Solution Explorer and then bring up the Property Pages. To make the changes apply to all configurations, also select from the Configuration dropdown “All configurations” entry and from Platform dropdown “All platforms” entry. Note that multi-select will work only if all projects are of the same type.

 

Once the “PlatformToolset” is set to v90, the compiler, linker, headers, and libraries from VS2008 will be used. Below is a snapshot of the build log when building against the v90 toolset from the VS2010 IDE or command line prompt. You can see that VS2008 compiler is used instead of VS2010 compiler.

 

c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\CL.exe /c /ZI /nologo /W3 /WX- /Od /Oy- /D WIN32 /D _WINDOWS /D _DEBUG /D _UNICODE /D UNICODE /D _AFXDLL /Gm /EHsc /RTC1 /MDd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Yc"StdAfx.h" /Fp"Debug\MFC.pch" /Fo"Debug\\" /Fd"Debug\vc90.pdb" /Gd /TP /analyze- /errorReport:prompt stdafx.cpp

 

Note that changing the value of the Platform Toolset property will cause a full rebuild of the project.

 

How does it work?

In VS2010, there are V90 and V100 folders under %ProgramFiles%\MSBuild\Microsoft.Cpp\v4.0\Platforms\<Platforms>\PlatformToolsets or %ProgramFiles(x86)%\MSBuild\Microsoft.Cpp\v4.0\Platforms\<Platforms>\PlatformToolsets on a x64 machine. Inside each folder, you can find a ToolSet specific props and targets file. Here is a representation of the layout of the file/directory structure on the disk:

 

 

 

Microsoft.Cpp.<Platform>.<PlatformToolset>.props file sets the properties required to build against a certain toolset. For example, in Microsoft.Cpp.Win32.v90.Props, ExecutablePath (PATH), IncludePath (INCLUDE), ReferencePath (LIBPATH), LibraryPath (LIB), SourcePath, ExcludedPath are set based on the VS2008 installation and Windows SDK installation that shipped with VS2008 (6.0A)

 

<VCInstallDir>$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\9.0\Setup\VC@ProductDir)</VCInstallDir>

<VCInstallDir

    Condition="'$(VCInstallDir)' == ''">$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\9.0\Setup\VC@ProductDir)</VCInstallDir>

<VCInstallDir

    Condition="'$(VCInstallDir)' == ''">$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VCExpress\9.0\Setup\VC@ProductDir)</VCInstallDir>

<VCInstallDir

    Condition="'$(VCInstallDir)' == ''">$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VCExpress\9.0\Setup\VC@ProductDir)</VCInstallDir>

<WindowsSdkDir

    Condition="'$(UseEnv)' != 'true'">$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows@CurrentInstallFolder)</WindowsSdkDir>

<WindowsSdkDir

    Condition="'$(WindowsSdkDir)'==''">$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\MicrosoftSDKs\Windows@CurrentInstallFolder)</WindowsSdkDir>

<ExecutablePath

    Condition="'$(ExecutablePath)' == ''">$(VCInstallDir)bin;$(WindowsSDKDir)bin;$(VSInstallDir)Common7\Tools\bin;$(VSInstallDir)Common7\tools;$(VSInstallDir)Common7\ide;$(ProgramFiles)\HTML Help Workshop;$(FrameworkSDKDir)bin;$(FrameworkDir)$(FrameworkVersion);$(VSInstallDir);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH);</ExecutablePath>

<IncludePath

    Condition="'$(IncludePath)' == ''">$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSdkDir)include;$(FrameworkSDKDir)include;</IncludePath>

<ReferencePath

    Condition="'$(ReferencePath)' == ''">$(VCInstallDir)atlmfc\lib;$(VCInstallDir)lib</ReferencePath>

<LibraryPath

    Condition="'$(LibraryPath)' == ''">$(VCInstallDir)lib;$(VCInstallDir)atlmfc\lib;$(WindowsSdkDir)lib;$(FrameworkSDKDir)lib</LibraryPath>

<SourcePath

    Condition="'$(SourcePath)' == ''">$(VCInstallDir)atlmfc\src\mfc;$(VCInstallDir)atlmfc\src\mfcm;$(VCInstallDir)atlmfc\src\atl;$(VCInstallDir)crt\src;</SourcePath>

<ExcludePath

    Condition="'$(ExcludePath)' == ''">$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSdkDir)include;$(FrameworkSDKDir)include;$(FrameworkDir)$(FrameworkVersion);$(VCInstallDir)atlmfc\lib;$(VCInstallDir)lib;</ExcludePath>

 

MSBuild can spawn the build environment based on the information you set in the props file for a certain platform toolset. In the command line build scenarios, this means that the PATH, LIBPATH, LIB, INCLUDE that the build system is using can come from the PlatformToolsets itself, which can eliminate the need to use other batch files, such as vcvars32.bat, to set up the build environment. This is a functionality that the old VCBuild system does not have. Below is a code snippet from Microsoft.cpp.Targets that enables the functionality. When UseEnv is not set to true, PATH, LIB, INCLUDE, LIBPATH will be set from the corresponding property values in the platform toolset.  When UseEnv is set to true, as in old build system, the values from environment variables for PATH, INCLUDE, LIB, LIBPATH will be used, instead.

 

<Target Name="SetBuildDefaultEnvironmentVariables"

          Condition="'$(UseEnv)' != 'true'">

    <SetEnv Condition="'$(_IsNativeEnvironment)' != 'true'"

            Name   ="PATH"

            Value  ="$(ExecutablePath)"

            Prefix ="false">

      <Output TaskParameter="OutputEnvironmentVariable" PropertyName="Path"/>

    </SetEnv>

    <SetEnv Condition="'$(_IsNativeEnvironment)' == 'true'"

            Name ="PATH"

            Value ="$(NativeExecutablePath)"

            Prefix ="false">

      <Output TaskParameter="OutputEnvironmentVariable" PropertyName="Path"/>

    </SetEnv>

    <SetEnv Name   ="LIB"

            Value  ="$(LibraryPath)"

            Prefix ="false">

      <Output TaskParameter="OutputEnvironmentVariable" PropertyName="LIB"/>

    </SetEnv>

    <SetEnv Name   ="LIBPATH"

            Value  ="$(ReferencePath)"

            Prefix ="false">

      <Output TaskParameter="OutputEnvironmentVariable" PropertyName="LIBPATH"/>

    </SetEnv>

    <SetEnv Name   ="INCLUDE"

            Value  ="$(IncludePath)"

            Prefix ="false" >

      <Output TaskParameter="OutputEnvironmentVariable" PropertyName="INCLUDE"/>

    </SetEnv>

  </Target>

 

 

For managed applications, since the VS2008 compiler can only target CLR 2.0, targeting v90 platform toolset it allows only one of these versions of .NET Framework: v2.0, v3.0 or v3.5. By default, v90 platform toolset target v3.5 framework.

 

How to extend it?

With this model, if you have a specific SDK that you would like to target, you can create your custom platform toolset. Below is an example of a Microsoft.cpp.Win32.v80.props file for targeting VS2005. Note that for VS2005, WindowsSDKDir is not available, we have PlatformSDK instead.  After creating the v80 directory for each platform along with the corresponding props and targets files, you will have support to build against v80 instantly.

 

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <Import Project="$(VCTargetsPath)\Platforms\Win32\ PlatformToolsets\v80\ImportBefore\*.props" Condition="Exists('$(VCTargetsPath)\Platforms\Win32\PlatformToolsets\v80\ImportBefore')" />

  <PropertyGroup>

    <PlatformToolsetVersion>80</PlatformToolsetVersion>

    <VCInstallDir>$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\8.0\Setup\VC@ProductDir)</VCInstallDir>

    <VCInstallDir

        Condition="'$(VCInstallDir)' == ''">$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\8.0\Setup\VC@ProductDir) </VCInstallDir>

    <VSInstallDir>$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\8.0\Setup\VS@ProductDir)</VSInstallDir>

    <VSInstallDir

        Condition="'$(VSInstallDir)' == ''">$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\8.0\Setup\VS@ProductDir)</VSInstallDir>

    <FrameworkDir

        Condition="'$(UseEnv)' != 'true'">$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework@InstallRoot)</FrameworkDir>

    <FrameworkDir

        Condition="'$(FrameworkDir)' == ''">$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\.NETFramework@InstallRoot)</FrameworkDir>

    <FrameworkSdkDir

        Condition="'$(UseEnv)' != 'true'">$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\.NETFrameWork\v2.0@InstallationFolder)</FrameworkSdkDir>

    <FrameworkSdkDir

        Condition="'$(FrameworkSdkDir)' == ''">$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\.NETFrameWork\v2.0@InstallationFolder)</FrameworkSdkDir>

    <FrameworkSdkDir

        Condition="'$(FrameworkSdkDir)' == ''">$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\.NETFrameWork\v2.0@InstallationFolder)</FrameworkSdkDir>

    <FrameworkVersion

        Condition="'$(UseEnv)' != 'true'">v2.0.50727</FrameworkVersion>

    <Framework35Version

        Condition="'$(UseEnv)' != 'true'">v3.5</Framework35Version>

    <ExecutablePath

        Condition="'$(ExecutablePath)' == ''">$(VCInstallDir)bin;$(VCInstallDir)PlatformSDK\bin;$(VCInstallDir)PlatformSDK\common\bin;$(VSInstallDir)Common7\Tools\bin;$(VSInstallDir)Common7\tools;$(VSInstallDir)Common7\ide;$(ProgramFiles)\HTML Help Workshop;$(FrameworkSDKDir)bin;$(FrameworkDir)$(FrameworkVersion);$(VSInstallDir);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH);</ExecutablePath>

    <IncludePath

        Condition="'$(IncludePath)' == ''">$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(VCInstallDir)PlatformSDK\include;$(VCInstallDir)PlatformSDK\common\include;$(FrameworkSDKDir)include;</IncludePath>

    <ReferencePath

        Condition="'$(ReferencePath)' == ''">$(FrameworkDir)$(FrameworkVersion);$(VCInstallDir)atlmfc\lib;</ReferencePath>

    <LibraryPath

        Condition="'$(LibraryPath)' == ''">$(VCInstallDir)lib;$(VCInstallDir)atlmfc\lib;$(VCInstallDir)atlmfc\lib\i386;$(VCInstallDir)PlatformSDK\lib;$(VCInstallDir)PlatformSDK\common\lib;$(FrameworkSDKDir)lib;$(VSInstallDir);$(VSInstallDir)lib;</LibraryPath>

    <SourcePath

        Condition="'$(SourcePath)' == ''">$(VCInstallDir)atlmfc\src\mfc;$(VCInstallDir)atlmfc\src\atl;$(VCInstallDir)crt\src;</SourcePath>

    <ExcludePath

        Condition="'$(ExcludePath)' == ''">$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(VCInstallDir)PlatformSDK\include;$(VCInstallDir)PlatformSDK\common\include;$(FrameworkSDKDir)include;$(FrameworkDir)$(FrameworkVersion);$(VCInstallDir)atlmfc\lib;</ExcludePath>

    <NativeExecutablePath

        Condition="'$(NativeExecutablePath)' == ''">$(ExecutablePath)</NativeExecutablePath>

  </PropertyGroup>

  <Import Project="$(VCTargetsPath)\Platforms\Win32\ PlatformToolsets\v80\ImportAfter\*..props" Condition="Exists('$(VCTargetsPath)\Platforms\Win32\ PlatformToolsets\v80\ImportAfter')" />

</Project>

 

 

Below is a snapshot of the IDE build setting and the build log:

 

 

The Platform Toolset feature also provides the extensibility points. In the Microsoft.Cpp.Win32.<PlatformToolset version>.props file, there are the following sections:

 

<Import Project="$(VCTargetsPath)\Platforms\Win32\PlatformToolsets\v100\ImportBefore\*.props"

        Condition="Exists('$(VCTargetsPath)\Platforms\Win32\PlatformToolsets\v100\ImportBefore')" />

 

<Import Project="$(VCTargetsPath)\Platforms\Win32\PlatformToolsets\v100\ImportAfter\*.props"

        Condition="Exists('$(VCTargetsPath)\Platforms\Win32\PlatformToolsets\v100\ImportAfter')" />

 

With this design, you can create your own special props file that is specific to a certain Platform Toolset. For example, you might create a custom props file called DirectX.props (it could be called anything) which you then drop into the following folder: win32\PlatformToolsets\v100\ImportAfter. The Properties defined in DirectX.props (below) would be imported after the properties in Microsoft.Cpp.Win32.<PlatformToolset version>.props are imported.

 

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <ItemDefinitionGroup>

    <ClCompile>

<AdditionalIncludeDirectories>$(DirectXSDK)\Latest\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

    </ClCompile>

    <Link>

<AdditionalLibraryDirectories>$(DirectXSDK)\Latest\Lib\x86%(AdditionalLibraryDirectories);</AdditionalLibraryDirectories>

    </Link>

  </ItemDefinitionGroup>

</Project>

 

Upon compile, you will get /I d:\DirectX\Latest\include being passed to CL.exe and /LIBPATH:d:\DirectX\Latest\Lib\x86 being passed to the linker when compiling a project targeting the Win32 platform and the v100 platform toolset. Any other project configurations will not be impacted.

 

Windows SDK will adopt this Platform Toolset concept for future releases so that re-targeting of different WinSDK versions becomes an easier task. We also encourage our customers to use this feature and let us know if you have any feedback.

 

Li Shao

Project and Build Team

 

  • Condition="Exists... is evil, after upgaring from beta1 to beta2 the path changed to the platform specific sheet and it could not find it, there was also one environment variable somewhere in the path which do not exists on win2k. In those cases the build system stays silent about it and all I can see are the compiler errors. Any reason those sheets may be optional?

  • @ Gabest

    There were some changes between Beta1 and Beta2 in terms of where we look for the property sheets, for example, the property sheets under ImportBefore\ImportAfter directories as I mentioned above. They are options since INCLUDE, LIB, LIBPATH, PATH are already set by Microsoft.Cpp.<Platform>.<PlatformToolset>.props. Hope this answers your questions.

    As far as I know, current Visual Studio does not support design time experience (including editor, building) on Win2K.

  • @ Gabest

    There were some changes between Beta1 and Beta2 in terms of where we look for the property sheets, for example, the property sheets under ImportBefore\ImportAfter directories as I mentioned above. They are options since INCLUDE, LIB, LIBPATH, PATH are already set by Microsoft.Cpp.<Platform>.<PlatformToolset>.props. Hope this answers your questions.

    As far as I know, current Visual Studio does not support design time experience (including editor, building) on Win2K.

  • Installing VC9 on Win2K was not supported (see "1.2. Supported Operating Systems" in http://go.microsoft.com/fwlink/?LinkId=102508 , linked from http://msdn.microsoft.com/en-us/library/4c26cc39.aspx ), but targeting Win2K was supported (see http://msdn.microsoft.com/en-us/library/ms235435.aspx for the full matrix).

    VC10 no longer supports even targeting Win2K. Note that http://msdn.microsoft.com/en-us/library/ms235435(VS.100).aspx is incorrect; we have notified MSDN.

  • Please ship or make available the ability to target 2005 and 2003.

  • Thanks Ben for you feedback. It is not in the plan to ship the PlatformToolsets for VS2005 and VS2003 with the VS2010 release. However, we should be able to make the targets/props samples available to target VS2005 and VS2003. The .props file that I posted above can be included in the PlatformToolset to target VS2005.

    Li Shao

    Project and Build team

  • What about the possibility of using multi-targeting to target the WinCE/Windows Mobile toolchain from 2008?  Would that cover everything except integrated debugging?

  • I see that you wrote:

    "Windows SDK will adopt this Platform Toolset concept for future releases so that re-targeting of different WinSDK versions becomes an easier task."

    But rather than have to install VS 2008 (SP1), is the multi-targeting currently configurable to work with the compilers/linkers supplied with the current Windows SDK?

  • @CMC: Native Multi-Targeting is a new feature in VS2010. VS2008 does not have the ability to do native Multi-Targeting. If you use VS2010, you can target WinCE/Windows Mobile toolchain as long as the customized PlatformToolset for these toolchains are created.

    @David: VS2010 does not ship the PlatformToolset to target different versions of Standalone Windows SDKs. However, you can create your customized PlatformToolset to target these standalone WinSDKs, in which case, you do not need to have previous versions of Visual Studio installed sidebyside on the machine.

  • Would it be possible to target VS2005 but use the VS2010 compiler and linker ?

  • Would it be possible to target VS2005 but use the VS2010 compiler and linker ?

  • Hi Rolf, let me see if I understand your question crrectly. Do you mean that you want to use VS2010 compiler and linker but use VS2005 headers/Libs?

  • Hi Li Shao. Yes is that possible ? (Not asking if it is supported by Microsoft)

  • Yes, it is possible in terms of crafting the PlatformToolset. In the example of the vc8 PlatformToolset above, you need to change <ExecutablePath> in Microsoft.Cpp.<Platform>.<PlatformToolset>.props to point to VS2010 compiler/linker path. For Example,

    <ExecutablePath

    Condition="'$(ExecutablePath)' == ''">$(VC10InstallDir)bin;$(WindowsSDKDir)bin;$(VS10InstallDir)Common7\Tools\bin;$(VS10InstallDir)Common7\tools;$(VS10InstallDir)Common7\ide;$(ProgramFiles)\HTML Help Workshop;$(FrameworkSDKDir)bin;$(FrameworkDir)$(FrameworkVersion);$(VS10InstallDir);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH)</ExecutablePath>

    You need to define VC10InstallDir, VS10InstallDir.

  • I have not been able to generate a successful build targeting VS 2003. It looks like the build system is sending Unicode characters instead of ANSI characters. I hope this is a solvable problem, otherwise I won't be able to use VS 2010.

Page 1 of 2 (24 items) 12