24

CMake is being used to compile some C++ files. There are assert calls in the code. These calls are disabled in Release mode of CMake. It defines NDEBUG in Release mode, I guess.

If I'm interested in having assert in Release mode of CMake, how do I enable it?

Ashwin Nanjappa
  • 76,204
  • 83
  • 211
  • 292
  • 3
    Remove this definition from `CMAKE_CXX_RELEASE_FLAGS`, obviously. – arrowd Mar 03 '14 at 11:28
  • 3
    Note that if you find yourself in need to do the checks in Release, `assert` might be the wrong tool for the job (although there are still valid use cases for your question, for instance debugging a problem that only occurs in Release). Consider introducing additional diagnostic macros that have weaker semantics than assert (which de facto specifies a condition that must _never fail_) that but can still be enabled selectively (for instance, a condition that can fail if the user passes invalid arguments to a function). – ComicSansMS Mar 04 '14 at 13:47

4 Answers4

14

See this answer in the CMake FAQ, i.e.:

Fix it manually by changing the definition of the cache variables CMAKE_C_FLAGS_RELEASE and CMAKE_CXX_FLAGS_RELEASE. This has to be done every time you set up a new build directory.

To fix it permanently, create a custom CMake rules file in your source folder with the desired settings for the release flags (omit the option /D NDEBUG). Then in your outermost CMakeLists.txt point the variable CMAKE_USER_MAKE_RULES_OVERRIDE to the custom CMake rules file.

sakra
  • 62,199
  • 16
  • 168
  • 151
  • This should be the accepted answer, as it fixes OPs problem without changing any CMake related code. – kfunk Apr 25 '19 at 12:58
13

This would be a solution for the MSVC compiler:

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

A better option may be to enable asserts not in Release mode but in RelWithDebInfo mode instead:

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

But this depends on your project and preferences of course.

letmaik
  • 3,348
  • 1
  • 36
  • 43
  • For gcc or clang, `/DNDEBUG` -> `-DNDEBUG`. To clean this up, you would have wrap it in an if statement like `if (CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU") ... endif()` – Fred Schoen Aug 18 '17 at 12:27
  • But why not just use the "Debug" build type then? Wouldn't that be equivalent? – Apteryx Jan 16 '20 at 05:10
7

1

If you interested in assert functionality only in your own code then the simple one solution is to provide custom assert. For instance:

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

Use option to enable/disable assert:

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

In this case you have full control over your checks, you can verify one component and ignore others:

... FOO_DEBUG=0 BOO_DEBUG=1 BAR_DEBUG=0 ...

2

Add custom CMAKE_BUILD_TYPE (also see CMAKE_CONFIGURATION_TYPES):

cmake_minimum_required(VERSION 2.8.12)
project(foo)

set(CMAKE_CXX_FLAGS_MYREL "-O3")

add_library(foo foo.cpp)

output:

# Debug
# ... -g ...

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

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

# MyRel
# ... -O3 ...
6

Here's how LLVM does it. They add a LLVM_ENABLE_ASSERTIONS option to the project (change LLVM to your project's prefix), then check for it and filter the compile flags. There is a special case for MSVC.

Overall, this seems more sensible to me than defining a build configuration. Enabling assertions is IMO orthogonal concern to the overall build configuration.

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

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

user7610
  • 25,267
  • 15
  • 124
  • 150
  • The foreach block should be moved outside the CMAKE_BUILD_TYPE check block. Apart from that, it works well. – Yongwei Wu Mar 26 '22 at 05:16
  • Why is that the case? – user7610 Mar 26 '22 at 10:03
  • 1
    For MSVC (default generator with msbuild), CMAKE_BUILD_TYPE is generally not specified at configure time. The configuration is chosen at make time. Putting the foreach block inside the CMAKE_BUILD_TYPE does not seem useful to me. (However, it does not harm too much, for generally people do not specified CMAKE_BUILD_TYPE, so the "NOT" condition is still satisfied generally.) – Yongwei Wu Mar 28 '22 at 14:11