什么是CMAKE_BUILD_TYPE:Debug,Release,RelWithDebInfo和MinSizeRel?

时间:2018-02-12 20:02:09

标签: cmake

来自docs page

  

CMAKE_BUILD_TYPE

     

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

     

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

我知道Debug版本和Release版本之间存在差异,但ReleaseRelWithDebInfoMinSizeRel之间有何区别?我猜RelWithDebInfo意味着创建可调试的二进制文件,MinSizeRel意味着创建尽可能小的二进制文件。

来自LLVM CMake page

  

CMAKE_BUILD_TYPE:STRING

     

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

如果我想生成生成版本,我应该选择Release吗?

3 个答案:

答案 0 :(得分:4)

RelWithDebInfo 发布相同,允许您symbol files进行调试。

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

MinSizeRel 发布相同,例如,其优化配置在Visual Studio中设置为Minimize size, Maximize speed

  

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

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

阅读this CMAKE FAQ实际上对你有很大的帮助。

答案 1 :(得分:1)

是的,你是对的:

  

我猜测RelWithDebInfo意味着创建可调试的二进制文件,MinSizeRel意味着创建尽可能小的二进制文件。

RelWithDebInfo将添加编译器标志以生成调试信息(GCC / clang的-g标志),并将导致可调试但更大的二进制文件。

MinSizeRel将添加编译器标志以生成更紧凑的二进制文件(GCC / clang的-Os标志),可能以程序速度为代价。

  

如果我想生成生成版本,我应该选择Release吗?

是的,Release将是一个不错的选择。它应该生成更快的二进制文件,方法是指定编译器优化级别以支持速度(GCC / clang为-O3),不包括调试符号。

答案 2 :(得分:0)

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[= type ]]
  3. 是否为assert()生成代码[-DNDEBUG]
  4. 是否包含调试(输出)代码[custom]

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

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.

就通常意味着的编译器标志而言(由于在大多数情况下所有平台上都支持这些标志):

1. Release: `-O3 -DNDEBUG`
2. Debug: `-O0 -g`
3. RelWithDebInfo: `-O2 -g -DNDEBUG`
4. MinSizeRel: `-Os -DNDEBUG`

在支持此功能的平台上添加了定义NDEBUG的位置(它禁用了assert())。这就是为什么您应该确保所有断言都没有副作用的原因。

扩展构建类型

尽管添加不同工具链需要不同选项的内容通常并不是您真正想做的(尽管,编译器选项基本上是特定于编译器/语言的,所以如果您愿意,可以轻松检查compiler ID想要,然后根据需要选择您的标志。)

当您将自己限制为[-g, -O0, -O2, -O3-Os]时,以更改优化标志或调试标志的形式添加支持非常容易,从而消除了可能的{ {1}}标志和/或添加自定义宏。

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

然后,我们共有四个优化级别,即是否调试信息,是否声明代码以及是否调试代码,总共有4 * 2 * 2 * 2 = 32个配置(构建类型)。但显然并非所有配置都非常实用。最好看看配置的用例是什么。

很显然,我们拥有DEBUG构建,它是无漏洞的代码,已广泛发布;这是生产代码。您不会经常编译它,并且在执行时,比起编译它要花多长时间,结果代码要快(或小?)更为重要。这样就产生了两种现有的生产代码构建类型:

Release

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

支持
1. Release
2. MinSizeRel

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

3. RelWithDebInfo

但是-您也有beta测试人员(也许您自己是每天使用该程序作为“用户”使用的)。在这种情况下,您希望对代码进行优化,以使其速度足够快-但您也希望所有断言都处于打开状态。断言可能会告诉您问题出在哪里比以后发生的核心转储好得多。或更糟糕的是,它的行为可能很奇怪并且根本不会崩溃。您需要确保即使在生产代码中也不会断言。那就是beta测试人员的目的。让我们将此构建类型称为

4. Debug

最后,有些调试版本不是 ,无法通过调试器逐步进行,堆栈跟踪也没有帮助(因为它不是核心转储,或者问题不是导致立即崩溃)。有很多(即使不是大多数)此类错误。查找这些错误(一旦发生)的唯一方法是使用 extra 调试代码和/或将大量调试输出写入日志文件。您希望至少使用5. BetaTest [`-O3 -g`] - aka Release minus the `-DNDEBUG` but with `-g`. 编译此代码,但也要声明断言(为什么不这样),并且需要定义宏-O2。当然,我们也可能包含调试信息,因为在这里,可执行文件的大小不太重要。让我们称之为这样的构建

DEBUG

我在这里建议6. RelWithDebug [`-O2 -g -DDEBUG`] - aka RelWithDebInfo but `-DNDEBUG` removed and `-DDEBUG` added. ,因为这是您作为开发人员最常编译的内容,因为您自己永远都是这样的用户,因为如果发生意外情况,您想知道是什么原因造成的(拥有这些日志) !),并且您不想一直使用慢得多的-O2进行编译...

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

这是执行此操作的方法

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

relwithdebug