SPDLog Header-Only vs Compiled Library: When to Use Each Variant

SPDLog offers two build variants—a header-only mode that includes implementation directly from include/spdlog/ and a compiled library mode that builds libspdlog.a or libspdlog.so from sources in src/—with identical runtime performance but different trade-offs in compilation speed and binary size.

The gabime/spdlog repository supports dual consumption models through conditional compilation controlled by CMake targets. Understanding the distinction between these variants helps you optimize build times for large projects while maintaining flexibility for rapid prototyping.

Build System Architecture and CMake Targets

The root CMakeLists.txt defines two distinct targets that determine how SPDLog is consumed. The spdlog_header_only target adds include directories and optionally links the bundled fmt header-only library, while the spdlog target compiles sources from src/ into a physical library artifact.

When consuming the header-only variant, the SPDLOG_HEADER_ONLY macro is defined automatically by the CMake target. This macro causes include/spdlog/spdlog.h to include implementation files directly rather than relying on external linkage. Conversely, the compiled variant leaves this macro undefined, expecting the linker to resolve symbols from the built library.

Compilation Speed and Binary Size Trade-offs

Header-Only Compilation Characteristics

Using the header-only variant eliminates the linking step entirely. You add #include "spdlog/spdlog.h" and compile with the include path set to the include/ directory. However, every translation unit that includes SPDLog headers recompiles the full implementation, which can significantly inflate build times in codebases with many source files.

Compiled Library Advantages

The compiled library variant produces libspdlog.a (static) or libspdlog.so (shared) from the implementation files in src/spdlog.cpp and related source files. After the initial build, incremental compilation is faster because only changes to the library itself trigger recompilation. Additionally, shared libraries reduce total binary size when multiple executables link against SPDLog, as the object code is emitted only once.

How to Configure the Header-Only Variant

Include the repository and link against the spdlog_header_only target. No library linking is required during the final executable build.

// main.cpp
#include "spdlog/spdlog.h"

int main() {
    spdlog::info("Header-only SPDLog works!");
    return 0;
}
cmake_minimum_required(VERSION 3.12)
project(HeaderOnlyDemo)

add_subdirectory(path/to/spdlog)
add_executable(demo main.cpp)
target_link_libraries(demo INTERFACE spdlog_header_only)

The header-only implementation is controlled in include/spdlog/spdlog.h, which conditionally includes the implementation based on the SPDLOG_HEADER_ONLY definition.

How to Configure the Compiled Library Variant

Link against the spdlog target to consume the compiled library. This requires linking against the built library plus the fmt dependency unless SPDLOG_FMT_EXTERNAL_HO is enabled.

// main.cpp
#include "spdlog/spdlog.h"
#include "spdlog/sinks/basic_file_sink.h"

int main() {
    auto logger = spdlog::basic_logger_mt("file_logger", "logs/app.log");
    logger->info("Compiled SPDLog library in action");
    return 0;
}
cmake_minimum_required(VERSION 3.12)
project(CompiledDemo)

add_subdirectory(path/to/spdlog)
add_executable(demo main.cpp)
target_link_libraries(demo PRIVATE spdlog)

On Unix systems, this translates to linking with -lspdlog at the command line. On Windows, you link against spdlog.lib.

Implementation Details and File Structure

The core implementation resides in src/spdlog.cpp, which contains the template instantiations and registry logic. When building the compiled variant, these source files are compiled separately. When using the header-only variant, spdlog.h includes these implementation details directly through conditional compilation directives.

The cmake/spdlog_header_only.pc.in file provides pkg-config support for header-only consumers who do not use CMake, ensuring the correct include flags are propagated to the compiler.

Summary

  • Choose header-only (spdlog_header_only target) for small programs, prototypes, or single-file distributions where build simplicity outweighs compile-time costs.
  • Choose compiled (spdlog target) for large projects with multiple translation units to reduce incremental build times and share code via shared libraries.
  • Runtime performance is identical between both variants because the generated machine code is the same; only the build process differs.
  • Switching variants requires only changing the CMake target name from spdlog to spdlog_header_only (or vice versa) and adjusting the link interface from PRIVATE to INTERFACE.

Frequently Asked Questions

Does header-only SPDLog impact runtime performance?

No. The header-only and compiled variants produce identical runtime performance. The generated machine code is exactly the same because the header-only version uses the same source files found in src/; they are simply included at compile time rather than linked at link time.

How do I switch between header-only and compiled modes in an existing project?

Change your CMake target link from target_link_libraries(my_app PRIVATE spdlog) to target_link_libraries(my_app INTERFACE spdlog_header_only). Remove any explicit linking flags like -lspdlog from your build commands. The public API remains identical, so no source code changes are required.

What is the difference between the spdlog and spdlog_header_only CMake targets?

The spdlog target compiles source files from src/ into a static or shared library and defines SPDLOG_HEADER_ONLY as false. The spdlog_header_only target is an interface library that sets SPDLOG_HEADER_ONLY to true, causing headers under include/spdlog/ to include their own implementations directly without producing a separate library file.

Can I use SPDLog in a single translation unit without CMake?

Yes. For header-only usage without CMake, simply add the include/ directory to your compiler's include path and compile a single file with g++ -Ipath/to/spdlog/include main.cpp -std=c++11. This works because the header-only variant requires no linking step, though you may need to link against the fmt library separately if not using the bundled header-only version.

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 →