A guide to .vcxproj and .props file structure

A guide to .vcxproj and .props file structure

Rate This
  • Comments 11

 

If you inspect the contents of a .vcxproj file (the new VC++ project file format in VS2010) in notepad or in VS editor (by first unloading the project and then choosing "Edit Foo.vcxproj" from the context menu in Solution Explorer), you will see that the various top-level MSBuild elements are laid out in a particular order. Go ahead and open a .vcxproj file right now. Notice, e.g., that most of the property groups and item definition groups occur after the import for Microsoft.Cpp.Default.props. Also, all targets are imported at the end of the project file. Then there are multiple property groups - distinguished by Labels on them – and they occur in a particular order.

 

What is the purpose of this ordered layout? Why are there multiple property groups (import groups, etc.) instead of only one? Well, read on.

 

The concept of an ordered layout is a natural outcome of MSBuild’s sequential evaluation model.  If your project file consists of two definitions of a property, such as below, the last definition overrides the preceding ones. So, the value “xyz” will be used during build time.

 

<MyProperty>abc</MyProperty>

<MyProperty>xyz</MyProperty>

 

The first property definition need not necessarily be in the project file itself. You could have included it via some import that is imported before the second definition of the property. What I say about properties here is also true about item definition metadata (in general, this holds true for the entire article).

 

Having said that, let me now show you the layout. The following skeletal (but legal) MSBuild file captures the layout succinctly. Any .vcxproj file generated by VS will contain these top-level MSBuild elements and in this particular order (although they may contain multiple copies of each such top-level element). Note that Labels are arbitrary tags only read and written by Visual Studio and used as signposts for editing; they have no other function.

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

  <ItemGroup Label="ProjectConfigurations" />

  <PropertyGroup Label="Globals" />

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

  <PropertyGroup Label="Configuration" />

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

  <ImportGroup Label="ExtensionSettings" />

  <ImportGroup Label="PropertySheets" />

  <PropertyGroup Label="UserMacros" />

  <PropertyGroup />

  <ItemDefinitionGroup />

  <ItemGroup />

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

  <ImportGroup Label="ExtensionTargets" />

</Project>

 

Let me explain what each of these elements are and why they are ordered this way.

 

<!-- This is the root node. It specifies the MSBuild version to use

and also the default target to be executed when this file is passed

