Multi-Targeting : How does it work?

So in my last post, I described the multi-targeting feature at a very high level. I discussed how there will be three frameworks that you can build "for", and how there will be two toolsets - i.e. .NET Framework 2.0 / MSBuild 2.0 toolset, and the .NET Framework 3.5 / MSBuild 3.5 toolset.

Recall that the capability we have added to MSBuild as a part of this feature is the ability for you to take a project, and build it using either toolset. MSBuild 3.5 supports a new command line parameter known as ToolsVersion that allows you to specify which toolset you want to build using, and is invoked as shown:

msbuild WindowsApplication1.csproj /ToolsVersion:3.5

ToolsVersion is the parameter that you use to force a project to build using a specific toolset. There are only two toolsets available out of the box, but you can also set up "custom" toolsets depending on your needs, and MSBuild can be used to build projects using those that you have defined. More on that later.

So, the next question obviously is, what happens when you build a project using a specific ToolsVersion, and what are the mechanics in action behind the scenes?

To understand this, we have to know a bit about how our project files are described. A standard Visual Studio managed project includes an import statement like the one shown below that is responsible for pulling in all the MSBuild / managed code build process into the project:

<

Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />

In MSBuild 2.0 (Visual Studio 2005 release), $(MSBuildBinPath) evaluated to the location of MSBuild 2.0, i.e. the .NET Framework 2.0 install path. In order to import the new version of Microsoft.CSharp.targets, naturally this needs to change to location of Microsoft.CSharp.targets that ship along with MSBuild 3.5. So in essence, specifying a ToolsVersion value at the command line is essentially equivalent to choosing from a predefined set of valid values for $(MSBuildBinPath). So specifying a ToolsVersion of 2.0 will cause MSBuildBinPath to evaluate to the .NET Framework 2.0 install path, and 3.5 will cause it to evaluate to the .NET Framework 3.5 install path, etc. Additionally, the targets that ship in MSBuild 3.5 include enhancements to the build process that will cause it to use the new set of compilers and other tasks.

MSBuildBinPath has also been "deprecated" in favor of MSBuildToolsPath - new projects created will use MSBuildToolsPath since that is a better name for what the property represents.

Allowing you to specify which toolset to use is only half the story. Multi-Targeting is also about building your code "targeting" a specific version of the framework - for instance, you might want to build your app only so that it relies on 2.0 assemblies and not on any 3.0 or 3.5 assemblies. This is done using another lever that is available via your project file. You can include a property in your project file known as TargetFrameworkVersion that specifies which target framework you are building your application for. TargetFrameworkVersion can either be v2.0, v3.0 or v3.5 - this means that if you are referencing assemblies that are not in a given TargetFrameworkVersion, then you will get errors/warnings at build time that will tell you so. This prevents you from taking on dependencies that will surprise you when you later turn around and try to deploy your app in a more tightly controlled environment that might only have a smaller subset of the three frameworks installed. Since TargetFrameworkVersion is a new concept, you need to be using ToolsVersion 3.5 in order to succefully build projects while honoring the TargetFrameworkVersion property.

This is a confusing topic, so please feel free to ask questions, and provide feedback so that we can help clarify anything on the subject.

[ Author : Faisal Mohamood ]