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.]
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.
0 comments