to MSBuild.exe -->

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

  <!-- This contains the project configurations known to the project

  (such as Debug|Win32 and Release|Win32). -->

  <ItemGroup Label="ProjectConfigurations" />

  <!-- This contains project level settings such as ProjectGuid,

  RootNamespace, etc. These properties are not normally overridden

  elsewhere in the project file. This group is not configuration

  dependent and so only one Globals group generally exists in the

  project file. -->

  <PropertyGroup Label="Globals" />

  <!-- This property sheet contains the default settings for a VC++

  project. It contains definitions of all the project settings such

  as Platform, PlatformToolset, OutputPath, TargetName, UseOfAtl,

  etc. and also all the item definition group defaults for each known

  item group. In general, properties in this file are not tool-specific. -->

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

  <!-- This property group has an attached configuration condition

  (such as Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'")

  and comes in multiple copies, one per configuration. This property

  group hosts configuration-wide properties. These properties control

  the inclusion of system property sheets in Microsoft.Cpp.props.

  E.g. if we define the property <CharacterSet>Unicode</CharacterSet>,

  then the system property sheet microsoft.Cpp.unicodesupport.props

  will be included (as can be seen in the Property Manager). Indeed,

  in one of the imports of Microsoft.Cpp.props, we can see the line:

  <Import Condition="'$(CharacterSet)' == 'Unicode'"   Project="$(VCTargetsPath)\microsoft.Cpp.unicodesupport.props"/> -->

  <PropertyGroup Label="Configuration" />

  <!-- This property sheet (directly or via imports) defines the

  default values for many tool-specific properties such as the

  compiler’s Optimization, WarningLevel properties, Midl tool’s

  TypeLibraryName property, etc. In addition, it imports various

  system property sheets based on configuration properties defined

  in the property group immediately above. -->

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

  <!-- This group contains imports for the property sheets that

  are part of Build Customizations (or Custom Build Rules as this

  feature was called in earlier editions). A Build Customization

  is defined by up to three files – a .targets file, a .props file

  and .xml file. This import group contains the imports for the

 .props file. -->

  <ImportGroup Label="ExtensionSettings" />

  <!-- This group contains the imports for user property sheets.

  These are the property sheets you add through the Property

  Manager view in VS. The order in which these imports are listed

  is relevant and is reflected in the Property Manager. The project

  file normally contains multiple instances of this kind of import

  group, one for each project configuration.  -->

  <ImportGroup Label="PropertySheets" />

  <!-- UserMacros are as variables used to customize your build

  process. E.g. you can define a user macro to define your custom

  output path as $(CustomOutpuPath) and use it to define other

  variables. This property group houses such properties. Note that

  in VS2010, this group is not populated by the IDE since we do not

  support user macros for configurations (we do for property sheets

  though). -->

  <PropertyGroup Label="UserMacros" />

  <!-- This property group normally comes with a configuration

  condition attached. You will also see multiple instances of the

  property group, one per configuration. It differs in its identity

  from the other property groups above by the fact that it does

  not have a label (to look at it in another way, it has a label

  that is equal to the empty string). This group contains project

  configuration level settings. These settings apply to all files

  that are part of the specified item group. Build Customization

  item definition metadata also gets initialized here. -->

  <PropertyGroup />

  <!-- Similar to the property group immediately above, but it

  contains item definitions and item definition metadata instead

  of properties. -->

  <ItemDefinitionGroup />

  <!-- Contains the items (source files, etc.) in the project.

  You will generally have multiple item groups – one per item

  type. -->

  <ItemGroup />

  <!-- Defines (directly or via imports) VC++ targets such as

  build, clean, etc. -->

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

  <!-- This group contains imports for the Build Customization

  target files. -->

  <ImportGroup Label="ExtensionTargets" />

</Project>

 

The above ordering ensures that editing the project file via that IDE gives expected results. E.g. when you define a property value in the property pages, the IDE will generally place the property definition in the property group with the empty label. This ensures that default values brought in the system property sheets are overridden by user defined values. Similarly, the target files are imported at the end since they consume the properties defined above and since they generally do not define properties themselves. Likewise, user property sheets are imported after the system property sheets (included via Microsoft.Cpp.props). This ensures that the user can override any defaults brought in by the system property sheets.

 

If a .vcxproj file does not follow this layout, the build results may not be like you expected. E.g. properties defined by the user using property pages may not be used during the build since they could have been overridden by the system property sheets in this different layout.

 

Even the IDE design time experience may suffer, although VS does its best to work with any .vcxproj file. If your .vcxproj file does not have, say, the PropertySheets import group, then you will not see any user property sheets in the Property Manager view (you might still see the system property sheets though). However, when you add a property sheet from the Property Manager view, then VS will create one such labeled import group for you at the right place in the .vcxproj file and add the import for the new property sheet. If however, your .vcxproj has a layout very different from the one described above, VS may not know what the right place is so it may end up creating it at an arbitrary location. In general, the heuristic used by VS IDE should work well for minor to moderate inconsistencies in the .vcxproj file layout.

 

You may want to know how VS magically knows where to write a particular property. E.g. when you set UseOfAtl property in the general property page, it gets written to Configuration property group whereas the TargetName property in the same general property page gets written to the label-less property group.  That is told to VS by the property itself. Well actually by the property schema in the property page xml file. Recall that property page xml defines the static information about a Rule and all its properties. One such piece of information is the preferred position of a Rule property in the destination file (the file where its value will be written). The preferred position is defined by taking advantage of the existence of Labels. Labels are used to distinguish the various top-level elements of the same type (such as two property groups).   Thus, a property can declare in the property page xml file, which of the property groups it would like to be housed in when the time comes for it to be defined in the project file.

 

Finally, here is the skeletal MSBuild file that will illustrate the file layout of a property sheet (.props) file in VS2010. The functionality of the layout elements can be inferred based on the discussion above.

 

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

  <ImportGroup Label="PropertySheets" />

  <PropertyGroup Label="UserMacros" />

  <PropertyGroup />

  <ItemDefinitionGroup />

  <ItemGroup />

</Project>

 

To summarize, the ordered layout of .vcxproj and .props files comports with MSBuild sequential evaluation model. The use of Labels helps the IDE in reading element definitions from and writing them to the right location in the file.

 

[I would like to thanks Marian Luparu whose notes on the .vcxproj file layout I used in preparing this blog post.]

 

Pavan (2)Short Bio: Pavan Adharapurapu is a developer on the Visual Studio Project and Build team. As part of VS 2010, he has worked on numerous features of the VC++ project system such as property sheets, filters, property pages, platform and tool extensibility, etc. His long term focus is on developing a "common project system" infrastructure which could be used to quickly build richly featured project systems. Prior to joining the Visual Studio team in 2008, he was working on Workflow technologies in Microsoft Dynamics Axapta. Pavan holds a Masters degree in Computer Science (CS) from the University of California, Los Angeles (UCLA) and a Bachelors degree in CS from the Indian Institute of Technology (IIT), Madras. He lives in Redmond, WA with his wife and loves to play soccer and watch movies in his spare time.

 

Leave a Comment
  • Please add 1 and 1 and type the answer here:
  • Post
  • Awesome, great post. Very helpful.  This is certainly a different extensibility model than managed code, but it seems pretty flexible.

    I'm curious - Do you have any guidance about how configuration that is common to multiple vcxproj files be "refactored" out?  For example, if a set of 4 ProjectConfiguration is shared between 10 vcxproj files, could those be imported from a common Settings.props file?

  • Good, helpful post. I'm with Matt on the issues of sharing configuration between different projects. We are having exactly this problem at work.

    It would be awesome to just import one settings file and have all projects use the same settings. I totally don't understand why each project file needs to have its own "configuration" (debug/release/etc). Can the common settings file contain configuration definitions for all projects? Not sure if VS is smart enough to understand that... Also, is there a way of telling VS to honor whitespace in project files? It's really annoying when each time a project is saved the whitespace gets deleted. Whitespace is essential. Especially for the C++ crowd. Lots of folks are coming from the makefile world. Reading tons of XML makes their brains hurt. Space between elements would help.

  • Yep, what Matt said.

    I tried creating an Import statement factoring the ProjectConfigurations out into a separate file. Visual Studio reported that my project file was no longer valid.

    I don't see why this scenario isn't supported though. It seems pretty obvious that if you have multiple projects, you want to be able to define new ProjectConfigurations once, in a common file, instead of by editing each and every project.

    Hopefully it is just a bug in the current version of VS. Right?

  • @jalf it is something I hope is fixed. I will ask the VC folks about it.

    Meanwhile there is a sort-of-workaround which may help, or not, depending on what you are trying to do. What it is looking for is just the configuration definitions. So this minimal .vcxproj will load successfully:

    <?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>

       <ProjectConfiguration Include="Release|Win32">

         <Configuration>Release</Configuration>

         <Platform>Win32</Platform>

       </ProjectConfiguration>

     </ItemGroup>

     <Import Project="test.targets" />

    </Project>

    In "test.targets" I just pasted the rest of the body of a regular .vcxproj project file, plus the root <Project> tag of course.

    If what you're trying to move out is what each configuration "does" -- for example, in Debug configuration define _DEBUG -- rather than what the various configuration names are, then this workaround might be good enough. Be aware that VS won't allow you to edit items that are defined in an imported file, so you'd want to keep those in the main project file. Also, it may not edit the main project file quite how you want, especially if you modify configuration-dependent properties for a particular project. But I guess if you do that, you're telling it that you want a special value for that project.

    Does this help?

    Dan [msbuild dev lead]

  • @Matt, @Filip, @jalf,

    The ability to define project configurations in an import is being considered for SP1. And there is a good chance that it will actually make it.

    Thanks,

    Pavan Adharapurapu

    Software Developer,

    Visual Studio Project & Build Team,

    Microsoft.

  • Now that VS 2010 SP1 beta is out, can someone confirm if the ability to define project configs in an imported property sheet is a feature of VS 2010 SP1?

    Thanks

    -Attila

  • I would like a way to get a property sheet before the CPP settings, so that we can share default settings between projects.  Namely we would like to set WindowsSdkDir off to a common location and not depend on locally installed wsdk.

    With the current setup the IncludePath is already formed (and the Default WindowsSdkDir is injected in it) by the time the property sheet import happens.  I need to overwrite and re-create the whole include path.  

    It's not the end of the world but a way to get a property sheet into the "Globals" section via the Property Manager would be cool.

    Thanks,

    Steve

  • Has the ability to define project configurations in an import been implemented in VS 2010 SP1 or VS 2012?

    Can anyone from the VS team confirm?

    Thank you in advance,

  • fyhfovhfgvp\zhsdfhijfiv\iogfj

  • Would you please provide solution for the problem I mentioned at following link?

    www.codeproject.com/.../includepluspropertyplussheetplusinplusVisualplusC

    Thanks.

  • NA6RDRWS9K KVNXJJXJJVJIXMCJNCIKM JCIJXNZCHB UVOXCKVJU9VFPKGJFI0VVJIFO0FOF9OF0OFK,VNMKD;PXLJBIGOFOLFOLFODOOPD

Page 1 of 1 (11 items)