How to set PreProcessorDefinitions as a task propery for the msbuild task
Asked Answered
P

3

13

The following is taken from a regular VS2010 C++ project.

    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <PrecompiledHeader>Use</PrecompiledHeader>
      <Optimization>MaxSpeed</Optimization>
      <FunctionLevelLinking>true</FunctionLevelLinking>
      <IntrinsicFunctions>true</IntrinsicFunctions>
      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
    </ClCompile>

If i edit PreprocessorDefinitions i can set a definition that is used by the preprocessor. I can see this in my code via #ifdef etc.

However if i use the following

  <Target Name="NormalBuild" Condition=" '$(_InvalidConfigurationWarning)' != 'true' " DependsOnTargets="_DetermineManagedStateFromCL;CustomBeforeBuild;$(BuildDependsOn)" Returns="@(ManagedTargetPath)">
    <ItemGroup>
        <ManagedTargetPath Include="$(TargetPath)" Condition="'$(ManagedAssembly)' == 'true'" />
    </ItemGroup>
      <Message Text="PreprocessorDefinitions: $(PreprocessorDefinitions)" Importance="High" />
  </Target>

  <Target Name="TestBuild" Returns="@(ManagedTargetPath)">
    <MSBuild Projects="demo.vcxproj" Targets="NormalBuild" Properties="PreprocessorDefinitions=THISGETSSETBUTDOESNOTHING"/>
  </Target>

i can also see via the message that PreprocessorDefinitions contains the value i set via Properties="PreprocessorDefinitions=THISGETSSETBUTDOESNOTHING" but i can not control my build using #ifdef etc. If i use a regular setup and try to output PreprocessorDefinitions using <Message Text="PreprocessorDefinitions: $(PreprocessorDefinitions)" the field is actually blank and does not contain the expected <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> although i can use any one of those keys to control my build using #ifdef etc.

  1. Why is that?
  2. What can i do to pass PreprocessorDefinitions für a VS2010 C++ Project via the tasks Properties element?
Py answered 28/2, 2013 at 17:5 Comment(0)
B
8

You can't do this without modifying demo.vcxproj because you need access to the PreprocessorDefinitions of CLCompile, which is not a PropertyGroup, and thus can't be passed via the MSBuild command line.

You can modify the preprocessor definitions in the GUI via Project Properties -> Configuration Propertis -> C/C++ -> Preprocessor, or edit the XML directly:

  <ClCompile>
    ....
    <PreprocessorDefinitions>$(MyMacro);%(PreprocessorDefinitions)</PreprocessorDefinitions>
  </ClCompile>

In your MSBuild project:

  <Target Name="TestBuild" Returns="@(ManagedTargetPath)">
    <MSBuild Projects="demo.vcxproj" Targets="NormalBuild" Properties="MyMacro=THISGETSSETBUTDOESNOTHING"/>
  </Target>

This is equivalent to running MSBuild.exe as:

  MSBuild demo.vcxproj /p:MyMacro=THISGETSSETBUTDOESNOTHING
Bobbobb answered 28/2, 2013 at 17:25 Comment(2)
None of this is working in my 2017 version, and I don't have a ClCompile section.Algetic
I don't work in this MSVC/VS world often.., more Eclipse. I had added a new folder and an empty cpp file, but like a Build Path, I don't think it was recognized yet, and/or the C++ 'facet' was not in the 'aggregate' project file. Once I realized the errors were in the individual sub-project vcxproj files defining their own preprocessor statements that caused this flood of xkeycheck errors to appear, I saw each of those projects were the ones to edit.. Thanks though!Algetic
C
38

This can be done without modifying the original project: the first thing done in Microsoft.Cpp.Targets, which is normally one of the last things imported in a normal C++ project, is to check if there's a property called ForceImportBeforeCppTargets and if so, import it.

So suppose you want to add ADDITIONAL to the preprocessor definitions you create a file 'override.props' like this (for full automation use the WritelinesToFile task to create the file):

<?xml version="1.0" encoding="utf-8"?> 
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <ItemDefinitionGroup>
    <ClCompile>
      <PreprocessorDefinitions>%(PreprocessorDefinitions);ADDITIONAL</PreprocessorDefinitions>
    </ClCompile>
  </ItemDefinitionGroup>

</Project>

And call

<MSBuild Projects="demo.vcxproj" 
         Properties="ForceImportBeforeCppTargets=override.props"/>

or from the command line that would be

msbuild demo.vcxproj /p:ForceImportBeforeCppTargets=override.props

Note as richb points out in the comment, the above only works if override.props can be found by msbuild's lookup rules. To make sure it is always found just specify the full path.

Update

Some years later, in msbuild 15 and beyond, there are new ways to customise builds. Same principle as above, but simpler: msbuild will automatically pick up the file named Directory.Build.props in the project file's directory or even all directories above that, without needing additional commandline options (so, also works from within VS without problems). And the project files also became a bit less verbose as well:

<Project>
  <ItemDefinitionGroup>
    <ClCompile>
      <PreprocessorDefinitions>%(PreprocessorDefinitions);ADDITIONAL</PreprocessorDefinitions>
    </ClCompile>
  </ItemDefinitionGroup>
</Project>
Comical answered 3/7, 2013 at 11:22 Comment(5)
Thanks for this info it's very helpful. Just a couple of corrections. First, the command line parameter is /p: not /t:. Second, you need to specify the full path to override.props otherwise msbuild ignores it without any warning.Airily
I just want to emphasise the full path mention of @richb, which I found was critical in making this work. By outputting a <ResourceCompile> section too, it works with resource compiler definitions.Graybill
Yeah actually last phrase in your answer is misleading - it does not work even if file located in the same directory where vcxproj is or msbuild is invoked. Spent quite a bit of time figuring that out.Archaean
sorry for that - I'll change it to just full path, which always works and is better ractice anywayComical
Yes, the silent failure to load the .props file due to it not being found is annoying. You can simply use purposefully malformed xml in your .props file in order to double-check that the filepath is correct. If the .props file is correctly found, it will print an error at build-time.Thessalonians
B
8

You can't do this without modifying demo.vcxproj because you need access to the PreprocessorDefinitions of CLCompile, which is not a PropertyGroup, and thus can't be passed via the MSBuild command line.

You can modify the preprocessor definitions in the GUI via Project Properties -> Configuration Propertis -> C/C++ -> Preprocessor, or edit the XML directly:

  <ClCompile>
    ....
    <PreprocessorDefinitions>$(MyMacro);%(PreprocessorDefinitions)</PreprocessorDefinitions>
  </ClCompile>

In your MSBuild project:

  <Target Name="TestBuild" Returns="@(ManagedTargetPath)">
    <MSBuild Projects="demo.vcxproj" Targets="NormalBuild" Properties="MyMacro=THISGETSSETBUTDOESNOTHING"/>
  </Target>

This is equivalent to running MSBuild.exe as:

  MSBuild demo.vcxproj /p:MyMacro=THISGETSSETBUTDOESNOTHING
Bobbobb answered 28/2, 2013 at 17:25 Comment(2)
None of this is working in my 2017 version, and I don't have a ClCompile section.Algetic
I don't work in this MSVC/VS world often.., more Eclipse. I had added a new folder and an empty cpp file, but like a Build Path, I don't think it was recognized yet, and/or the C++ 'facet' was not in the 'aggregate' project file. Once I realized the errors were in the individual sub-project vcxproj files defining their own preprocessor statements that caused this flood of xkeycheck errors to appear, I saw each of those projects were the ones to edit.. Thanks though!Algetic
S
2

Based on @Kevin answer you need to define a user-defined macro in a PropertySheet. Then create a Preprocessor which refers to the user-defined macro. You can now use the new preprocessor value in your code. Finally, for the build, you can change the value of user-defined macro with /p flag. In here I defined a user-defined value like mymacro and a preprocessor value like VAL. Now you can simply compile the project with /p:mymacro="\"some thing new\"".

#include <iostream>


int main() {
    std::cout << VAL << std::endl;

    getchar();
}

yourproject.vcxproj:

<ClCompile>
  ...
  <PreprocessorDefinitions>VAL=$(mymacro);%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>

msbuild yourproject.vcxproj /p:mymacro="\"some thing new\""

Springer answered 7/4, 2019 at 12:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.