什么是CMAKE_BUILD_TYPE:调试,发布,RelWithDebInfo和MinSizeRel?

MiP*_*MiP 7 cmake

文档页面

CMAKE_BUILD_TYPE

指定单配置生成器上的构建类型。

这静态指定将在此构建树中构建哪种构建类型(配置)。可能的值是空的,DebugReleaseRelWithDebInfoMinSizeRel。此变量仅对单配置生成器(例如Makefile GeneratorsNinja)有意义,即那些在CMake运行以生成生成树时选择单个配置的生成器,而与多配置生成器不同,后者在生成的生成环境中提供对构建配置的选择。有许多按配置的属性和变量(通常遵循SOME_VAR_<CONFIG>无序顺序约定),例如CMAKE_C_FLAGS_<CONFIG>,指定为大写:CMAKE_C_FLAGS_[DEBUG|RELEASE|RELWITHDEBINFO|MINSIZEREL]。例如,在配置为build type的构建树中Debug,CMake将看到CMAKE_C_FLAGS_DEBUG已将设置添加到CMAKE_C_FLAGS设置。另请参阅CMAKE_CONFIGURATION_TYPES

我知道之间的差异Debug构建和Release建立,但什么是之间的差异ReleaseRelWithDebInfo以及MinSizeRel?我猜的RelWithDebInfo意思是创建可调试的二进制文件,并MinSizeRel意味着创建可能的最小大小的二进制文件。

LLVM CMake页面

CMAKE_BUILD_TYPE:STRING

如果使用的是Visual Studio之类的IDE,则应使用IDE设置来设置构建类型。请注意,Release和RelWithDebInfo在大多数平台上使用不同的优化级别。

如果要生成生产版本,应该选择Release吗?

Car*_*ood 43

重要提示CMAKE_BUILD_TYPE仅对单目标生成器有意义,例如 Makefile。它不用于多目标生成器,因为它们只是生成一个能够构建所有构建类型(调试、发布等)的构建系统。

CMAKE_BUILD_TYPE 是关于,

  1. 优化(级别) [ -O0, -O1, -O2, -O3, -Ofast, -Os, -Oz, -Og, -O, -O4]
  2. 在可执行文件中包含“调试信息”[-g, -gline-tables-only, -gmodules, -g级别, -gcoff, -gdwarf, -gdwarf-版本, -ggdb, -grecord-gcc-switches, -gno-record-gcc-switches, -gstabs, -gstabs+, -gstrict-dwarf, -gno-strict-dwarf, -gcolumn-info, -gno-column-info, -gvms, -gxcoff, -gxcoff+, -gz[=类型]]
  3. 是否为assert()[ -DNDEBUG]生成代码
  4. 是否包括调试(输出)代码[自定义]

大多数此类编译器选项都是特定于编译器和/或平台的。因此,对构建类型的扩展支持需要更新您想要支持的每个现有工具链。

cmake 附带的默认构建类型或多或少意味着以下内容,

1. Release: high optimization level, no debug info, code or asserts.
2. Debug: No optimization, asserts enabled, [custom debug (output) code enabled],
   debug info included in executable (so you can step through the code with a
   debugger and have address to source-file:line-number translation).
3. RelWithDebInfo: optimized, *with* debug info, but no debug (output) code or asserts.
4. MinSizeRel: same as Release but optimizing for size rather than speed.
Run Code Online (Sandbox Code Playgroud)

就通常意味着的编译器标志而言(因为无论如何,在大多数情况下,所有平台都支持这些标志):

1. Release: `-O3 -DNDEBUG`
2. Debug: `-O0 -g`
3. RelWithDebInfo: `-O2 -g -DNDEBUG`
4. MinSizeRel: `-Os -DNDEBUG`
Run Code Online (Sandbox Code Playgroud)

NDEBUG支持此功能的平台上添加定义的位置(禁用assert())。这就是为什么你应该确保你的断言没有副作用,当然。

扩展构建类型

虽然为不同的工具链添加需要不同选项的东西通常不是你真正想要做的事情(尽管编译器选项基本上是编译器/语言特定的,所以如果你愿意,你可以很容易地检查编译器 ID,然后选择你的标志视情况而定)。

