How to Enable FMT_OS for Platform-Specific APIs and File I/O in {fmt}

Enable FMT_OS by setting the CMake option -DFMT_OS=ON (enabled by default) or defining the FMT_OS macro to 1 before including fmt/os.h to access RAII file wrappers and system error utilities.

The {fmt} library provides optional operating system helpers—file I/O abstractions, formatted system_error exceptions, and portable system call wrappers—controlled by the FMT_OS feature flag. Enabling this feature compiles platform-specific code paths in include/fmt/os.h and links implementations from src/os.cc, giving you safe file handling and error reporting across POSIX and Windows systems.

Configuring FMT_OS with CMake

The build system controls FMT_OS through a top-level CMake option.

Default Configuration

According to the source in CMakeLists.txt (line 86), the option is declared as:

option(FMT_OS "Include OS-specific APIs." ON)

By default, FMT_OS is enabled, meaning OS-specific APIs are compiled into the library. When you build {fmt} without customization, you automatically receive fmt::buffered_file, fmt::system_error, and related utilities.

Explicit Enable or Disable

To explicitly enable the feature (or re-enable after a previous disable), pass the definition to CMake:

cmake -DFMT_OS=ON ..

# or

cmake -DFMT_OS=1 ..

To disable the OS layer entirely—for header-only deployments or embedded systems where file I/O is unavailable—use:

cmake -DFMT_OS=OFF ..

Disabling FMT_OS excludes src/os.cc from compilation and hides all OS-specific declarations from fmt/os.h, producing a smaller binary footprint.

Understanding the FMT_OS Macro

Beyond CMake, the feature is guarded by a C++ preprocessor macro that controls conditional compilation.

Macro Definition

In src/fmt.cc (line 127), the library defines the default state:

#ifndef FMT_OS

#  define FMT_OS 1

#endif

If you consume {fmt} as a header-only library without the CMake build system, define this macro yourself before including headers:

#define FMT_OS 1
#include <fmt/os.h>

Conditional Compilation

The header include/fmt/os.h wraps platform-specific declarations with preprocessor guards:

#if FMT_OS
// OS-specific declarations are compiled
#endif

When FMT_OS evaluates to a non-zero value, symbols like fmt::buffered_file, fmt::file, and fmt::system_error are available. When defined as 0 or undefined, these classes are omitted, but the header still includes successfully due to guard macros.

Platform-Specific APIs Available

Enabling FMT_OS unlocks three major categories of functionality implemented in include/fmt/os.h.

File I/O Wrappers

The library provides RAII-style file management classes:

  • fmt::buffered_file (lines 64-100): Wraps std::FILE* with automatic close, EINTR retry logic, and platform-specific path handling
  • fmt::file: Low-level file descriptor wrapper with portable open/close semantics

These classes ensure resources are released automatically and integrate with fmt::print for direct formatting to file streams.

Error Handling Utilities

FMT_OS enables formatted exception types for system errors:

  • fmt::system_error (lines 115-158): Exception class that formats errno or system error codes with custom messages
  • fmt::windows_error: Windows-specific variant for GetLastError() codes
  • fmt::report_system_error: Non-throwing error reporting function

The header also provides helper macros: FMT_POSIX(call), FMT_SYSTEM(call), and FMT_RETRY, which wrap system calls for testability and automatic retry on interrupt.

Practical Usage Examples

The following examples compile only when FMT_OS is enabled.

Writing to Buffered Files

Use fmt::buffered_file for automatic resource management and direct formatting:

#include <fmt/os.h>
#include <fmt/format.h>
#include <chrono>

int main() {
    // Opens "log.txt" in append mode; destructor closes automatically
    fmt::buffered_file f("log.txt", "a");
    
    fmt::print(f, "Timestamp: {}\n", 
               fmt::format("{}", std::chrono::system_clock::now()));
    // Explicit flush optional; destructor handles cleanup
}

Throwing System Errors

Report file system failures with formatted error messages:

#include <fmt/os.h>
#include <cerrno>
#include <cstdio>

void open_or_fail(const char* name) {
    std::FILE* f = std::fopen(name, "r");
    if (!f) {
        // Throws exception combining errno and formatted message
        throw fmt::system_error(errno, "cannot open file '{}'", name);
    }
    std::fclose(f);
}

Windows-Specific Error Reporting

For Windows applications, report errors without throwing exceptions:

#ifdef _WIN32
#include <fmt/os.h>
#include <windows.h>

void create_process_or_report() {
    // ... process creation logic ...
    DWORD err = GetLastError();
    if (err != ERROR_SUCCESS) {
        fmt::report_windows_error(err, "failed to create process");
    }
}
#endif

Verifying the Build

After configuring with -DFMT_OS=ON, compile the library and verify symbol availability:

  1. Build the project with cmake --build . (or make, ninja)
  2. Confirm fmt::buffered_file appears in the static/shared library using nm (Linux) or dumpbin (Windows)
  3. Run the unit tests in test/module-test.cc and test/os.cc to validate file I/O and error handling on your target platform

If FMT_OS is disabled, these test files will either skip OS-specific tests or fail to compile the relevant sections.

Summary

  • FMT_OS is a CMake option defined in CMakeLists.txt (line 86) that defaults to ON, enabling OS-specific APIs by default
  • The FMT_OS macro controls conditional compilation in src/fmt.cc and include/fmt/os.h; define it to 1 manually for header-only usage
  • Enabling FMT_OS provides fmt::buffered_file, fmt::file, fmt::system_error, and platform-specific error reporting macros
  • Disabling FMT_OS removes file I/O dependencies, useful for embedded or restricted environments
  • Verification requires checking that src/os.cc is compiled and symbols appear in the library binary

Frequently Asked Questions

What happens if I include <fmt/os.h> with FMT_OS disabled?

The header includes guards that check #if FMT_OS, so the include succeeds but all OS-specific classes and functions are omitted. Any code attempting to use fmt::buffered_file or fmt::system_error will fail to compile with "identifier not found" errors.

Can I use FMT_OS features in a header-only configuration?

Yes, but you must manually define FMT_OS 1 before including fmt/os.h, and ensure that src/os.cc (or its contents) is compiled into your project. The CMake option is the recommended path, but manual definition works for custom build systems.

Does FMT_OS affect the size of the compiled binary?

Yes. Disabling FMT_OS with -DFMT_OS=OFF excludes src/os.cc and associated platform-specific code from the library, reducing binary size. This is beneficial for embedded targets or WebAssembly builds where file system access is unavailable or restricted.

Is FMT_OS required for basic string formatting in {fmt}?

No. Core formatting functionality in <fmt/format.h> operates independently of FMT_OS. You only need to enable FMT_OS when your application requires file I/O helpers (fmt::buffered_file), system error formatting (fmt::system_error), or portable system call wrappers (FMT_POSIX, FMT_RETRY).

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 →