默认在 CMake 中优化
我有一个 C++ 项目,它使用 CMake 作为其构建系统.我想要以下行为:
I have a C++ project which uses CMake as its build system. I'd like the following behavior:
如果 cmake 被调用为 cmake ..
,那么 CMAKE_CXX_FLAGS
是 -O3 -Wall -Wextra
If cmake is invoked as cmake ..
, then CMAKE_CXX_FLAGS
is -O3 -Wall -Wextra
如果 cmake 被调用为 cmake .. -DCMAKE_BUILD_TYPE=Debug
,那么 CMAKE_CXX_FLAGS
是 -g -Wall -Wextra
If cmake is invoked as cmake .. -DCMAKE_BUILD_TYPE=Debug
, then CMAKE_CXX_FLAGS
is -g -Wall -Wextra
我尝试了以下
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
set(CMAKE_CXX_FLAGS "-O3 -Wall -Wextra")
set(CMAKE_CXX_FLAGS_DEBUG "-g -Wall -Wextra")
但这有一个大问题.首先,如果使用第二次调用,则 -O3
和 -g
标志都会传递给编译器.此外,如果我使用第二次调用和之后的第一次调用,CMAKE_BUILD_TYPE
将保持 Debug
虽然没有明确排序 - 所以我得到了一个调试版本,尽管我想要一个优化的版本.
But this has a big problem. First of all, if the second invocation is used, then both -O3
and -g
flags are passed to the compiler. Besides, if I use the second invocation and the first thereafter, CMAKE_BUILD_TYPE
stays Debug
although not explicitly ordered so - so I get a Debug build although I want an optimized build.
为什么?我该怎么做才能获得所需的行为?
Why? What can I do to get the desired behavior?
推荐答案
首先:推荐的 CMake 用法是始终在命令行上明确指定 CMAKE_BUILD_TYPE
(当且仅当使用单个 -配置生成器).您的用例偏离了此最佳实践,因此将此答案视为您可以如何做",而不一定是您应该如何做".
First off: recommended usage of CMake is to always specify CMAKE_BUILD_TYPE
explicitly on the command line (if and only if using a single-configuration generator). Your use case deviates from this best practice, so treat this answer as "how you can do it," not necessarily as "how you should do it."
要解决第一个问题,您应该能够在 CMakeList 的早期执行此操作:
To address the first issue, you should be able to do this early in your CMakeList:
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()
set(CMAKE_CXX_FLAGS "-Wall -Wextra")
set(CMAKE_CXX_FLAGS_DEBUG "-g")
set(CMAKE_CXX_FLAGS_RELEASE "-O3")
这将确保如果您根本不指定构建类型,它将默认为发布",因此将使用 CMAKE_CXX_FLAGS_RELEASE
.
This will make sure that if you do not specify a build type at all, it will default to "Release" and thus CMAKE_CXX_FLAGS_RELEASE
will be used.
第二个更难解决.从命令行传递的变量(例如 CMAKE_BUILD_TYPE=Debug
)由 CMake 缓存,因此在后续调用中重新使用(这是必要的,因为 CMake 可以重新触发如果您在两次构建之间修改其输入,则自行修改).
The second one is harder to tackle. Variables passed from the command line (such as CMAKE_BUILD_TYPE=Debug
) are cached by CMake and thus re-used in subsequent invocations (that is necessary, since CMake can re-trigger itself if you modify its inputs between builds).
唯一的解决方案是让用户再次显式切换构建类型,使用 cmake .. -DCMAKE_BUILD_TYPE=Release
.
The only solution is to make the user switch the build type explicitly again, using cmake .. -DCMAKE_BUILD_TYPE=Release
.
考虑为什么这是必要的:正如我所说,如果 CMake 的输入(CMakeLists.txt
文件或其依赖项)自上次 CMake 运行以来发生了变化,则 CMake 可以重新触发自身作为构建的一部分.在这种情况下,它也将在没有命令行参数的情况下运行,例如 -DCMAKE_BUILD_TYPE=whatever
,并将依赖缓存提供与上次相同的值.这种情况与您手动运行 cmake ..
没有附加参数没有区别.
Consider why this is necessary: as I said, CMake can re-trigger itself as part of a build if CMake's input (CMakeLists.txt
files or their dependencies) has changed since last CMake ran. In such case, it will also be run without command-line arguments such as -DCMAKE_BUILD_TYPE=whatever
, and will rely on the cache to supply the same value as last time. This scenario is indistinguishable from you manually running cmake ..
without additional arguments.
如果没有在命令行中明确指定,我可以提供一个 hacky 解决方案来始终将 CMAKE_BUILD_TYPE
重置为 Release
.但是,这也意味着如果自动重新生成发生,生成为 Debug
的构建系统将重新生成为 Release
.我很确定这不是你想要的.
I could provide a hacky solution to always reset CMAKE_BUILD_TYPE
to Release
if not specified explicitly on the command line. However, it would also mean that a buildsystem generated as Debug
would get re-generated as Release
if automatic re-generation happened. I am pretty sure that's not what you want.
相关文章