【问题标题】:msbuild: set a specific preprocessor #define in the command linemsbuild:在命令行中设置特定的预处理器#define
【发布时间】:2010-09-15 01:17:05
【问题描述】:

在 C++ 文件中,我有这样的代码:

#if ACTIVATE
#   pragma message( "Activated" )
#else
#   pragma message( "Not Activated")
#endif

我想使用 msbuild 命令行将此 ACTIVE 定义设置为 1。

试过了,还是不行:

msbuild /p:DefineConstants="ACTIVATE=1"

有什么想法吗?

【问题讨论】:

    标签: c++ visual-studio msbuild


    【解决方案1】:

    我参加聚会有点晚了(只有 4 年左右),但我只需要在一个项目中解决这个问题,并在寻找解决方案时偶然发现了这个问题。我们的解决方案是使用其中定义了 /D 的环境变量,并结合 Visual Studio 中的 Additional Options 框。

    1. 在 Visual Studio 中,将环境变量宏 $(ExternalCompilerOptions) 添加到项目选项->C/C++->命令行下的附加选项(记住调试和发布配置)
    2. 在调用 msbuild 之前设置环境变量。使用 /D 编译器选项定义宏
        c:\> set ExternalCompilerOptions=/DFOO /DBAR 
        c:\> msbuild
    

    第 1 项最终在 vcxproj 文件中看起来像这样:

        <ClCompile>
          <AdditionalOptions>$(ExternalCompilerOptions) ... </AdditionalOptions>
        </ClCompile>
    

    这适用于 VS 2010。我们从各种构建脚本驱动 msbuild,因此环境变量 ugliness 被隐藏了一点。请注意,当您需要将定义设置为特定值(/DACTIVATE=1)时,我没有测试这是否有效。我认为它会起作用,但我担心那里有多个“=”。

    H^2

    【讨论】:

    • 感谢您迟到的答复:)
    • 要在构建资源文件时设置定义,还要在配置属性 -> 资源 -> 命令行下设置附加选项
    【解决方案2】:

    C++ 项目(和解决方案)尚未(还?)集成到 MSBuild 环境中。作为构建过程的一部分,VCBuild task 被调用,它只是 vcbuild.exe 的包装。

    你可以:

    • 为您的解决方案创建一个特定的配置,其中将定义ACTIVATE=1,并使用devenv.exe(使用/ProjectConfig 开关)对其进行编译。
    • 创建您自己的目标文件以包装您自己对VCBuild task 的调用(请参阅 Override 参数)...
    • 使用 vcbuild.exe 代替 msbuild.exe。(vcbuild.exe 似乎没有等效的 Override 参数)。

    请注意,除非您稍微调整一下项目文件,否则您的解决方案也不适用于 C# 项目。作为参考,我会这样做:

    • 在调用&lt;Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /&gt;之前添加以下代码:
    $(DefineConstants);$(MyConstants)
    • 像这样调用 MSBuild:
    msbuild /p:MyConstants="ACTIVATE=1"

    【讨论】:

    • 我可以使用 vcbuild.exe 而不是 msbuild.exe 但问题是一样的。如何在vcbuild命令行中设置特定的预处理器?
    • 你是对的:我错误地认为 vcbuild.exe 具有与 VCBuild 任务相同的参数集。答案已更新。
    • 拍得好,&lt;DefineConstants&gt;$(DefineConstants);$(MyConstants)&lt;/DefineConstants&gt;,这就是我想要的。
    【解决方案3】:

    我想你想要:

    /p:DefineConstants=ACTIVATE
    

    【讨论】:

    • @Matt,我提出了相同的答案,但两位评论者告诉我这不起作用。所以我删除了我的答案,以便其他有更多 MSBuild 经验的人提供想法。
    • 哦,acemtp 告诉我他已经尝试过了,但没有成功。
    • 这也适用于我。我确实在我定义的常量列表周围加上了引号,但这可能并不重要。
    • 这似乎覆盖了 .csproj 文件中定义的常量
    【解决方案4】:

    如果您需要定义一些常量(不仅仅是true/false),您可以通过以下方式进行:

    在命令行上:

    MSBuild /p:MyDefine=MyValue
    

    在 vcxproj 文件中(在 &lt;ClCompile&gt; 部分;和/或 &lt;ResourceCompile&gt;,取决于您需要的位置):

    <PreprocessorDefinitions>MY_DEFINE=$(MyDefine);$(PreprocessorDefinitions)</PreprocessorDefinitions>
    

    请注意,如果您在调用MSBuild 时未指定/p:MyDefine=MyValue,则空字符串将被分配给MY_DEFINE 宏。如果你觉得没问题,就是这样。如果没有,请继续阅读。

    如果未指定相应的 MSBuild 参数,如何使宏未定义

    要使MY_DEFINE 宏未定义而不是空字符串,您可以使用以下技巧:

    <ClCompile>
      ....
      <PreprocessorDefinitions>_DEBUG;_CONSOLE;OTHER_UNCONDITIONAL_MACROS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <PreprocessorDefinitions Condition="'$(MyDefine)'!=''">MY_DEFINE=$(MyDefine);%(PreprocessorDefinitions)</PreprocessorDefinitions>
      ....
    </ClCompile>
    

    首先PreprocessorDefinitions 定义无条件宏。当MyDefine 不是空字符串时,第二个PreprocessorDefinitions 还定义了MY_DEFINE 宏。您可以通过将以下代码放入您的 cpp 文件中来进行测试:

    #define STRINGIZE2(x) #x
    #define STRINGIZE(x) STRINGIZE2(x)
    
    #ifndef MY_DEFINE
    #pragma message("MY_DEFINE is not defined.")
    #else
    #pragma message("MY_DEFINE is defined to: [" STRINGIZE(MY_DEFINE) "]")
    #endif
    

    并运行:

    > MSBuild SandBox.sln /p:Configuration=Debug /p:MyDefine=test /t:Rebuild
    ...
    MY_DEFINE is defined to: [test]
    ...
    
    > MSBuild SandBox.sln /p:Configuration=Debug /p:MyDefine= /t:Rebuild
    ...
    MY_DEFINE is not defined.
    ...
    
    > MSBuild SandBox.sln /p:Configuration=Debug /t:Rebuild
    ...
    MY_DEFINE is not defined.
    ...
    

    【讨论】:

    • 是否可以在项目属性中添加MY_DEFINE=$(MyDefine)?
    • @s4eed 是的,打开项目属性对话框,选择特定的配置(例如调试)和平台(例如 Win32),转到 C/C++ -> 预处理器部分,然后添加“MY_DEFINE=$(MyDefine) ;"在预处理器定义字段中的其他定义之前。例如,如果您在该字段中有“a=b;$(PreprocessorDefinitions)”,则将其设为“MY_DEFINE=$(MyDefine);a=b;$(PreprocessorDefinitions)”。如果需要,请在 Resources -> General 部分执行相同操作。
    • 对其他配置和平台重复此操作。
    • 这似乎比设置环境变量的最佳答案更干净,并且适用于 MSBuild 16.1.76。您可能需要在常量中添加 #ifndef 守卫以消除警告。
    • 这个解决方案的挑战是 MY_DEFINE 总是被定义 - 至少是空字符串。这很难测试。 @MakotoE 对#ifndef 的建议不起作用。
    【解决方案5】:

    使用 CL 环境变量定义预处理器宏

    在调用 MSBUILD 之前,只需使用“/D”选项设置环境变量“CL”,如下所示:

    set CL=/DACTIVATE 定义激活

    您可以使用“#”符号替换“=”符号

    set CL=/DACTIVATE#1 将定义 ACTIVATE=1

    然后调用 MSBUILD

    更多关于 CL 环境变量的文档可以在以下位置找到: https://msdn.microsoft.com/en-us/library/kezkeayy(v=vs.140).aspx

    【讨论】:

      【解决方案6】:

      也许回答这么老的问题是个坏主意,但最近我在谷歌上搜索了一个类似的问题并找到了这个话题。我为某些构建系统编写了一个 cmd 脚本,并成功找到了解决方案。我把它留给后代(:

      根据@acemtp 的问题,我的解决方案是这样的:

      @echo off
      
      :: it is considered that Visual Studio tools are in the PATH
      if "%1"=="USE_ACTIVATE_MACRO" (
          :: if parameter USE_ACTIVATE_MACRO is passed to script
          :: the macro ACTIVATE will be defined for the project
          set CL=/DACTIVATE#1
      )
      call msbuild /t:Rebuild /p:Configuration=Release
      

      UPD:我尝试使用set CL=/DACTIVATE=1,它也有效,但official documentation 建议使用数字符号

      【讨论】:

        【解决方案7】:

        我也需要这样做 - 需要能够构建我的应用程序的两个不同版本,并希望能够使用 VCBUILD 编写构建脚本。 VCBUILD 确实有 /override 命令行开关,但我不确定它是否可以用来修改 #define 符号,然后可以使用 #if 条件编译进行测试。

        我想出的解决方案是编写一个简单的实用程序来创建一个头文件,该文件根据环境变量的状态#defined 符号并从预构建步骤运行该实用程序。在每次执行 VCBUILD 步骤之前,脚本会设置环境变量并“接触”应用程序中的文件以确保执行预构建步骤。

        是的,这是一个丑陋的 hack,但这是我能想到的最好的方法!

        【讨论】:

          【解决方案8】:

          对于 VS2010 及更高版本,请参阅我的回答 here 以获得不需要修改原始项目文件的解决方案。

          【讨论】:

            【解决方案9】:

            正如@bigh_29 所提到的,使用环境变量来定义或取消定义预处理器。

            他建议取消定义预处理器的方法实际上是/UACTIVATE。

            这样,任何匹配 ACTIVATE 的预处理器都会被否定,并且编译器不会通过你的 #if ACTIVATE #endif 附件。

            【讨论】:

              【解决方案10】:

              应该是这样的:

              #ifdef ACTIVATE
              #   pragma message( "Activated" )
              #else
              #   pragma message( "Not Activated")
              #endif
              

              【讨论】:

              • 不,它不是#ifdef,它是一个#if 无论如何,它也不适用于#ifdef
              【解决方案11】:

              答案是:你不能

              【讨论】:

              • 耸耸肩,也许它不在 C++ 中,但 Matt Howells 的回答对我来说确实适用于 C# 项目。想不出它在 C++ 中不起作用的任何原因。
              • 这个被接受的答案太深了,我什至看不到它。
              • @blak3r Matts 的答案在 C++ 中不起作用,这个问题专门针对 C++。而且似乎没有办法只在命令行上添加标志而不对项目文件或另一个外部文件进行额外的更改。
              • 不知道为什么你得到了反对票。问题是针对 C++ 的,'/p:DefineConstants' 的技巧对我来说也不适用于 vcxproj。
              猜你喜欢
              • 1970-01-01
              • 2010-12-19
              • 2010-10-03
              • 1970-01-01
              • 1970-01-01
              • 2013-03-20
              • 1970-01-01
              • 2021-12-29
              • 1970-01-01
              相关资源
              最近更新 更多