【问题标题】:How to enable assert in CMake Release mode?如何在 CMake 发布模式下启用断言?
【发布时间】:2014-03-03 06:56:38
【问题描述】:

CMake 被用于编译一些 C++ 文件。代码中有assert 调用。这些调用在 CMake 的发布模式下被禁用。我猜它在发布模式下定义了NDEBUG

如果我有兴趣在 CMake 的 Release 模式下使用断言,我该如何启用它?

【问题讨论】:

  • 显然从CMAKE_CXX_RELEASE_FLAGS 中删除这个定义。
  • 请注意,如果您发现自己需要在 Release 中进行检查,assert 可能是该工作的错误工具(尽管您的问题仍有有效的用例,例如调试仅在 Release 中出现的问题)。考虑引入额外的诊断宏,这些宏的语义比 assert 弱(实际上指定了一个必须永不失败的条件),但仍然可以有选择地启用(例如,如果用户通过了可能会失败的条件)函数的参数无效)。

标签: cmake assert ndebug


【解决方案1】:

请参阅 CMake 常见问题解答中的 this answer,即:

通过更改缓存变量CMAKE_C_FLAGS_RELEASECMAKE_CXX_FLAGS_RELEASE 的定义来手动修复它。每次设置新的构建目录时都必须这样做。

要永久修复它,请在您的源文件夹中创建一个自定义 CMake 规则文件,其中包含所需的发布标志设置(省略选项 /D NDEBUG)。然后在最外面的 CMakeLists.txt 中将变量 CMAKE_USER_MAKE_RULES_OVERRIDE 指向自定义 CMake 规则文件。

【讨论】:

  • 这应该是公认的答案,因为它可以在不更改任何 CMake 相关代码的情况下解决 OP 问题。
【解决方案2】:

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

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

一个更好的选择可能不是在 Release 模式下而是在 RelWithDebInfo 模式下启用断言:

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

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

【讨论】:

  • 对于 gcc 或 clang,/DNDEBUG -> -DNDEBUG。要清理它,您可以将其包装在一个 if 语句中,例如 if (CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU") ... endif()
  • 但是为什么不直接使用“Debug”构建类型呢?那不是等价的吗?
【解决方案3】:

1

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

#if (MY_DEBUG)
# define MY_ASSERT(A) ... checks here ...
#else
# define MY_ASSERT(A) ... ignore A ...
#endif

使用option 启用/禁用断言:

# 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

添加自定义CMAKE_BUILD_TYPE(另见CMAKE_CONFIGURATION_TYPES):

cmake_minimum_required(VERSION 2.8.12)
project(foo)

set(CMAKE_CXX_FLAGS_MYREL "-O3")

add_library(foo foo.cpp)

输出:

# Debug
# ... -g ...

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

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

# MyRel
# ... -O3 ...

【讨论】:

    【解决方案4】:

    以下是 LLVM 的工作方式。他们为项目添加了LLVM_ENABLE_ASSERTIONS 选项(将LLVM 更改为项目的前缀),然后检查它并过滤编译标志。 MSVC 有一个特殊情况。

    总的来说,这对我来说似乎比定义构建配置更明智。启用断言是 IMO 对整体构建配置的正交关注。

    # 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()
    

    来源:https://opensource.apple.com/source/llvmCore/llvmCore-2358.3/CMakeLists.txt.auto.html

    【讨论】:

      猜你喜欢
      • 2020-04-19
      • 1970-01-01
      • 2012-01-27
      • 1970-01-01
      • 1970-01-01
      • 2011-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多