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_onlytarget) for small programs, prototypes, or single-file distributions where build simplicity outweighs compile-time costs. - Choose compiled (
spdlogtarget) 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
spdlogtospdlog_header_only(or vice versa) and adjusting the link interface fromPRIVATEtoINTERFACE.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →