.vcxproj and .props file structure

MSBuild is the default project system in Visual Studio; when you choose File > New Project in Visual C++ you are creating an MSBuild project whose settings are stored in an XML project file that has the extension .vcxproj. The project file may also import .props files and .targets files where settings can be stored. In most cases, you never need to manually edit the project file, and in fact you should not edit it manually unless you have a good understanding of MSBuild. Whenever possible you should use the Visual Studio property pages to modify project settings (see Set C++ compiler and build properties in Visual Studio. However, in some cases you may need to modify a project file or property sheet manually. For those scenarios, this article contains basic information about the structure of the file.

Important:

If you choose to manually edit a .vcxproj file, be aware of these facts:

  1. The structure of the file must follow a prescribed form, which is described in this article.

  2. The Visual Studio C++ project system currently does not support wildcards in project items. For example, this is not supported:

    <ClCompile Include="*.cpp"/>
    
  3. The Visual Studio C++ project system currently does not support macros in project item paths. For example, this is not supported:

    <ClCompile Include="$(IntDir)\generated.cpp"/>
    

    "Not supported" means that macros are not guaranteed to work for all operations in the IDE. Macros which don’t change their value in different configurations should work, but might not be preserved if an item is moved to a different filter or project. Macros which change their value for different configurations will cause problems because the IDE doesn't expect project item paths to be different for different project configurations.

  4. In order to have project properties correctly added, removed, or modified when edited in the Project Properties dialog, the file must contain separate groups for each project configuration, and the conditions must be in this form:

    Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"
    
  5. Each property must be specified in the group with correct label, as specified in the property rule file. For more information, see Property page xml rule files.

.vcxproj file elements

You can inspect the contents of a .vcxproj file by using any text or XML editor. You can view it in Visual Studio by right-clicking on the project in Solution Explorer, choosing Unload project and then choosing Edit Foo.vcxproj.

The first thing to notice is that the top-level elements appear in a particular order. For example:

  • Most of the property groups and item definition groups occur after the import for Microsoft.Cpp.Default.props.

  • All targets are imported at the end of the file.

  • There are multiple property groups, each with a unique label, and they occur in a particular order.

The order of elements in the project file is very important, because MSBuild is based on a sequential evaluation model. If your project file, including all the imported .props and .targets files, consists of multiple definitions of a property, the last definition overrides the preceding ones. In the following example, the value "xyz” will be set during compilation because the MSBUild engine encounters it last during its evaluation.

  <MyProperty>abc</MyProperty>
  <MyProperty>xyz</MyProperty>

The following snippet shows a minimal .vcxproj file. Any .vcxproj file generated by Visual Studio will contain these top-level MSBuild elements and they will appear in this order (although they may contain multiple copies of each such top-level element). Note that Label attributes are arbitrary tags that are only used by Visual Studio 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>

The following sections describe the purpose of each of these elements and why they are ordered this way:

Project element

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

Project 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.

ProjectConfigurations ItemGroup element

<ItemGroup Label="ProjectConfigurations" />

ProjectConfigurations contains the project configuration description. Examples are Debug|Win32, Release|Win32, Debug|ARM and so on. Many project settings are specific to a given configuration. For example, you will probably want to set optimization properties for a release build but not a debug build.

The ProjectConfigurations item group is not used at build time. The Visual Studio IDE requires it in order to load the project. This item group can be moved to a .props file and imported into the .vcxproj file. However, in that case, if you need to add or remove configurations, you must manually edit the .props file; you can't use the IDE.

ProjectConfiguration elements

The following snippet shows a project configuration. In this example 'Debug|x64' is the configuration name. The project configuration name must be in the format $(Configuration)|$(Platform). A Project Configuration node can have two properties: Configuration and Platform. Those properties will be automatically set with the values specified here when the configuration is active.

<ProjectConfiguration Include="Debug|x64">
  <Configuration>Debug</Configuration>
  <Platform>x64</Platform>
</ProjectConfiguration>

The IDE expects to find a project configuration for any combination of Configuration and Platform values used in all ProjectConfiguration items. This often means that a project might have meaningless project configurations to fulfill this requirement. For instance, if a project has these configurations:

  • Debug|Win32

  • Retail|Win32

  • Special 32-bit Optimization|Win32

then it must also have these configurations, even though "Special 32-bit Optimization" is meaningless for x64:

  • Debug|x64

  • Retail|x64

  • Special 32-bit Optimization|x64

You can disable the build and deploy commands for any configuration in the Solution Configuration Manager.

Globals PropertyGroup element

<PropertyGroup Label="Globals" />

Globals contains project level settings such as ProjectGuid, RootNamespace, and ApplicationType/ ApplicationTypeRevision. The last two often define the target OS. A project can only target a single OS due to the fact that references and project items cannot have conditions currently. These properties are typically not overridden elsewhere in the project file. This group is not configuration-dependent and therefore typically only one Globals group exists in the project file.

Microsoft.Cpp.default.props Import element

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

The Microsoft.Cpp.default.props property sheet comes with Visual Studio and cannot be modified. It contains the default settings for the project. The defaults might vary depending on the ApplicationType.

Configuration PropertyGroup elements

<PropertyGroup Label="Configuration" />

A Configuration 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 the properties that are set for a specific configuration. Configuration properties include PlatformToolset and also control the inclusion of system property sheets in Microsoft.Cpp.props. For example, if you define the property <CharacterSet>Unicode</CharacterSet>, then the system property sheet microsoft.Cpp.unicodesupport.props will be included. If you inspect Microsoft.Cpp.props, you will see the line: <Import Condition=”'$(CharacterSet)' == 'Unicode'” Project=”$(VCTargetsPath)\microsoft.Cpp.unicodesupport.props”/>.

Microsoft.Cpp.props Import element

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

The Microsoft.Cpp.props property sheet (directly or via imports) defines the default values for many tool-specific properties such as the compiler's Optimization and Warning Level properties, the MIDL tool's TypeLibraryName property, and so on. It also imports various system property sheets based on which configuration properties are defined in the property group immediately above.

ExtensionSettings ImportGroup element

<ImportGroup Label="ExtensionSettings" />

The ExtensionSettings group contains imports for the property sheets that are part of Build Customizations. A Build Customization is defined by up to three files: a .targets file, a .props file and an .xml file. This import group contains the imports for the .props file.

PropertySheets ImportGroup elements

<ImportGroup Label="PropertySheets" />

The PropertySheets group contains the imports for user property sheets. These are the property sheets that you add through the Property Manager view in Visual Studio. The order in which these imports are listed is important 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.

UserMacros PropertyGroup element

<PropertyGroup Label="UserMacros" />

UserMacros contains properties you create as variables that are used to customize your build process. For example, you can define a user macro to define your custom output path as $(CustomOutputPath) and use it to define other variables. This property group houses such properties. Note that in Visual Studio, this group is not populated in the project file because Visual C++ does not support user macros for configurations. User macros are supported in property sheets.

Per-configuration PropertyGroup elements

<PropertyGroup />

There are multiple instances of this property group, one per configuration for all project configurations. Each property group must have one configuration condition attached. If any configurations are missing, the Project Properties dialog won't work correctly. Unlike the property groups above, this one does not have a label. 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 is initialized here.

This PropertyGroup must come after <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> and there must be no other PropertyGroup without a Label before it (otherwise Project Properties editing won’t work correctly).

Per-configuration ItemDefinitionGroup elements

<ItemDefinitionGroup />

Contains item definitions. These must follow the same conditions rules as the label-less per-configuration PropertyGroup elements.

ItemGroup elements

<ItemGroup />

Contains the items (source files, etc.) in the project. Conditions are not supported for Project items (that is, item types which are treated as project items by rules definitions).

The metadata should have configuration conditions for each configuration, even if they are all the same. For example:

<ItemGroup>
  <ClCompile Include="stdafx.cpp">
    <TreatWarningAsError Condition="‘$(Configuration)|$(Platform)’==’Debug|Win32’">true</TreatWarningAsError>
    <TreatWarningAsError Condition="‘$(Configuration)|$(Platform)’==’Debug|x64’">true</TreatWarningAsError>
  </ClCompile>
</ItemGroup>

The Visual Studio C++ project system currently does not support wildcards in project items.

<ItemGroup>
  <ClCompile Include="*.cpp"> <!--Error-->
</ItemGroup>

The Visual Studio C++ project system currently does not support macros in project items.

<ItemGroup>
  <ClCompile Include="$(IntDir)\generated.cpp"> <!--not guaranteed to work in all scenarios-->
</ItemGroup>

References are specified in an ItemGroup, and they have these limitations:

  • References do not support conditions.

  • References metadata do not support conditions.

Microsoft.Cpp.targets Import element

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

Defines (directly or via imports) Visual C++ targets such as build, clean, etc.

ExtensionTargets ImportGroup element

<ImportGroup Label="ExtensionTargets" />

This group contains imports for the Build Customization target files.

Impact of incorrect ordering

The Visual Studio IDE depends on the project file having the ordering described above. For example, 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 what you expect. For example, if you mistakenly import a system property sheet after the property sheets defined by the user, the user settings will be overridden by the system property sheets.

Even the IDE design time experience depends to some extent on correct ordering of elements. For example, if your .vcxproj file does not have the PropertySheets import group, the IDE might not be able to determine where to place a new property sheet that the user has created in Property Manager. This could result in a user sheet being overridden by a system sheet. Although the heuristic used by IDE can tolerate minor inconsistencies in the .vcxproj file layout, it is strongly recommended not to deviate from the structure shown earlier in this article.

How the IDE uses element labels

In the IDE, when you set the UseOfAtl property in the general property page, it is written to the Configuration property group in the project file, while the TargetName property in the same property page is written to the label-less per-configuration property group. Visual Studio looks at the property page's xml file for the information on where to write each property. For the General property page (assuming you have an English version of Visual Studio 2019 Enterprise Edition), that file is %ProgramFiles(x86)%\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\VC\VCTargets\1033\general.xml. The property page XML rule file 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 specified by the Label attribute on the project file elements.

Property Sheet layout

The following XML snippet is a minimal layout of a property sheet (.props) file. It is similar to a .vcxproj file, and the functionality of the .props elements can be inferred from the earlier discussion.

<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ImportGroup Label="PropertySheets" />
  <PropertyGroup Label="UserMacros" />
  <PropertyGroup />
  <ItemDefinitionGroup />
  <ItemGroup />
</Project>

To make your own property sheet, copy one of the .props files in the VCTargets folder and modify it for your purposes. For Visual Studio 2019 Enterprise edition, the default VCTargets path is %ProgramFiles%\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\VC\VCTargets.

See also

Set C++ compiler and build properties in Visual Studio
Property Page XML Files