12

以下内容来自一个常规的 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等控制我的构建。如果我使用常规设置并尝试PreprocessorDefinitions使用<Message Text="PreprocessorDefinitions: $(PreprocessorDefinitions)"该字段进行输出,该字段实际上是空白的,并且不包含预期的内容,<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>尽管我可以使用使用这些键中的任何一个来控制我的构建#ifdef等等。

  1. 这是为什么?
  2. 我可以做些什么来通过任务Properties元素传递 PreprocessorDefinitions für VS2010 C++ 项目?
4

3 回答 3

36

这可以在不修改原始项目的情况下完成:在 中完成的第一件事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 及更高版本中,出现了自定义构建的新方法。与上面的原理相同,但更简单:msbuild 将自动Directory.Build.props获取项目文件目录中命名的文件,甚至是上面的所有目录,而不需要额外的命令行选项(因此,在 VS 中也可以正常工作)。项目文件也变得不那么冗长了:

<Project>
  <ItemDefinitionGroup>
    <ClCompile>
      <PreprocessorDefinitions>%(PreprocessorDefinitions);ADDITIONAL</PreprocessorDefinitions>
    </ClCompile>
  </ItemDefinitionGroup>
</Project>
于 2013-07-03T11:22:51.607 回答
8

如果不进行修改,则无法执行此操作,demo.vcxproj因为您需要访问PreprocessorDefinitionsof CLCompile,它不是 a 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
于 2013-02-28T17:25:33.453 回答
2

根据@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\""

于 2019-04-07T12:42:03.693 回答