////
Copyright (c) 2024 The C++ Alliance, Inc. (https://cppalliance.org)

Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

Official repository: https://github.com/boostorg/website-v2-docs
////
= Production and Debug Builds
:navtitle: Production and Debug Builds

== FAQ


. *What is the value of using `BOOST_ASSERT` or `BOOST_STATIC_ASSERT` over the Standard Library assert macros?*
+
There are a few advantages of using the Boost asserts, available in `<boost/assert.hpp>`, including that `BOOST_ASSERT` is fully customizable using `BOOST_ENABLE_ASSERT_HANDLER`, which can be used to log extra data or stack traces, and there is better integration with boost:test[]. `BOOST_STATIC_ASSERT` is best utilized when using older pass:[C++] standards (pre-pass:[C++17]), or you are using deeply templated code. You might also prefer the Boost macros if you are engaging the features of other Boost libraries and are looking for consistent tooling. For a fuller discussion, refer to xref:boost-macros.adoc[].

. *For maximum performance, is it good practice to remove, or comment out, the `BOOST_ASSERT`s for the final production code, or do they simply not get compiled into anything so there is no performance cost for leaving them as is?*
+
By default, `BOOST_ASSERT` macros are completely removed from the compiled binary when `NDEBUG` is defined, just like the standard assert macro. If `NDEBUG` is not defined a `BOOST_ASSERT(x)` will expand, usually to an `assertion_failed()` if the assert condition fails. If NDEBUG is defined it expands to `((void)0)` so nothing is generated. Boost does provide the `BOOST_DISABLE_ASSERTS` macro, which has the same effect on Boost asserts as `NDEBUG` - but will leave other asserts alone.

. *What is usually considered to be best practices in handling assertions that fire with a production build?*
+
Instead of throwing an exception when an assert fails, it is often the best practice to log the failure. For example, here is a custom assert handler using the features of boost:log[] to record the event:
+
[source,cpp]
----
#include <boost/assert.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/utility/setup/file.hpp>
#include <boost/log/utility/setup/console.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/expressions.hpp>
#include <sstream>
#include <cstdlib>

namespace logging = boost::log;

// Configure Boost.Log (call once at startup)
void init_logging() {
    logging::add_common_attributes();

    // Console output
    logging::add_console_log(
        std::clog,
        logging::keywords::format = "[%TimeStamp%] [%Severity%] %Message%"
    );

    // File output
    logging::add_file_log(
        logging::keywords::file_name = "assert_failures_%N.log",
        logging::keywords::rotation_size = 10 * 1024 * 1024, // 10 MB
        logging::keywords::format = "[%TimeStamp%] [%Severity%] %Message%"
    );
}

// Custom handler for BOOST_ASSERT
namespace boost {
    void assertion_failed(char const* expr, char const* function, char const* file, long line) {
        std::ostringstream oss;
        oss << "BOOST_ASSERT failed!\n"
            << "  Expression: " << expr << "\n"
            << "  Function:   " << function << "\n"
            << "  File:       " << file << "\n"
            << "  Line:       " << line;

        BOOST_LOG_TRIVIAL(error) << oss.str();

        std::abort(); // Optional: comment out if soft fail is desired
    }
}

----
+
An example use of this handler would be:
+
[source,cpp]
----
#include <boost/assert.hpp>
#include <iostream>

// Declare logging initializer
void init_logging();

void test_logic(int value) {
    BOOST_ASSERT(value >= 0);
    std::cout << "Value is: " << value << std::endl;
}

int main() {
    init_logging();

    std::cout << "Testing BOOST_ASSERT with value = 42..." << std::endl;
    test_logic(42);

    std::cout << "Testing BOOST_ASSERT with value = -1..." << std::endl;
    test_logic(-1); // Logs to file and console, then aborts

    return 0;
}

----

. *What should I be aware of when moving from a Debug to a Production release?*
+
Use this checklist to ensure your application correctly integrates Boost libraries across **Debug** and **Release** configurations.
+
- *Linking and Compatibility*
- [ ] Link with the correct Boost library variant (`-gd` for Debug, none for Release).
- [ ] Ensure runtime settings (Debug CRT or Release CRT) match Boost binaries.
- [ ] Avoid mixing Debug-built Boost libraries with Release-built applications.
- *Macro Definitions and Configuration*
- [ ] Define `BOOST_DEBUG` in Debug builds to enable extra runtime checks (if applicable).
- [ ] Define `BOOST_DISABLE_ASSERTS` in Release builds to remove `BOOST_ASSERT` checks.
- [ ] Optionally define `BOOST_ENABLE_ASSERT_HANDLER` to install custom assertion handlers.
- [ ] Review conditional macros like `BOOST_NO_EXCEPTIONS`, `BOOST_NO_RTTI`, etc.
- *Assertions and Diagnostics*
- [ ] Use `BOOST_ASSERT` for critical development-time checks.
- [ ] Consider diagnostic logging using `BOOST_LOG_TRIVIAL`.
- [ ] Ensure failing assertions are tested and logged in Debug builds.
- *Debugging and Tooling*
- [ ] Run AddressSanitizer, Valgrind, or Visual Leak Detector in Debug builds. Refer to xref:contributor-guide:ROOT:testing/sanitizers.adoc[Contributor Guide: Sanitizers].
- [ ] Confirm boost:pool[], boost:container[], and alloc-heavy libraries don't leak memory.
- [ ] Validate boost:thread[], boost:asio[], and boost:fiber[] components using thread sanitizers.
- *Performance Awareness*
- [ ] Avoid benchmarking with Debug builds — optimization is disabled.
- [ ] Use Release builds to test compile times for boost:mp11[], boost:spirit[], and any heavy use of templates.
- [ ] Validate any `BOOST_FORCEINLINE` or `BOOST_NOINLINE` effects in both builds.
- *Unit Testing*
- [ ] Run the full suite of unit tests in both Debug and Release.
- [ ] Ensure no logic is only covered by Debug-only paths or assertions.
- [ ] Use boost:test[] to validate results across optimization levels.

. *Typically, how should I set up a CMake file to handle Debug and Release builds?*
+
Here's an example of how to set up your `CMakeLists.txt` to handle `BOOST_ASSERT` correctly by toggling behavior based on the build type (Debug or Release). The example includes linking with some sample libraries (boost:log[], boost:system[] and boost:thread[]):
+
[source,cmake]
----
cmake_minimum_required(VERSION 3.10)
project(MyBoostApp)

# Set your C++ standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# Enable debug symbols for Debug mode
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g")

# Link Boost (adjust components as needed)
find_package(Boost REQUIRED COMPONENTS log log_setup system thread)

target_link_libraries(MyBoostApp PRIVATE
    Boost::log
    Boost::log_setup
    Boost::system
    Boost::thread
)

add_executable(MyBoostApp main.cpp)

target_include_directories(MyBoostApp PRIVATE ${Boost_INCLUDE_DIRS})
target_link_libraries(MyBoostApp PRIVATE ${Boost_LIBRARIES})

# Enable BOOST_ASSERT in Debug, disable in Release
target_compile_definitions(MyBoostApp PRIVATE
    $<$<CONFIG:Debug>:BOOST_ENABLE_ASSERT_HANDLER>
    $<$<CONFIG:Release>:NDEBUG>
)

# Optional: You can define a custom assert handler in debug builds
# by linking a file like the assert handler shown above that defines `boost::assertion_failed`

----




== See Also

* xref:faq.adoc[]

