C++ 默认在 CMake 中优化

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/41361631/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 15:26:44  来源:igfitidea点击:

Optimize in CMake by default

c++cmakecompiler-optimization

提问by marmistrz

I have a C++ project which uses CMake as its build system. I'd like the following behavior:

我有一个 C++ 项目,它使用 CMake 作为其构建系统。我想要以下行为:

If cmake is invoked as cmake .., then CMAKE_CXX_FLAGSis -O3 -Wall -Wextra

如果 cmake 被调用为cmake ..,则CMAKE_CXX_FLAGS-O3 -Wall -Wextra

If cmake is invoked as cmake .. -DCMAKE_BUILD_TYPE=Debug, then CMAKE_CXX_FLAGSis -g -Wall -Wextra

如果 cmake 被调用为cmake .. -DCMAKE_BUILD_TYPE=Debug,则CMAKE_CXX_FLAGS-g -Wall -Wextra

I tried the following

我尝试了以下

message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")

set(CMAKE_CXX_FLAGS "-O3 -Wall -Wextra")
set(CMAKE_CXX_FLAGS_DEBUG "-g -Wall -Wextra")

But this has a big problem. First of all, if the second invocation is used, then both -O3and -gflags are passed to the compiler. Besides, if I use the second invocation and the first thereafter, CMAKE_BUILD_TYPEstays Debugalthough not explicitly ordered so - so I get a Debug build although I want an optimized build.

但这有一个很大的问题。首先,如果使用第二次调用,则-O3-g标志都将传递给编译器。此外,如果我使用第二次调用和此后的第一次调用,尽管没有明确排序,但CMAKE_BUILD_TYPE仍然保持不变Debug- 所以尽管我想要一个优化的构建,但我得到了一个调试构建。

Why? What can I do to get the desired behavior?

为什么?我该怎么做才能获得所需的行为?

回答by Angew is no longer proud of SO

First off: recommended usage of CMake is to always specify CMAKE_BUILD_TYPEexplicitly 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."

首先:推荐的 CMake 用法是始终CMAKE_BUILD_TYPE在命令行上明确指定(当且仅当使用单配置生成器时)。您的用例偏离了此最佳实践,因此将此答案视为“您可以如何做”,而不一定是“您应该如何做”。

To address the first issue, you should be able to do this early in your CMakeList:

要解决第一个问题,您应该能够在 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")

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_RELEASEwill be used.

这将确保如果您根本不指定构建类型,它将默认为“发布”并因此CMAKE_CXX_FLAGS_RELEASE将被使用。

The second one is harder to tackle. Variables passed from the command line (such as CMAKE_BUILD_TYPE=Debug) are cachedby 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_BUILD_TYPE=Debug)由 CMake缓存,因此在后续调用中重新使用(这是必要的,因为如果您在构建之间修改其输入,CMake 可以重新触发自身)。

The only solution is to make the user switch the build type explicitly again, using cmake .. -DCMAKE_BUILD_TYPE=Release.

唯一的解决方案是让用户再次显式切换构建类型,使用cmake .. -DCMAKE_BUILD_TYPE=Release.

Consider why this is necessary: as I said, CMake can re-trigger itself as part of a build if CMake's input (CMakeLists.txtfiles 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.

考虑为什么这是必要的:正如我所说,如果 CMake 的输入(CMakeLists.txt文件或其依赖项)自上次 CMake 运行以来发生了变化,CMake 可以重新触发自身作为构建的一部分。在这种情况下,它也将在没有命令行参数的情况下运行,例如-DCMAKE_BUILD_TYPE=whatever, 并将依赖缓存提供与上次相同的值。这种情况与您在cmake ..没有其他参数的情况下手动运行没有区别。

I could provide a hacky solution to always reset CMAKE_BUILD_TYPEto Releaseif not specified explicitly on the command line. However, it would also mean that a buildsystem generated as Debugwould get re-generated as Releaseif automatic re-generation happened. I am pretty sure that's not what you want.

如果未在命令行中明确指定,我可以提供一个 hacky 解决方案,以始终重置CMAKE_BUILD_TYPERelease。但是,这也意味着生成的构建系统Debug会重新生成,Release就像自动重新生成发生一样。我很确定这不是你想要的。

回答by roalz

For CXX flags specific for Release target, you should set
CMAKE_CXX_FLAGS_RELEASE
instead of
CMAKE_CXX_FLAGS

对于特定于发布目标的 CXX 标志,您应该设置
CMAKE_CXX_FLAGS_RELEASE
而不是
CMAKE_CXX_FLAGS

In your case you can use:

在您的情况下,您可以使用:

set(CMAKE_CXX_FLAGS "-Wall -Wextra")
set(CMAKE_CXX_FLAGS_DEBUG "-g")
set(CMAKE_CXX_FLAGS_RELEASE "-O3")

设置(CMAKE_CXX_FLAGS“-Wall -Wextra”)
设置(CMAKE_CXX_FLAGS_DEBUG“-g”)
设置(CMAKE_CXX_FLAGS_RELEASE“-O3”)

A more modern CMake approach (which I suggest, if you are using CMake version 2.8.12 or newer), is well described in this StackOverflow answerand involves the use of target_compile_options.

更现代的 CMake 方法(我建议,如果您使用的是 2.8.12 或更高版本的 CMake),在这个 StackOverflow 答案中有很好的描述,并且涉及到target_compile_options的使用。

回答by Mike T

The default optimization level for various release modes is O3, which often isn't the best choice. Within CMakeLists.txtfile, these can be modified to O2:

各种发布模式的默认优化级别是 O3,这通常不是最佳选择。在CMakeLists.txt文件中,这些可以修改为 O2:

# Modify compile flags to change optimization level from O3 to O2
string(REGEX REPLACE "([\/\-]O)3" "\12"
  CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
string(REGEX REPLACE "([\/\-]O)3" "\12"
  CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
string(REGEX REPLACE "([\/\-]O)3" "\12"
  CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL}")
string(REGEX REPLACE "([\/\-]O)3" "\12"
  CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")

These regular expressions will be modified (e.g.):

这些正则表达式将被修改(例如):

  • -O3to -O2usually for Linux-based compilers
  • /O3to /O2usually for Windows-based compilers
  • -O3-O2通常基于Linux编译器
  • /O3/O2通常为基于Windows的编译器