比较容易的改变优化标志或调试标志的形式添加支持,当你限制自己[-g, -O0, -O2, -O3-Os],去除可能的-DNDEBUG标志和/或添加自定义宏。

假设我们有一个DEBUG要定义的宏以包含特定的调试代码(例如可能包括编写调试输出)。

然后我们有四个优化级别,是否调试信息,是否断言代码和是否调试代码,总共 4 * 2 * 2 * 2 = 32 个配置(构建类型)。但显然并非所有配置都非常实用。这最好看的使用情况是什么样的配置。

很明显,我们有Release构建,它是大量发布的无错误代码;它是生产代码。你不会经常编译它,当你这样做时,结果代码要快(或小?)比编译它需要多长时间更重要。这导致了生产代码的两种现有构建类型:

1. Release
2. MinSizeRel
Run Code Online (Sandbox Code Playgroud)

但后来发现生产代码中毕竟存在一个导致应用程序崩溃的错误。你无法复制它,它只会偶尔发生。您为您的用户实施了一种反馈机制来向您发送核心转储,但仅提供信息还不够。您想获得堆栈跟踪,希望它能告诉您更多信息。您要求某些用户(或者您自己,每天以“用户”身份使用它)下载一个可以正常使用的特殊版本(它足够快,经过优化)但它包含调试信息,因此需要更长的时间去下载。这些用户并不介意:他们希望修复此崩溃。这是支持的

3. RelWithDebInfo
Run Code Online (Sandbox Code Playgroud)

当然,您作为开发人员需要一个可以使用调试器逐步完成的版本。它不必很快 - 您已经知道如何重现不依赖于优化的错误(这是一个逻辑错误,是您代码中的问题 - 不是 Heisenbug)。为此,您使用,

4. Debug
Run Code Online (Sandbox Code Playgroud)

但是 - 您也有 beta 测试人员(也许您自己每天都以“用户”身份使用该程序)。在这种情况下,您希望优化代码,因此它足够快 - 但您还希望打开所有断言;断言可能会告诉您问题在哪里比稍后发生的核心转储更好。或者更糟的是,它可能只是表现得很奇怪而根本不会崩溃。您需要确保您的任何断言都不会触发,即使在生产代码中也是如此。这就是 Beta 测试人员的用途。让我们称之为构建类型,

5. BetaTest [`-O3 -g`] - aka Release minus the `-DNDEBUG` but with `-g`.
Run Code Online (Sandbox Code Playgroud)

最后,还有一些不需要调试器逐步完成的调试版本;有些错误根本无法重现,堆栈跟踪也没有帮助(因为它不会进行核心转储,或者问题不会导致立即崩溃)。有很多,如果不是大多数,这样的错误。找到这些错误(一旦发生)的唯一方法是使用额外的调试代码和/或将大量调试输出写入日志文件。您希望-O2至少使用此代码进行编译,但您也希望断言(为什么不),并且需要DEBUG定义宏。当然,我们也可以包含调试信息,因为可执行文件的大小在这里不太重要。让我们调用这样的构建

6. RelWithDebug [`-O2 -g -DDEBUG`] - aka RelWithDebInfo but `-DNDEBUG` removed and `-DDEBUG` added.
Run Code Online (Sandbox Code Playgroud)

-O2在这里建议是因为这是您作为开发人员编译最多的内容,因为您自己将永远是这样的用户,因为如果发生意外情况,您想知道是什么原因造成的(有那些日志!)想一直用慢得多的速度编译-O3...

为了支持这两种额外的构建类型,我们需要能够做两件事:获取现有构建类型的标志(更改它们)并将这些标志用于新的(自定义)构建类型。

这是如何做到这一点

如果将以下四行添加到项目根CMakeLists.txt文件顶部的某处,则使用-DCMAKE_BUILD_TYPE=BetaTest(或RelWithDebug), 将使用上述标志。当然,如果.cmake文件中的其他内容取决于构建类型,则可能需要进行更多更改。这是我个人使用的一个示例:CW_OPTIONS.cmake(看,不区分大小写betatestrelwithdebug加上根据这两个值设置的变量)。

