【问题标题】:Define preprocessor macro through CMake?通过 CMake 定义预处理器宏?
【发布时间】:2012-02-19 12:20:30
【问题描述】:

如何通过 CMake 定义预处理器变量?

等效代码是#define foo

【问题讨论】:

    标签: c++ cmake c-preprocessor


    【解决方案1】:

    很长一段时间以来,CMake 都有 add_definitions 命令用于此目的。但是,最近该命令已被更细粒度的方法(用于编译定义、包含目录和编译器选项的单独命令)取代。

    使用新的add_compile_definitions 的示例:

    add_compile_definitions(OPENCV_VERSION=${OpenCV_VERSION})
    add_compile_definitions(WITH_OPENCV2)
    

    或者:

    add_compile_definitions(OPENCV_VERSION=${OpenCV_VERSION} WITH_OPENCV2)
    

    这方面的好处是它规避了 CMake 为 add_definitions 设置的破旧诡计。 CMake 是一个如此破旧的系统,但他们终于找到了一些理智。

    在此处查找有关将哪些命令用于编译器标志的更多说明:https://cmake.org/cmake/help/latest/command/add_definitions.html

    同样,您可以按照 Jim Hunziker 的回答中的说明针对每个目标执行此操作。

    【讨论】:

    • 来自链接页面:“注意此命令已被替代命令取代:使用 add_compile_definitions() 添加预处理器定义。”也许这个答案需要修改?
    • 在 cmake 3.10.2 中,add_compile_definitions 抛出 CMake Error at CMakeLists.txt:6 (add_compile_definitions): Unknown CMake command "add_compile_definitions".。不得不改用add_compile_options(-D <your-def>)
    • @mannygover 我不这么认为,但您可以使用 -D 设置编译器标志,类似于cmake -D CMAKE_CXXFLAGS='-DDEBUG_CHESSBOARD'(未测试)
    • 它真的很新……事实上它在更现代的 CMake (> 3.11) 中。很难知道何时引入了命令。
    • @Sandburg 您可以打开指向最后一个文档的链接:https://cmake.org/cmake/help/v3.17/command/add_compile_definitions.html#command:add_compile_definitions 并开始向下更改版本号,直到页面消失。那将是它尚不存在的版本。在下一步中,您可以转到Whats new 部分以查找新命令或功能。所以这并不难。
    【解决方案2】:

    要针对特定​​目标执行此操作,您可以执行以下操作:

    target_compile_definitions(my_target PRIVATE FOO=1 BAR=1)
    

    如果您要构建多个目标并且不希望它们都使用相同的标志,则应该这样做。另请参阅target_compile_definitions 上的官方文档。

    【讨论】:

    • @JimHunziker target_compile_definitions(my_target PRIVATE FOO=1)set_source_files_properties(foo.cpp PROPERTIES COMPILE_DEFINITIONS -DFOO=1) 有何不同?
    • @JohnStrood 区别在于范围级别。 target_compile_definitions 设置整个可执行文件/库的值,其中 'set_source_files_properties` 仅设置指定文件的值。后一个命令允许使用不同的语言编译文件;即:set_source_files_properties(compile_me_as_objc.c PROPERTIES -x objective-c。请注意,这里的 -x objective-c 是特定于 GCC/Clang 的标志。
    【解决方案3】:

    本页提出的其他解决方案对某些版本的 Cmake > 3.3.2 很有用。这是我正在使用的版本的解决方案(即3.3.2)。使用$ cmake --version 检查您的 Cmake 版本,然后选择适合您需求的解决方案。 cmake documentation可以在官网找到。

    使用 CMake 版本 3.3.2,为了创建

    #define foo
    

    我需要使用:

    add_definitions(-Dfoo)   # <--------HERE THE NEW CMAKE LINE inside CMakeLists.txt
    add_executable( ....)
    target_link_libraries(....)
    

    并且,为了有一个像另一个这样的预处理器宏定义:

    #define foo=5
    

    这行是这么修改的:

    add_definitions(-Dfoo=5)   # <--------HERE THE NEW CMAKE LINE inside CMakeLists.txt
    add_executable( ....)
    target_link_libraries(....)
    

    请注意(正如@squareskittles 在其中一条评论中建议的那样):“如果您使用CMake 3.3.2,则必须使用use add_definitions()target_compile_definitions()。更现代的命令,@ 987654333@,直到CMake 3.12 才添加。”

    【讨论】:

    • 根据documentation,这个解决方案实际上是更老、更陈旧的方法。其他答案提供了更现代的解决方案。
    • 当我写下答案时,我确实尝试了其他解决方案,但它们都不起作用。
    • @squareskittles,知道为什么其他答案的解决方案不能正常工作吗?如果我尝试,CMake 会出错
    • 如果您使用的是 CMake 3.3.2,正如您在回答中指出的那样,您必须使用 add_definitions()target_compile_definitions()。直到 CMake 3.12 才添加更现代的命令 add_compile_definitions()。 @Leos313
    • @squareskittles,对!用您的信息更新答案!
    【解决方案4】:

    当您的解决方案包含许多项目时,我建议使用 target_*** 操作而不是 add_*** 操作。

    【讨论】:

      【解决方案5】:

      1.) target_compile_definitions

      如果您使用的是 CMake 3.X,则添加预处理器宏的首选应该是 target_compile_definitions

      您应该比任何其他方法更喜欢这种方法的原因是因为它的粒度是基于target。 IE 宏只会添加到您的 exe/库中。

      这是一个常见的例子:

      if (WIN32)
          target_compile_definitions(my_lib PRIVATE   
             # Prevents Windows.h from adding unnecessary includes    
             WIN32_LEAN_AND_MEAN  
             # Prevents Windows.h from defining min/max as macros 
             NOMINMAX 
          )   
      endif() 
      

      2.) add_compile_definitions

      3.12 版中的新功能。

      在此处查找有关将哪些命令用于编译器标志的更多说明:https://cmake.org/cmake/help/latest/command/add_definitions.html

      add_compile_definitions 将宏应用于调用后定义的任何目标。

      这里的逻辑与上面的 add_compile_definitions 相同。

      add_compile_definitions(WIN32_LEAN_AND_MEAN NOMINMAX)
      add_library(my_lib)
      

      如果您是top level project,请谨慎使用此方法。 否则,如果用户使用 add_subdirectory 使用您的库,他们可能会遇到问题。

      3.) 其他不太推荐的方式

      这些方法真的不再推荐了。由于没有模块化,扩展性不好,不支持生成器表达式等。

      为什么 target_compile_definitions 更好/更受欢迎?

      • CMake 代码的读者更清楚它是如何工作的。
      • 如果需要,允许使用 PRIVATE/PUBLIC/INTERFACE。这可以让您图书馆的消费者生活更轻松。
      • 它更加模块化。

      全局应用预处理器标志(或任何编译器标志)可以在您的构建中创建隐藏的依赖关系。

      基本上将 add_compile_definitions 视为 C/C++ 中的全局变量。有时您需要它们,但要小心。

      【讨论】:

        【解决方案6】:

        这是一个示例,您可以将值从 CMAKE 传递到 C++ 代码。说,你想通过:

        • 标志,此处:BOOST(“真”或“假”)
        • 软件版本字符串(例如:“1.0.0”)

        我建议将它们作为字符串传递。 因此,当您使用 CMAKE 构建软件时,您可以传递参数,例如,如果它是使用 boost 库构建的,则从 CMAKE 变量中提取软件版本(这样您只能在一个地方更改该数字) 见下文。

        在 CMakeLists.txt 中:

        add_compile_definitions( 升压=“${升压}” Software_VERSION="${PROJECT_VERSION}" )

        在您的 .cpp 代码中:

        std::cout

        希望这会有所帮助。问候。

        【讨论】:

          猜你喜欢
          • 2022-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-01-26
          • 1970-01-01
          • 2021-12-29
          • 1970-01-01
          相关资源
          最近更新 更多