May 14th, 2010

A guide to .vcxproj and .props file structure

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.

 

Author

Visual Studio has been around since 1997 when it first released many of its programming tools in a bundle. Back then it came in 2 editions - Visual Studio Professional and Visual Studio Enterprise. Since then the family has expanded to include many more products, tools, and services.

0 comments

Discussion are closed.