我正在努力寻找一种正确的方法来为所有目标传播正确的编译器标志。
让我们假设有一个包含库和单元测试的项目。
ProjectFolder
|-WorkerLibFolder
|-Worker.cpp
|-Worker.hpp
|-CMakeLists.txt (2)
|-main.cpp
|-CMakeLists.txt (1)
|-TestsFolder
|-UnitTests.cpp
|-CMakeLists.txt (3)
在CMakeLists.txt(1)中,我想全局设置编译选项,因为我认为优化级别和其他标志对于项目的所有库都应该相同。add_compile_options(-Wall -Werror -Wno-error=maybe-uninitialized)
用于实现它。
我也使用CMAKE_BUILD_TYPE
功能,它借助CMAKE_CXX_FLAGS_RELEASE
或CMAKE_CXX_FLAGS_DEBUG
标志自动设置所需的优化级别。
而且将这些变量之一隐式传递给编译器这一事实似乎很烦人,因为无论如何,我必须事先为所需的优化标志set(CMAKE_CXX_FLAGS_RELEASE "-Ofast -DNDEBUG -DBOOST_DISABLE_ASSERTS")
设置这些变量,这仅是因为-O3
通过defaut设置为Release配置。
无论如何,直到我要始终在编译测试环境(UniTests.cpp)时设置-O0
的时候,一切正常。 CMakeLists.txt(3)生成project_ut可执行文件。我希望使用配置的优化级别(从CMAKE_BUILD_TYPE
中获取)编译WorkerLib,但这自动意味着CMAKE_CXX_FLAGS_RELEASE
和-Ofast
会传播到UnitTest.cpp
我想我可能在这里做了一些奇怪的事情,并且有更好的方法来处理问题。这里的一种选择是在没有CMAKE_BUILD_TYPE
功能帮助的情况下传递优化标志,但这似乎是错误的(因为我不想维护每个目标的标志列表)。
设置标志的正确方法是使用set_compile_options
和target_compile_options
以及使用add_compile_definitions
和target_compile_definitions
的宏。您不应该(或很少)自己触摸CMAKE_*_FLAGS
,并且在创建生成器表达式时,也很少应触摸CMAKE_*_FLAGS_*
。使用$<CONFIG:RELEASE>
更简单,因为您无需关心大小写(-DCMAKE_BUILD_TYPE=Release
和-DCMAKE_BUILD_TYPE=rElEaSe
都是发行版),而且我的眼睛也更清晰易读。
在主CMakeLists.txt
中执行:
add_compile_options(
-Wall -Werror -Wno-error=maybe-uninitialized
$<$<CONFIG:RELEASE>:-Ofast>
)
add_compile_definitions(
$<$<CONFIG:RELEASE>:NDEBUG>
$<$<CONFIG:RELEASE>:BOOST_DISABLE_ASSERTS>
)
add_subdirectory(WorkerLibFolder)
add_subdirectory(TestsFolder)
add_executable(main ...)
我一直希望在编译测试环境时设置-O0
完全要这样做。在TestsFolder
内部执行:
add_compile_options(-O0)
add_library(test_environment ....)
或更佳:
add_library(test_environment ..
target_compile_options(test_environment PRIVATE -O0)
因为编译选项是累积的,所以TestsFolder
中添加的选项将加后缀/编译行中的最后一个选项,因此它将起作用,我的意思是ex。 gcc -O3 -Ofast -O0
将与gcc -O0
相同。