string(REGEX REPLACE "( -DNDEBUG$|-DNDEBUG )" "" CMAKE_CXX_FLAGS_BETATEST "${CMAKE_CXX_FLAGS_RELEASE}" ) 
string(REGEX REPLACE "( -DNDEBUG$|-DNDEBUG )" "" CMAKE_C_FLAGS_BETATEST "${CMAKE_C_FLAGS_RELEASE}" )    
string(REGEX REPLACE "-DNDEBUG " "" CMAKE_CXX_FLAGS_RELWITHDEBUG "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -DDEBUG" )
string(REGEX REPLACE "-DNDEBUG " "" CMAKE_C_FLAGS_RELWITHDEBUG "${CMAKE_C_FLAGS_RELWITHDEBINFO} -DDEBUG" )
Run Code Online (Sandbox Code Playgroud)

  • 不客气。目前我写下这样的答案,我只是做了很多研究,因为我自己需要它,我只是在完成研究后花额外的时间将我的知识添加到匹配的问题中。那时,一切对我来说都显得一清二楚,因为我对材料的了解很深。但是当我一年后读回我的答案时,我常常感觉它根本不那么清楚!:(。所以,很高兴听到它对您来说是一个很好的信息来源。 (7认同)
  • 这是一个很好的答案,但我很好奇 cmake 文档中的哪里列出了这些默认值。我一直在寻找,但终其一生都找不到他们。所有文档提到的是构建选项的存在,而不是它们的作用或它们设置的标志。 (2认同)

Dea*_*Seo 6

RelWithDebInfoRelease相同,允许您具有用于调试的符号文件

例如,在Visual Studio中,您将拥有.pdb文件,而没有文件,将很难调试,因为二进制文件中的所有签名都不会被人类读取,并且无法将它们映射到源代码。

MinSizeRelRelease相同,例如,其优化配置仅设置为“ 最小化大小”,​​“最大化 Visual Studio中的速度”

如果要生成生产版本,应该选择发布吗?

是的,那应该为您做正确的工作。调试/发布是最常用的选项。

阅读此CMAKE常见问题解答实际上会对您有很大帮助。

  • 注意,在大多数编译器上,由RelWithDebInfo生成的代码的效率不应低于由Release生成的代码,但是您仍然会获得调试符号。如果您打算向用户发布二进制文件,这将是一个“巨大的胜利”,您需要稍后对其进行调试。因此,除非您有很好的理由不使用它,否则我会认为“ RelWithDebInfo”通常比“发布”更好。 (3认同)
  • 默认优化级别会更改。至少对于gcc和clang,`RelWithDebInfo`使用`-O2`,但是`Release`使用`-O3`。 (3认同)

Cir*_*四事件 6

您还可以通过以下方式获得构建类型的概述:

cmake -LAH .. | grep -C1 CMAKE_CXX_FLAGS
Run Code Online (Sandbox Code Playgroud)

如以下所述:如何列出所有 CMake 构建选项及其默认值?列出所有内置变量并给出:

// Flags used by the CXX compiler during all build types.
CMAKE_CXX_FLAGS:STRING=

// Flags used by the CXX compiler during DEBUG builds.
CMAKE_CXX_FLAGS_DEBUG:STRING=-g

// Flags used by the CXX compiler during MINSIZEREL builds.
CMAKE_CXX_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG

// Flags used by the CXX compiler during RELEASE builds.
CMAKE_CXX_FLAGS_RELEASE:STRING=-O3 -DNDEBUG

// Flags used by the CXX compiler during RELWITHDEBINFO builds.
CMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG
Run Code Online (Sandbox Code Playgroud)

对于那些熟悉相应 GCC 选项的人来说,每种构建类型的含义应该很清楚。

默认情况下,如果-DMAKE_BUILD_TYPE不传递,则为空,并且不添加CMAKE_BUILD_TYPE任何额外值。CMAKE_CXX_FLAGS_XXX

在 Ubuntu 22.10、CMake 3.24.2 上测试。