如何在CMake发布模式下启用断言? CGUP用于编译一些C++文件。代码中有assert调用。这些调用在CMake的释放模式下被禁用。我想它在发布模式下定义了NDEBUG

如何在CMake发布模式下启用断言? CGUP用于编译一些C++文件。代码中有assert调用。这些调用在CMake的释放模式下被禁用。我想它在发布模式下定义了NDEBUG,cmake,assert,ndebug,Cmake,Assert,Ndebug,如果我对在CMake的发布模式下使用assert感兴趣,我如何启用它?请参见CMake常见问题解答,即: 通过更改缓存变量CMAKE\u C\u FLAGS\u RELEASE和CMAKE\u CXX\u FLAGS\u RELEASE的定义手动修复它。每次设置新的生成目录时都必须执行此操作 要永久修复此问题,请在源文件夹中创建一个自定义CMake规则文件,其中包含发布标志的所需设置(省略选项/D NDEBUG)。然后在最外层的CMakeLists.txt中,将变量CMAKE\u USER\u

如果我对在CMake的发布模式下使用assert感兴趣,我如何启用它?

请参见CMake常见问题解答,即:

通过更改缓存变量
CMAKE\u C\u FLAGS\u RELEASE
CMAKE\u CXX\u FLAGS\u RELEASE
的定义手动修复它。每次设置新的生成目录时都必须执行此操作

要永久修复此问题,请在源文件夹中创建一个自定义CMake规则文件,其中包含发布标志的所需设置(省略选项
/D NDEBUG
)。然后在最外层的CMakeLists.txt中,将变量
CMAKE\u USER\u MAKE\u RULES\u OVERRIDE
指向自定义CMAKE规则文件。

1 如果您只对自己代码中的
assert
功能感兴趣,那么简单的解决方案 是提供自定义断言。例如:

#if (MY_DEBUG)
# define MY_ASSERT(A) ... checks here ...
#else
# define MY_ASSERT(A) ... ignore A ...
#endif
使用
选项
启用/禁用断言:

# CMakeLists.txt
option(ENABLE_MY_ASSERT "Turn on MY_ASSERT checks" OFF)
if(ENABLE_MY_ASSERT)
  add_definitions(-DMY_DEBUG=1)
else()
  add_definitions(-DMY_DEBUG=0)
endif()
在这种情况下,您可以完全控制您的支票,您可以验证一个 组件和忽略其他组件:

... FOO_DEBUG=0 BOO_DEBUG=1 BAR_DEBUG=0 ...
2. 添加自定义(另请参见):

输出:

# Debug
# ... -g ...

# Release
# ... -O3 -DNDEBUG ...

# RelWithDebInfo
# ... -O2 -g -DNDEBUG ...

# MyRel
# ... -O3 ...

这将是MSVC编译器的解决方案:

