使用 CMake 时处理编译器标志的正确方法

NwM*_*Man 2 cmake build-system compiler-flags

我正在努力寻找一种正确的方法来为所有目标传播正确的编译器标志。

假设有一个包含库和单元测试的项目。

ProjectFolder
|-WorkerLibFolder
  |-Worker.cpp
  |-Worker.hpp
  |-CMakeLists.txt  (2)
|-main.cpp
|-CMakeLists.txt (1)
|-TestsFolder
  |-UnitTests.cpp
  |-CMakeLists.txt  (3)
Run Code Online (Sandbox Code Playgroud)

在 CMakeLists.txt (1) 中,我想全局设置编译选项,因为我假设项目的所有库的优化级别和其他标志应该相同。 add_compile_options(-Wall -Werror -Wno-error=maybe-uninitialized)用来实现它。

我还使用CMAKE_BUILD_TYPE了在CMAKE_CXX_FLAGS_RELEASECMAKE_CXX_FLAGS_DEBUG标志的帮助下自动设置所需优化级别的功能。

此外,这些变量之一被隐式传递给编译器的事实似乎很烦人,因为无论如何我必须提前为所需的优化标志设置这些变量,set(CMAKE_CXX_FLAGS_RELEASE "-Ofast -DNDEBUG -DBOOST_DISABLE_ASSERTS")因为这-O3是默认设置的发布配置。

无论如何,直到我想-O0在编译测试环境 (UniTests.cpp) 时总是设置的那一刻,一切都很好。CMakeLists.txt (3) 生成 project_ut 可执行文件。我希望 WorkerLib 使用配置的优化级别(取自CMAKE_BUILD_TYPE)进行编译,但它自动意味着CMAKE_CXX_FLAGS_RELEASEwith-Ofast被传播到 UnitTest.cpp

我想我可能在这里做了一些奇怪的事情,并且有更好的方法来处理问题。这里的一个选择是在没有CMAKE_BUILD_TYPE功能帮助的情况下传递优化标志,但这似乎是错误的(因为我不想为每个目标维护标志列表)。

编辑:

#CMakeLists.txt(1):
cmake_minimum_required(VERSION 3.14.1)
project(TestProject LANGUAGES CXX C)

#####  common comp flags #####

add_compile_options(-Wall -Werror -Wno-error=maybe-uninitialized)

##############################

set(RELEASE_FLAGS "-Ofast -DNDEBUG -DBOOST_DISABLE_ASSERTS")
set(DEBUG_FLAGS "-O0 -ggdb3")

set(CMAKE_CXX_FLAGS_RELEASE ${RELEASE_FLAGS})
set(CMAKE_C_FLAGS_RELEASE ${RELEASE_FLAGS})

set(CMAKE_CXX_FLAGS_DEBUG ${DEBUG_FLAGS})
set(CMAKE_C_FLAGS_DEBUG ${DEBUG_FLAGS})

add_subdirectory(WorkerLibFolder)
add_subdirectory(TestsFolder)


add_executable(mainExec main.cpp)
target_link_libraries(mainExec PRIVATE worker)

Run Code Online (Sandbox Code Playgroud)
#CMakeLists.txt(3):
add_executable(tests UnitTests.cpp)
target_link_libraries(tests PRIVATE worker)
#I want sommehow fix optimization flags for that particular target, while for worker library left them as they were set
Run Code Online (Sandbox Code Playgroud)
#CMakeLists.txt(2):
add_library(worker Worker.cpp)
target_include_directories(worker PUBLIC ${CMAKE_CURRENT_LIST_DIR})
Run Code Online (Sandbox Code Playgroud)

Kam*_*Cuk 6

设置标志的正确方法是使用set_compile_optionsandtarget_compile_options和宏使用add_compile_definitionsand 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>
       $<$<CONFIG:DEBUG>-O0>
       $<$<CONFIG:DEBUG>-ggdb3>
)
add_compile_definitions(
        $<$<CONFIG:RELEASE>:NDEBUG>
        $<$<CONFIG:RELEASE>:BOOST_DISABLE_ASSERTS>
)
add_subdirectory(WorkerLibFolder)
add_subdirectory(TestsFolder)
add_executable(main ...)
Run Code Online (Sandbox Code Playgroud)

我想在编译测试环境时总是设置 -O0

所以就这样做吧。里面TestsFolder做:

add_compile_options(-O0)
add_library(test_environment  ....)
Run Code Online (Sandbox Code Playgroud)

或更好:

add_library(test_environment ..
target_compile_options(test_environment PRIVATE -O0)
Run Code Online (Sandbox Code Playgroud)

因为编译选项是累积的,添加的选项TestsFolder将是后缀/编译行上的最后一个选项,所以它会起作用,我的意思是 ex。gcc -O3 -Ofast -O0将编译相同gcc -O0

target_include_directories(worker PUBLIC ${CMAKE_CURRENT_LIST_DIR})

CMAKE_CURRENT_LIST_DIR通常从使用include(this_files)文件从文件所在指示。包含当前目录CMAKE_CURRENT_SOURCE_DIR更常用,这表明 cmake 正在处理的当前源目录。

PS:我不会使用不同的优化选项对程序/库进行单元测试,然后发布版本。我使用与发布版本完全相同的编译选项进行单元测试。某些错误仅在启用优化后才会出现。我最好对(以前的)库进行单元测试的方式是在禁用和启用优化的情况下进行编译和单元测试。