ProjectConfiguration versus PropertyGroup (MSBuild)

2k views Asked by At

When I create a C++ Visual Studio project I get the following in my project file for MSBuild:

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

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

I don't understand what the difference is between the two sections. When I run the following:

MSBuild.exe MyProject.vcxproj /p:Configuration=Debug /p:Platform=Win32

Which is being applied? Are they combined into one? I don't understand the difference between "include" of ProjectConfiguration and "condition" of PropertyGroup.

1

There are 1 answers

3
stijn On

First of all, you missed to paste an important part (and consequently what you show is not valid msbuild syntax): the 'ProjectConfiguration' is an Item since it is inside of an ItemGroup. So the complete definition is actually, for instance:

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

This defines a list/array/collection/'whatever you want to call it' named ProjectConfiguration with 2 elements. The first element is "Debug|Win32" and has 2 Metadata items: first one called 'Configuration' with value 'Debug' and second one called 'Platform' with value 'Win32'. The ProjectConfiguration Item basically serves as a list telling the build system, including the gui in VS, what configuration/platform combinations exist for the project.

Properties are defined in a PropertyGroup and are just key/value pairs. The Condition attribute on the PropertyGroup leads to the properties inside it only being define if the condition matches. So while both Include and Condition are xml attributes they serve completely different purposes: the first, used in an Item, adds an element to the Item collection while the second is a conditional (which by the way can also be placed on nearly every other msbuild element, so also on an Item or ItemGroup) which when evaluated to False discards the content.

When I run the following: MSBuild.exe MyProject.vcxproj /p:Configuration=Debug /p:Platform=Win32 Which is being applied? Are they combined into one?

Passing /p defines Properties on the command line, no different from Properties defined in a PropertyGroup (moreover Properties defined on the commandline usually override those specified in the project file). Now for the ItemGroup this makes no difference what you pass on the commandline: it still contains the 2 elements telling the build system what combinations are available. It does change which Properties take effect though. Consider:

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
  <UseDebugLibraries>true</UseDebugLibraries>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
  <UseDebugLibraries>false</UseDebugLibraries>
</PropertyGroup>

The $() syntax is used to expand property values so if you pass /p:Configuration=Debug;Platform=Win32 on the commandline then '$(Configuration)|$(Platform)'=='Debug|Win32'" will after parsing and evaluation expand to 'Debug|Win32'=='Debug|Win32'" which in turn evaluates to True. As such the first PropertyGroup definition takes effect but not the second since for the latter the condition doesn't match. As a result the Property named 'UseDebugLibraries' gets the value 'true'. Should you pass /p:Configuration=Release;Platform=Win32 instead it would get the value 'false'. This is used ultimately to change the compiler/linker command executed and pass it a flag to tell which runtime library to use.