如何通过 CMake 定义预处理器变量?
等效代码为 #define foo
。
很长一段时间以来,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 的回答中的说明对每个目标执行此操作。
要对特定目标执行此操作,您可以执行以下操作:
target_compile_definitions(my_target PRIVATE FOO=1 BAR=1)
如果您要构建多个目标并且不希望它们都使用相同的标志,则应该这样做。另请参阅 target_compile_definitions 上的官方文档。
target_compile_definitions(my_target PRIVATE FOO=1)
与 set_source_files_properties(foo.cpp PROPERTIES COMPILE_DEFINITIONS -DFOO=1)
有何不同?
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 的标志。
此页面上提出的其他解决方案对于某些版本的 Cmake > 3.3.2 很有用。这里是我正在使用的版本(即 3.3.2)的解决方案。使用 $ cmake --version 检查您的 Cmake 版本,然后选择适合您需要的解决方案。可以在官方页面上找到 cmake 文档。
使用 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()
。更现代的命令 add_compile_definitions()
,直到 CMake 3.12
才添加。”
add_definitions()
或 target_compile_definitions()
。直到 CMake 3.12 才添加更现代的命令 add_compile_definitions()
。 @Leos313
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.) 其他不太推荐的方式
这些方法真的不再推荐了。由于不是模块化的,不能很好地扩展,不支持生成器表达式等。
添加定义
CMAKE_LANG_FLAGS
为什么 target_compile_definitions 更好/更受欢迎?
CMake 代码的读者更清楚它是如何工作的。
如果需要,允许使用 PRIVATE/PUBLIC/INTERFACE。这可以使您图书馆的消费者的生活更轻松。
它更加模块化。
全局应用预处理器标志(或任何编译器标志)可以在您的构建中创建隐藏的依赖项。
本质上将 add_compile_definitions 视为 C/C++ 中的全局变量。有时你需要它们,但要小心。
当您的解决方案包含许多项目时,我建议使用 target_***
操作而不是 add_***
操作。
这是一个示例,您可以将值从 CMAKE 传递到 C++ 代码。说,你想通过:
标志,此处:BOOST(“真”或“假”)
软件版本字符串(例如:“1.0.0”)
我建议将它们作为字符串传递。因此,当您使用 CMAKE 构建软件时,您可以传递参数,例如,如果它是使用 boost 库构建的,则从 CMAKE 变量中提取软件版本(以便您仅在一处更改该数字)见下文。
在 CMakeLists.txt 中:
add_compile_definitions( BOOST="${BOOST}" Software_VERSION="${PROJECT_VERSION}" )
在您的 .cpp 代码中:
std::cout << "软件版本为:" << Software_VERSION << " BOOST: " << BOOST << "\n";
希望这可以帮助。问候。
add_compile_definitions
抛出CMake Error at CMakeLists.txt:6 (add_compile_definitions): Unknown CMake command "add_compile_definitions".
。不得不改用add_compile_options(-D <your-def>)
。cmake -D CMAKE_CXXFLAGS='-DDEBUG_CHESSBOARD'
(未经测试)https://cmake.org/cmake/help/v3.17/command/add_compile_definitions.html#command:add_compile_definitions
并开始向下更改版本号,直到页面消失。那将是它尚不存在的版本。在下一步中,您可以转到Whats new
部分来查找新的命令或功能。所以它不是那么难。