2

The problem

  • I have a VS2015 solution that uses precompiled headers.
  • Our Continuous Integration server builds the solution using msbuild.
  • We also use a coverage tool that has some issues with precompiled headers.

The question

How to tell to msbuild.exe do not use precompiled headers?

Note

I tried adding /Y- in the msbuild call, but it's not a valid parameter for msbuild.

Cartucho
  • 3,257
  • 2
  • 30
  • 55

1 Answers1

3

We can't directly do this by msbuild since PrecompiledHeader is not a msbuild property...

MSbuild reads data from project file to execute the build. And there're several elements in xx.vcxproj can be specified in command-line like targets, properties, so we can use command like msbuild xx.vcxproj/xx.sln /t:xx /p:xx to specify the target element and property element when building in command-line.

e.g: msbuild xx.vcxproj /t:build /p:OutDir=xxx can specify where to output your assembly.

I changed one VS2015 C++ project's settings to make it not use precompiled headers, after comparing the difference(using git for version control) between the two versions of the xx.vcxproj file I found:

enter image description here

So the element to control the behavior of precompiled-header is an Item metadata in ClCompile Item. Since the element is an Item metadata instead of a property, we can't use command like msbuild xx.vcxproj /p:PrecompiledHeader=NotUsing ... to disable the precompiled headers. (/p <=> /property)

Possible direction:

The only possible direction I can imagine which may work to achieve your goals is creating a custom property to control this behavior.

1.For a normal C++ project, the content of its project file is:

<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <ClCompile>
      <PrecompiledHeader>NotUsing</PrecompiledHeader>
      ...
    </ClCompile>
  </ItemDefinitionGroup>

  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <ClCompile>
      <PrecompiledHeader>Use</PrecompiledHeader>
      ...
    </ClCompile>
  </ItemDefinitionGroup>

  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <ClCompile>
      <PrecompiledHeader>Use</PrecompiledHeader>
      ...
    </ClCompile>
  </ItemDefinitionGroup>

  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <ClCompile>
      <PrecompiledHeader>Use</PrecompiledHeader>
      ...
    </ClCompile>
  </ItemDefinitionGroup> 

2.Add a custom DisablePCH property, make a copy of these four ItemDefinitionGroups and involve this property into their Condition.

<PropertyGroup>
    <DisablePCH>false</DisablePCH>
  </PropertyGroup>

  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32' And '$(DisablePCH)'=='false'">
    <ClCompile>
      <PrecompiledHeader>Use</PrecompiledHeader>
      ...
    </ClCompile>
  </ItemDefinitionGroup>

  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64' And '$(DisablePCH)'=='false'">
    <ClCompile>
      <PrecompiledHeader>Use</PrecompiledHeader>
      ...
    </ClCompile>
  </ItemDefinitionGroup>

  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32' And '$(DisablePCH)'=='false'">
    <ClCompile>
      <PrecompiledHeader>Use</PrecompiledHeader>
      ...
    </ClCompile>
  </ItemDefinitionGroup>

  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64' And '$(DisablePCH)'=='false'">
    <ClCompile>
      <PrecompiledHeader>Use</PrecompiledHeader>
      ...
    </ClCompile>
  </ItemDefinitionGroup>

<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32' And '$(DisablePCH)'=='true'">
    <ClCompile>
      <PrecompiledHeader>NotUsing</PrecompiledHeader>
      ...
    </ClCompile>
  </ItemDefinitionGroup>

  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64' And '$(DisablePCH)'=='true'">
    <ClCompile>
      <PrecompiledHeader>NotUsing</PrecompiledHeader>
      ...
    </ClCompile>
  </ItemDefinitionGroup>

  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32' And '$(DisablePCH)'=='true'">
    <ClCompile>
      <PrecompiledHeader>NotUsing</PrecompiledHeader>
      ...
    </ClCompile>
  </ItemDefinitionGroup>

  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64' And '$(DisablePCH)'=='true'">
    <ClCompile>
      <PrecompiledHeader>NotUsing</PrecompiledHeader>
      ...
    </ClCompile>
  </ItemDefinitionGroup>

3.Then by default if we use normal command like msbuild xx.vcxproj ... , it will use the precompiledheaders. If we want to disable it in command, use command like msbuild xx.vcxproj /p:DisablePCH=true ....

ps:If you do want to disable PCH(precompiled headers) by msbuild, you can try the possible direction, for some reason I'm not able to test it in my machine :(. Feel free to let me know if it helps or not.

LoLance
  • 25,666
  • 1
  • 39
  • 73
  • 2
    Thanks for such a detailed answer, it helped me a lot. Finally, I end up resolving my problem by disabling precompiled headers from my coverage tool (using a pretty hidden argument), but this answer clarify many doubts using msbuild. – Cartucho Oct 22 '19 at 18:11