我想在CMake中更改CMAKE_CXX_FLAGS_RELEASE
或CMAKE_CXX_FLAGS_DEBUG
的默认值。基本上,我有一些项目默认值与CMake略有不同(例如发布),我不应该问自己"哦,他们的-O3或我们的-O2添加add_compile_options时优先。"
现在,我知道如何设置这些值,但我不知道如何通过两种常用方式使用户可编辑:在命令行上使用 - DCMAKE_CXX_FLAGS_DEBUG=yourflags
或使用ccmake或CMakeSetup。
问题是CMAKE为这些设置并缓存了它们自己的默认值,如果你试图在不使用FORCE的情况下覆盖变量,那么"默认值为"永远不会改变。如果我在我的set命令set(CMAKE_CXX_FLAGS_DEBUG blah CACHE STRING "" FORCE)
中使用FORCE,它将在每次运行脚本时覆盖它,从而消除了用户根据需要进行更改的可能性。
我设法通过执行以下操作来破解它与CCMAKE合作,但这仍然无法与cmake -DCMAKE_CXX_FLAGS_DEBUG
一起使用,因为它覆盖了用户更改后的更改:
set(DEFAULTS_SET FALSE CACHE BOOL "")
set(CMAKE_CXX_FLAGS_DEBUG "-this -that" CACHE STRING "" FORCE)
set(DEFAULTS_SET TRUE CACHE BOOL "" FORCE)
显然,这是一个讨厌的黑客,并没有完全奏效(在cmake -Dwhatever = thisorthat的情况下)。我也可以添加其他构建类型,但我真的不明白为什么只需改变一些简单的东西就可以了。
编辑2015年3月1日:
我已经创建了一个有效的解决方案,尽管我仍然不会对我必须做的事感到非常激动。我看到其他评论解决了设置CMAKE_CXX_FLAGS_DEBUG
和朋友的问题而没有让他们受到破坏,但这最初对我没有用,因为我试图根据编译器选择它们正在使用中。但是,编译器尚未确定,直到它已经为我填充了变量。我使用的技巧如下。您必须将标志变量设置为' special'在项目命令之前。
set(CMAKE_CXX_FLAGS_DEBUG "_UNSET" CACHE STRING "")
project(your_project C CXX)
if(${CMAKE_CXX_FLAGS_DEBUG} STREQUAL "_UNSET")
# Do some compiler switching here and then set your flags with FORCE.
set(CMAKE_CXX_FLAGS_DEBUG "-ggdb3 -O0" CACHE STRING "" FORCE)
endif()
现在允许我选择通过命令行-D或cmake-gui完全覆盖的默认值。
答案 0 :(得分:9)
我只想添加我看到的四种可能性:
拥有自己的工具链文件,其中包含您支持的每个编译器的预设,如:
<强> GNUToolchain.cmake 强>
set(CMAKE_CXX_FLAGS_DEBUG "-ggdb3 -O0" CACHE STRING "")
然后将其与
一起使用cmake -DCMAKE_TOOLCHAIN_FILE:string=GNUToolchain.cmake ...
您可以通过选中CMAKE_GENERATOR
(在project()
命令之前有效)来尝试确定编译器:
<强>的CMakeLists.txt 强>
if("${CMAKE_GENERATOR}" MATCHES "Makefiles" OR
("${CMAKE_GENERATOR}" MATCHES "Ninja" AND NOT WIN32))
set(CMAKE_CXX_FLAGS_DEBUG "-ggdb3 -O0" CACHE STRING "")
endif()
project(your_project C CXX)
您可以使用CMAKE_USER_MAKE_RULES_OVERRIDE
为脚本提供自己的..._INIT
值:
在加载CMake的内置编译器和平台信息模块之后但在使用信息之前加载它。该文件可以设置平台信息变量以覆盖CMake的默认值。
<强> MyInitFlags.cmake 强>
# Overwrite the init values choosen by CMake
if (CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_CXX_FLAGS_DEBUG_INIT "-ggdb3 -O0")
endif()
<强>的CMakeLists.txt 强>
set(CMAKE_USER_MAKE_RULES_OVERRIDE "MyInitFlags.cmake")
project(your_project C CXX)
您可以通过检查编译器标志变量的..._INIT
变体来从3月1日开始简化您的解决方案:
<强>的CMakeLists.txt 强>
project(your_project C CXX)
if (DEFINED CMAKE_CXX_FLAGS_DEBUG_INIT AND
"${CMAKE_CXX_FLAGS_DEBUG_INIT}" STREQUAL "${CMAKE_CXX_FLAGS_DEBUG}")
# Overwrite the init values choosen by CMake
if (CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_CXX_FLAGS_DEBUG "-ggdb3 -O0" CACHE STRING "" FORCE)
endif()
endif()
评论:
我更喜欢并使用工具链变体。但我承认它的缺点是必须手动提供工具链文件(如果你没有通过脚本/批处理文件调用cmake
)。
参考:
答案 1 :(得分:1)
弗洛里安使用工具链文件的答案对于较早版本的CMake是一个很好的答案。但是CMake 3.19添加了一项名为presets的功能,该功能可帮助管理项目的常见缓存变量集。基本上,您将创建两个文件CMakePresets.json
和CMakeUserPresets.json
(通常添加到.gitignore
或类似文件)中的至少一个,其中包含有关如何配置项目的规范。
例如,您可以写:
{
"version": 1,
"cmakeMinimumRequired": {
"major": 3,
"minor": 19,
"patch": 0
},
"configurePresets": [
{
"name": "default",
"displayName": "Default",
"description": "Build using Ninja and a GCC-like compiler",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build",
"cacheVariables": {
"CMAKE_CXX_FLAGS_DEBUG": "-ggdb3 -O0"
}
},
{
"name": "default-vcpkg",
"displayName": "Default (vcpkg)",
"description": "Default build with vcpkg (from VCPKG_ROOT)",
"inherits": "default",
"cacheVariables": {
"CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
}
}
]
}
然后,从源目录中,您的CMake命令行将变为:
$ cmake --preset=default
这种方法有一些优点:
*_INIT
标志中的标志。扩展第4点和第5点:添加标记是个坏主意,除非它们必须必须正确地编译 并且没有内置标记达到这些标志的功能(例如CMAKE_CXX_STANDARD
)。如果有人尝试使用其他编译器(甚至是同一编译器的不同版本)来编译您的库,例如,如果您添加的警告标志太新或不被支持,则他们可能会遇到问题。您可以使用生成器表达式和/或复杂的逻辑(例如上面的_UNDEF
技巧)来解决此问题,但是使用工具链或这些新的预设通常更容易,更方便。
例如,要正确添加-Wsuggest-override
,您需要编写:
target_compile_options(lib PRIVATE $<$<AND:$<VERSION_GREATER_EQUAL:$<CXX_COMPILER_VERSION>,5.1>,$<COMPILE_LANG_AND_ID:CXX,GNU>>:-Wsuggest-override>)
# ... or ...
# Note: only correct if using "PRIVATE". Must use a genex for INTERFACE/PUBLIC because the whole genex gets exported, whereas this flag will get exported verbatim.
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 5.1)
target_compile_options(lib PRIVATE -Wsuggest-override)
endif ()
或者您也可以将标志放在已经知道您正在使用哪种编译器的工具链/预设中。