如何在CMake发布模式下启用断言? CGUP用于编译一些C++文件。代码中有assert调用。这些调用在CMake的释放模式下被禁用。我想它在发布模式下定义了NDEBUG
如果我对在CMake的发布模式下使用assert感兴趣,我如何启用它?请参见CMake常见问题解答,即: 通过更改缓存变量如何在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\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()