string( REPLACE "/DNDEBUG" "" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
更好的选择可能不是在发布模式下而是在RelWithDeInfo模式下启用断言:

string( REPLACE "/DNDEBUG" "" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")

当然,这取决于您的项目和偏好。

以下是LLVM的工作方式。他们向项目添加
LLVM\u ENABLE\u断言
选项(将
LLVM
更改为项目的前缀),然后检查它并过滤编译标志。MSVC有一个特例

总的来说,这似乎比定义构建配置更合理。启用断言与整个构建配置密切相关

# This is commonly needed so define it before we include anything else.
string(TOUPPER "${CMAKE_BUILD_TYPE}" uppercase_CMAKE_BUILD_TYPE)

[...]

if(uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG" )
    option(QD_ENABLE_ASSERTIONS "Enable assertions" ON)
else()
    option(QD_ENABLE_ASSERTIONS "Enable assertions" OFF)
endif()

[...]

if(QD_ENABLE_ASSERTIONS)
    if(NOT MSVC)
        add_definitions(-D_DEBUG)
    endif()
    # On non-Debug builds cmake automatically defines NDEBUG, so we explicitly undefine it:
    if(NOT uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG")
        # NOTE: use `add_compile_options` rather than `add_definitions` since
        # `add_definitions` does not support generator expressions.
        add_compile_options($<$<OR:$<COMPILE_LANGUAGE:C>,$<COMPILE_LANGUAGE:CXX>>:-UNDEBUG>)

        # Also remove /D NDEBUG to avoid MSVC warnings about conflicting defines.
        foreach (flags_var_to_scrub
                CMAKE_CXX_FLAGS_RELEASE
                CMAKE_CXX_FLAGS_RELWITHDEBINFO
                CMAKE_CXX_FLAGS_MINSIZEREL
                CMAKE_C_FLAGS_RELEASE
                CMAKE_C_FLAGS_RELWITHDEBINFO
                CMAKE_C_FLAGS_MINSIZEREL)
            string (REGEX REPLACE "(^| )[/-]D *NDEBUG($| )" " "
                    "${flags_var_to_scrub}" "${${flags_var_to_scrub}}")
        endforeach()
    endif()
endif()
#这是通常需要的,所以在包含任何其他内容之前先定义它。
字符串(大写“${CMAKE\u BUILD\u TYPE}”为“${CMAKE\u BUILD\u TYPE”)
[...]
if(大写字母\u CMAKE\u BUILD\u TYPE STREQUAL“DEBUG”)
选项(QD_启用_断言“启用断言”打开)
else()
选项(QD_启用_断言“启用断言”关闭)
endif()
[...]
if(QD_启用_断言)
if(非MSVC)
添加\u定义(-D\u调试)
endif()
#在非调试版本上,cmake自动定义NDEBUG,因此我们显式取消定义:
if(不是大写字母\u CMAKE\u BUILD\u TYPE STREQUAL“DEBUG”)
#注意:使用'add_compile_options'而不是'add_definitions',因为
#'add_definitions'不支持生成器表达式。
添加编译选项($)
#同时删除/D NDEBUG以避免MSVC对冲突定义的警告。
foreach(标志从“变量”到“擦洗”)
CMAKE\U CXX\U标志\U发布
CMAKE_CXX_FLAGS_RELWITHDEBINFO
CMAKE_CXX_FLAGS_MINSIZEREL
CMAKE_C_标志发布
CMAKE_C_FLAGS_RELWITHDEBINFO
克梅克(意大利)
字符串(正则表达式替换“(^ |)[/-]D*NDEBUG($|)”“
“${flags\u var\u to_scrub}”“${{flags\u var\u to_scrub}”)
endforeach()
endif()
endif()

来源:

显然,从
CMAKE\u CXX\u RELEASE\u FLAGS
中删除此定义。请注意,如果您发现自己需要在RELEASE中执行检查,
assert
可能是错误的作业工具(尽管您的问题仍然存在有效的用例,例如调试仅在RELEASE中出现的问题)。考虑引入比AsReScript(实际上事实上指定一个必须决不失败的条件)更弱语义的附加诊断宏,但仍然可以选择性地启用(例如,如果用户将无效参数传递给函数,则可能会失败的条件)。
/DNDEBUG
->
-DNDEBUG
。为了解决这个问题,您需要将它封装在一个if语句中,比如
if(CMAKE_CXX_COMPILER_ID匹配“Clang|GNU”)。。。endif()
但是为什么不使用“Debug”构建类型呢?这不是等价的吗?这应该是公认的答案,因为它修复了OPs问题,而不改变任何与CMake相关的代码。
# This is commonly needed so define it before we include anything else.
string(TOUPPER "${CMAKE_BUILD_TYPE}" uppercase_CMAKE_BUILD_TYPE)

[...]

if(uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG" )
    option(QD_ENABLE_ASSERTIONS "Enable assertions" ON)
else()
    option(QD_ENABLE_ASSERTIONS "Enable assertions" OFF)
endif()

[...]

if(QD_ENABLE_ASSERTIONS)
    if(NOT MSVC)
        add_definitions(-D_DEBUG)
    endif()
    # On non-Debug builds cmake automatically defines NDEBUG, so we explicitly undefine it:
    if(NOT uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG")
        # NOTE: use `add_compile_options` rather than `add_definitions` since
        # `add_definitions` does not support generator expressions.
        add_compile_options($<$<OR:$<COMPILE_LANGUAGE:C>,$<COMPILE_LANGUAGE:CXX>>:-UNDEBUG>)

        # Also remove /D NDEBUG to avoid MSVC warnings about conflicting defines.
        foreach (flags_var_to_scrub
                CMAKE_CXX_FLAGS_RELEASE
                CMAKE_CXX_FLAGS_RELWITHDEBINFO
                CMAKE_CXX_FLAGS_MINSIZEREL
                CMAKE_C_FLAGS_RELEASE
                CMAKE_C_FLAGS_RELWITHDEBINFO
                CMAKE_C_FLAGS_MINSIZEREL)
            string (REGEX REPLACE "(^| )[/-]D *NDEBUG($| )" " "
                    "${flags_var_to_scrub}" "${${flags_var_to_scrub}}")
        endforeach()
    endif()
endif()