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_VERSION is defined in include/fmt/base.h as a single integer encoding the library version using major×10000 + minor×100 + patch
  • Compile-time detection allows feature gating with #if FMT_VERSION >= 120200 or extraction of components via division and modulo operations
  • CMake integration provides the fmt_VERSION variable (e.g., "12.2.1") extracted from the header via regex in the repository's CMakeLists.txt
  • pkg-config support exposes the version string through --modversion using templates support/cmake/fmt.pc.in and fmt-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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →