How to Disable Exceptions in fmtlib: Complete Configuration Guide
Set the compile-time macro FMT_USE_EXCEPTIONS to 0 to disable C++ exceptions in fmtlib, which strips out all internal try/catch blocks and redirects error handling to fmt::assert_fail.
Disabling exceptions in {fmt} is critical for embedded systems, real-time applications, and environments compiled with -fno-exceptions. The library provides robust exception-free operation through the FMT_USE_EXCEPTIONS configuration macro, which is evaluated in include/fmt/core.h before any formatting logic is compiled.
Understanding the FMT_USE_EXCEPTIONS Macro
The {fmt} library controls exception support through the FMT_USE_EXCEPTIONS macro defined in include/fmt/core.h (lines 46–57). When this macro evaluates to 0, the library eliminates exception overhead by redefining exception handling constructs as no-ops.
// include/fmt/core.h – exception control macros (lines 46-57)
#if FMT_USE_EXCEPTIONS
# define FMT_TRY try
# define FMT_CATCH(x) catch (x)
#else
# define FMT_TRY if (true) // no try block generated
# define FMT_CATCH(x) if (false) // no catch block generated
#endif
When FMT_USE_EXCEPTIONS is 0, the library automatically translates all throw fmt::format_error statements into calls to fmt::assert_fail, which aborts the program by default. The macro is automatically detected if you compile with -fno-exceptions on GCC/Clang or with _HAS_EXCEPTIONS==0 on MSVC, but you can also override it manually.
Methods to Disable Exceptions in fmtlib
You can disable exceptions through three primary configuration methods, depending on your build system and integration approach.
CMake Configuration
When building {fmt} as a compiled library, pass the CMake option to disable exception handling at the configuration stage:
cmake -DFMT_USE_EXCEPTIONS=OFF ..
# or explicitly set to 0
cmake -DFMT_USE_EXCEPTIONS=0 ..
This definition propagates through the build system defined in CMakeLists.txt and sets the preprocessor macro consistently across all translation units.
Compiler Flags
Define the macro via compiler flags when building your project. This method works for both header-only and compiled library usage:
# GCC/Clang
g++ -std=c++20 -DFMT_USE_EXCEPTIONS=0 -I/path/to/fmt/include main.cpp -lfmt
# MSVC
cl /std:c++20 /DFMT_USE_EXCEPTIONS=0 /I\path\to\fmt\include main.cpp fmt.lib
Source-Level Macro Definition
Define FMT_USE_EXCEPTIONS before including any {fmt} headers. This approach is necessary when using header-only mode (FMT_HEADER_ONLY):
#define FMT_USE_EXCEPTIONS 0 // Must precede all fmt headers
#include <fmt/core.h>
#include <fmt/format.h>
int main() {
// Format errors now trigger assert_fail instead of throwing
fmt::print("Value: {}\n", 42);
}
According to the official documentation in doc/api.md (lines 87–89), the default value is 1 (exceptions enabled), or 0 when the compiler disables exceptions.
Error Handling Without Exceptions
When exceptions are disabled, {fmt} replaces exception-based error reporting with an assertion mechanism that offers deterministic termination and optional customization.
The assert_fail Mechanism
By default, fmt::assert_fail writes an error message to stderr and calls std::abort(). The function signature matches the standard assertion pattern:
void fmt::assert_fail(const char* msg, const char* file, int line);
Custom Assertion Handlers
For projects requiring custom error recovery (such as logging errors or returning error codes), define FMT_CUSTOM_ASSERT_FAIL before including headers and provide your own implementation:
#define FMT_USE_EXCEPTIONS 0
#define FMT_CUSTOM_ASSERT_FAIL 1
#include <fmt/core.h>
#include <iostream>
void fmt::assert_fail(const char* msg, const char* file, int line) {
std::cerr << "Format error at " << file << ":" << line
<< " - " << msg << std::endl;
// Custom handling: log, set error flag, or throw different type
std::terminate(); // Required: must not return
}
Practical Code Examples
Triggering error handling without exceptions:
#define FMT_USE_EXCEPTIONS 0
#include <fmt/format.h>
#include <iostream>
int main() {
// This valid call works normally
auto s = fmt::format("Hello, {}!", "world");
// This malformed format string triggers fmt::assert_fail
// instead of throwing fmt::format_error
fmt::format("{:d}", "not-a-number"); // Aborts or calls custom handler
}
Complete build command for exception-free static library:
# Configure and build fmt without exceptions
git clone https://github.com/fmtlib/fmt.git
cd fmt
cmake -B build -DFMT_USE_EXCEPTIONS=OFF -DFMT_DOC=OFF -DFMT_TEST=OFF
cmake --build build --config Release
Summary
- Macro control: Use
FMT_USE_EXCEPTIONSdefined ininclude/fmt/core.hto toggle exception support at compile time. - Automatic detection: {fmt} automatically sets
FMT_USE_EXCEPTIONS=0when compiled with-fno-exceptionsor_HAS_EXCEPTIONS==0. - Three configuration methods: CMake option (
-DFMT_USE_EXCEPTIONS=OFF), compiler flag (-DFMT_USE_EXCEPTIONS=0), or source-level#define. - Error redirection: Disabled exceptions route errors to
fmt::assert_fail, which can be customized viaFMT_CUSTOM_ASSERT_FAILfor project-specific error handling. - Header-only compatibility: Exception disabling works identically in
FMT_HEADER_ONLYmode.
Frequently Asked Questions
What happens when FMT_USE_EXCEPTIONS is set to 0?
All internal TRY/CATCH macros expand to no-ops, and any formatting error that would normally throw fmt::format_error instead calls fmt::assert_fail. The program aborts unless you provide a custom handler via FMT_CUSTOM_ASSERT_FAIL.
Can I use fmtlib without exceptions in header-only mode?
Yes. Define FMT_USE_EXCEPTIONS 0 before including any {fmt} headers when using FMT_HEADER_ONLY. The macro controls conditional compilation in include/fmt/core.h regardless of whether you link against the compiled library or include headers directly.
How do I handle errors gracefully when exceptions are disabled?
Implement a custom fmt::assert_fail function and define FMT_CUSTOM_ASSERT_FAIL before including headers. Your implementation can log errors to external systems, set global error flags, or invoke alternative exception types, but it must not return (typically ending with std::terminate() or std::abort()).
Does disabling exceptions improve performance?
Disabling exceptions eliminates the overhead of exception handling tables (EH tables) and stack unwinding information, which can reduce binary size and improve cache locality. However, error handling becomes fatal by default, so you should only disable exceptions if your application can tolerate termination on format errors or if you implement FMT_CUSTOM_ASSERT_FAIL to handle errors appropriately.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →