FMT_VERSION Macro: How to Detect the fmtlib Version at Compile Time
The FMT_VERSION macro is a preprocessor constant defined in include/fmt/base.h that encodes the fmt library version as a single integer using the formula major×10000 + minor×100 + patch, enabling compile-time version checks and conditional compilation paths.
The fmt library provides a standardized mechanism to query its version directly from source code. This eliminates guesswork when writing portable applications that must support multiple fmt releases. This guide explains the macro's encoding scheme, demonstrates how to extract version components, and shows integration with CMake and pkg-config.
Understanding the FMT_VERSION Macro Encoding
The FMT_VERSION macro packs semantic version components into a single comparable integer value defined in the fmt source headers.
Macro Definition and Location
According to the fmtlib/fmt source code, the macro is defined in include/fmt/base.h at line 24:
#define FMT_VERSION 120201 // major·10000 + minor·100 + patch
This definition is the single source of truth for the library's version number. The CMake build system extracts this value using a regex in CMakeLists.txt (lines 112-119) to populate the FMT_VERSION CMake variable, ensuring consistency between build-time and compile-time version detection.
Version Encoding Formula
The integer follows the pattern major × 10000 + minor × 100 + patch. For example, the value 120201 represents version 12.2.1:
- Major: 12 (
120201 / 10000) - Minor: 2 (
(120201 / 100) % 100) - Patch: 1 (
120201 % 100)
This encoding allows for simple integer comparisons to check version requirements.
Compile-Time Version Detection in C++
You can query the fmt version directly in your source code to enable or disable features based on the available API.
Basic Version Checks
To conditionally compile code based on the fmt version, include fmt/base.h and compare against the encoded integer:
#include <fmt/base.h>
#if FMT_VERSION >= 120200 // Require at least 12.2.0
// Use API features introduced in fmt 12.2.0
auto formatted = fmt::format(std::runtime_format("{}"), value);
#else
// Fallback implementation for older versions
#endif
Extracting Individual Components
For logging or validation purposes, you can extract the major, minor, and patch versions using integer arithmetic:
#include <fmt/base.h>
constexpr int fmt_major = FMT_VERSION / 10000;
constexpr int fmt_minor = (FMT_VERSION / 100) % 100;
constexpr int fmt_patch = FMT_VERSION % 100;
static_assert(fmt_major >= 12, "fmt version 12 or higher required");
Build System Integration
Beyond compile-time checks, fmt exposes its version through standard build system interfaces for dependency management.
CMake Detection
When using CMake, the find_package command reads the macro from include/fmt/base.h and sets the fmt_VERSION variable as a dotted string:
find_package(fmt REQUIRED)
message(STATUS "Using fmt ${fmt_VERSION}") # Outputs: Using fmt 12.2.1
add_executable(myapp main.cpp)
target_link_libraries(myapp PRIVATE fmt::fmt)
The extraction logic is implemented in the library's CMakeLists.txt at lines 112-119, where a regex parses the macro definition from the header file.
pkg-config Support
For systems using pkg-config, the version is embedded in the generated fmt.pc file, which is produced from the template support/cmake/fmt.pc.in at line 8:
pkg-config --modversion fmt # Outputs: 12.2.1
A similar template exists at support/cmake/fmt-c.pc.in for the C API bindings.
Complete Working Example
Here is a comprehensive example demonstrating runtime version formatting, compile-time conditional logic, and static assertions:
#include <fmt/core.h>
#include <fmt/base.h>
#include <iostream>
int main() {
// Deconstruct version for display
constexpr int major = FMT_VERSION / 10000;
constexpr int minor = (FMT_VERSION / 100) % 100;
constexpr int patch = FMT_VERSION % 100;
std::cout << "fmt version: " << major << '.' << minor << '.' << patch << '\n';
std::cout << "Raw FMT_VERSION: " << FMT_VERSION << '\n';
#if FMT_VERSION >= 120200
fmt::print("Compiled with fmt 12.2.0 or later - modern API available\n");
#else
std::cerr << "Warning: fmt version is older than 12.2.0\n";
#endif
// Compile-time verification
static_assert(FMT_VERSION >= 120000, "fmt version 12.x required");
}
Summary
FMT_VERSIONis defined ininclude/fmt/base.has a single integer encoding the library version usingmajor×10000 + minor×100 + patch- Compile-time detection allows feature gating with
#if FMT_VERSION >= 120200or extraction of components via division and modulo operations - CMake integration provides the
fmt_VERSIONvariable (e.g., "12.2.1") extracted from the header via regex in the repository'sCMakeLists.txt - pkg-config support exposes the version string through
--modversionusing templatessupport/cmake/fmt.pc.inandfmt-c.pc.in - Portability is maintained across all platforms since detection relies solely on preprocessor macros available in the standard header layout
Frequently Asked Questions
What header file defines the FMT_VERSION macro?
The FMT_VERSION macro is defined in include/fmt/base.h at line 24. While other headers like fmt/core.h include this definition transitively, including fmt/base.h directly ensures you can check the version before including heavy formatting headers.
How do I check if the installed fmt version is at least 12.2.0?
Use a preprocessor directive comparing against the encoded integer: #if FMT_VERSION >= 120200. This works because 12×10000 + 2×100 + 0 equals 120200, making integer comparisons semantically equivalent to version tuple comparisons.
Can I get the version string at runtime?
Yes, but you must construct it yourself from the macro components. There is no pre-built string constant; calculate the major, minor, and patch values using integer division and modulo, then format them using fmt::format("{}.{}.{}", major, minor, patch) or standard streams.
Why does CMake set fmt_VERSION but the C++ macro is named FMT_VERSION?
The CMake variable fmt_VERSION (lowercase) contains a human-readable dotted string like "12.2.1" extracted by the build system's regex parser in CMakeLists.txt, while the C++ macro FMT_VERSION (uppercase) is the raw integer encoding (120201) defined in the header. Both derive from the same source line in include/fmt/base.h but serve different consumption patterns.
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 →