【问题标题】:How to set PreProcessorDefinitions as a task propery for the msbuild task如何将 PreProcessorDefinitions 设置为 msbuild 任务的任务属性
【发布时间】:2013-02-14 23:48:16
【问题描述】:

以下内容摘自一个常规的 VS2010 C++ 项目。

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

如果我编辑PreprocessorDefinitions,我可以设置预处理器使用的定义。我可以通过#ifdef 等在我的代码中看到这一点。

但是,如果我使用以下内容

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

我还可以通过消息看到PreprocessorDefinitions 包含我通过Properties="PreprocessorDefinitions=THISGETSSETBUTDOESNOTHING" 设置的值,但我无法使用#ifdef 等控制我的构建。 如果我使用常规设置并尝试使用&lt;Message Text="PreprocessorDefinitions: $(PreprocessorDefinitions)" 输出PreprocessorDefinitions,则该字段实际上是空白的,并且不包含预期的&lt;PreprocessorDefinitions&gt;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)&lt;/PreprocessorDefinitions&gt;,尽管我可以使用其中任何一个键来控制使用#ifdef 等的构建。

  1. 这是为什么呢?
  2. 如何通过任务Properties 元素为 VS2010 C++ 项目传递 PreprocessorDefinitions?

【问题讨论】:

    标签: msbuild


    【解决方案1】:

    这可以在不修改原始项目的情况下完成:在Microsoft.Cpp.Targets 中完成的第一件事,通常是在普通 C++ 项目中导入的最后一件事,是检查是否有一个名为 ForceImportBeforeCppTargets 的属性,如果所以,导入它。

    因此,假设您想将ADDITIONAL 添加到预处理器定义中,您可以像这样创建一个文件“override.props”(为了完全自动化,请使用WritelinesToFile 任务来创建文件):

    <?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>
    

    然后调用

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

    或者从命令行

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

    注意 正如richb 在评论中指出的那样,上面的方法只有在可以通过 msbuild 的查找规则找到 override.props 时才有效。为确保始终可以找到它,只需指定完整路径即可。

    更新

    几年后,在 msbuild 15 及更高版本中,有 new ways to customise builds。原理与上面相同,但更简单:msbuild 将自动在项目文件的目录甚至上面的所有目录中提取名为 Directory.Build.props 的文件,而无需额外的命令行选项(因此,在 VS 中也可以毫无问题地工作)。项目文件也变得不那么冗长了:

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

    【讨论】:

    • 感谢您提供的信息,它非常有帮助。只是一些更正。首先,命令行参数是/p:而不是/t:。其次,您需要指定 override.props 的完整路径,否则 msbuild 会忽略它而不会发出任何警告。
    • 我只想强调@richb 的完整路径提及,我发现这对于完成这项工作至关重要。通过输出 部分,它也可以与资源编译器定义一起使用。
    • 是的,实际上答案中的最后一个短语具有误导性-即使文件位于调用 vcxproj 或 msbuild 的同一目录中,它也不起作用。花了很多时间弄清楚这一点。
    • 很抱歉 - 我将其更改为 完整路径,它始终有效,并且无论如何都是更好的做法
    • 是的,由于找不到 .props 文件而导致无声加载失败很烦人。您可以简单地在 .props 文件中使用故意格式错误的 xml,以便仔细检查文件路径是否正确。如果正确找到 .props 文件,它将在构建时打印错误。
    【解决方案2】:

    如果不修改demo.vcxproj,则无法执行此操作,因为您需要访问CLCompilePreprocessorDefinitions,它不是PropertyGroup,因此无法通过MSBuild 命令行传递。

    您可以通过Project Properties -> Configuration Propertis -> C/C++ -> Preprocessor在GUI中修改预处理器定义,或直接编辑XML:

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

    在您的 MSBuild 项目中:

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

    这相当于将 MSBuild.exe 运行为:

      MSBuild demo.vcxproj /p:MyMacro=THISGETSSETBUTDOESNOTHING
    

    【讨论】:

    • 这些都不适用于我的 2017 版本,而且我没有 ClCompile 部分。
    • 我不经常在这个 MSVC/VS 世界中工作……更多的是 Eclipse。我添加了一个新文件夹和一个空的 cpp 文件,但就像构建路径一样,我认为它尚未被识别,和/或 C++ 'facet' 不在'聚合'项目文件中。一旦我意识到错误出现在各个子项目 vcxproj 文件中,这些文件定义了它们自己的预处理器语句,导致出现大量 xkeycheck 错误,我看到这些项目中的每一个都是要编辑的......不过还是谢谢!
    【解决方案3】:

    根据@Kevin 的回答,您需要在 PropertySheet 中定义用户定义的宏。然后创建一个引用用户定义宏的预处理器。您现在可以在代码中使用新的预处理器值。最后,对于构建,您可以使用/p 标志更改用户定义宏的值。 在这里,我定义了一个用户定义的值,如mymacro 和一个预处理器值,如VAL。 现在您可以简单地使用/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\""

    【讨论】:

      猜你喜欢
      • 2010-10-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多