Hand-constructing Visual Studio 2012 vcxproj

Here is the simplest legal vcxproj that I could make.

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0"
         xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup Label="ProjectConfigurations">
    <ProjectConfiguration Include="Debug|Win32">
      <Configuration>Debug</Configuration>
      <Platform>Win32</Platform>
    </ProjectConfiguration>
  </ItemGroup>
</Project>

The first line declares it as an XML file, with the body in UTF-8.

<?xml version="1.0" encoding="utf-8"?>

The root element of an MSBuild XML document is Project. I’m assuming that the ToolsVersion=”4.0″ refers to MSBuild 4.0.

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

Every vcxproj must have at least one project configuration. This is wrapped inside an ItemGroup element that has a label of “ProjectConfigurations”. There are only a few sub-elements of Project allowed.

  <ItemGroup Label="ProjectConfigurations">
    <ProjectConfiguration Include="Debug|Win32">
      <Configuration>Debug</Configuration>
      <Platform>Win32</Platform>
    </ProjectConfiguration>
  </ItemGroup>

You can have as many project configurations as you want, although the real variable is Configuration – you’re more limited on Platform, since MSBuild has to understand that platform.

This project file will actually open up in Visual Studio, or be parsed by MSBuild, but you need a few more elements before you have something useful. First, note that project XML files are written in a specific order, and parsed as they are written. The XML is not in a canonical order, so you can’t use a tree parser to read or write these.

First off, a lot of the behavior is inherited. There are some magic import lines to scatter throughout your project file. Let’s focus on those. Here they are in a group. (Note for expert users: I am ignoring the fact that project files try to inherit from a user directory – that’s an abomination, and you don’t want that in your project files).

...
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
...
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
...
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
...

All of these are found in your MSBuild folder, which for me is C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V110; your mileage may vary.

Microsoft.Cpp.Default.props handles some default settings; if you don’t specify Platform, then Platform=Win32; if you don’t specify a Configuration, then Configuration=Debug; and so on.

Microsoft.Cpp.props is a wrapper to import the proper platform props, which isĀ “$(VCTargetsPath)\Platforms\$(Platform)\Microsoft.Cpp.$(Platform).props”, which simply turns around and importsĀ “$(VCTargetsPath)\Microsoft.Cpp.Platform.props”. The layers are used by platforms like ARM to declare min platform versions. This eventually leads to files like Microsoft.Cpp.Win32.v110.props, which sets paths, and Microsoft.Cpp.Common.props, which sets the majority of the defaults.

Microsoft.Cpp.targets sets up a lot of the default scaffolding for building C++ projects. Or, to restate it, it sets up the project file to build C++ projects. It’s one of the final lines in your project file.

It would be interesting to draw out the map of what’s included here; I suspect there is some organizational method, but it’s not obvious at first glance.

Note that if you use Microsoft.Cpp.props, you will get what the system defaults to – for me, it actually defaults to v100, which is Visual Studio 2010. So you need a few lines before that include to set specific properties for the project. Strictly speaking, you only need to set the PlatformToolset to v110; everything else has a default.

  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
    <ConfigurationType>StaticLibrary</ConfigurationType>
    <UseDebugLibraries>true</UseDebugLibraries>
    <PlatformToolset>v110</PlatformToolset>
    <CharacterSet>Unicode</CharacterSet>
  </PropertyGroup>

Now, if you put all of this together, you’ll end up with a project file that opens in Visual Studio and could actually be used to add files to, build with, and etc. It’s still not a complete project file; if you compare against a wizard-generated one, you’ll see lots of extra settings. But it is complete and almost useful.

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup Label="ProjectConfigurations">
    <ProjectConfiguration Include="Debug|Win32">
      <Configuration>Debug</Configuration>
      <Platform>Win32</Platform>
    </ProjectConfiguration>
  </ItemGroup>
  <PropertyGroup Label="Globals">
    <ProjectGuid>{FBEF15CB-6F54-49E3-853B-4238684902B8}</ProjectGuid>
    <Keyword>Win32Proj</Keyword>
    <RootNamespace>SHA1</RootNamespace>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
    <ConfigurationType>StaticLibrary</ConfigurationType>
    <UseDebugLibraries>true</UseDebugLibraries>
    <PlatformToolset>v110</PlatformToolset>
    <CharacterSet>Unicode</CharacterSet>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
  <Import Project="..\time-hash.lib.props" />
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>

Why am I doing this? I need to construct good Visual Studio projects automatically, and I don’t want to create things based on copy/paste information.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>