# How to Integrate spdlog into a CMake Project: Complete Guide

> Integrate spdlog into your CMake project seamlessly. Learn to add the spdlog repository as a subdirectory and link against spdlog::spdlog or spdlog::spdlog_header_only for efficient logging. Get the complete guide now

- Repository: [Gabi Melman/spdlog](https://github.com/gabime/spdlog)
- Tags: how-to-guide
- Published: 2026-07-20

---

**To integrate spdlog into a CMake project, add the repository as a subdirectory and link against either `spdlog::spdlog` for compiled library usage or `spdlog::spdlog_header_only` for header-only integration.**

The `gabime/spdlog` repository provides a comprehensive CMake build system defined in the top-level [`CMakeLists.txt`](https://github.com/gabime/spdlog/blob/main/CMakeLists.txt) that supports both compiled and header-only modes. This guide covers the exact targets, configuration options, and source file locations you need to successfully integrate spdlog into your CMake-based C++ project.

## CMake Targets and Build Options

The root [`CMakeLists.txt`](https://github.com/gabime/spdlog/blob/main/CMakeLists.txt) creates two primary targets that determine how spdlog is consumed:

- **`spdlog::spdlog`** – A compiled library (static by default, or shared when `SPDLOG_BUILD_SHARED` is enabled). Linking this target automatically adds the `include/` directory and links `Threads::Threads`.
- **`spdlog::spdlog_header_only`** – An **INTERFACE** target for header-only usage that requires no compiled objects. This also propagates include directories and threading dependencies.

Both targets handle transitive dependencies automatically. When you enable external fmt support via `SPDLOG_FMT_EXTERNAL` or `SPDLOG_FMT_EXTERNAL_HO`, the targets additionally link `fmt::fmt` or `fmt::fmt-header-only` respectively.

Key configuration options defined in [`CMakeLists.txt`](https://github.com/gabime/spdlog/blob/main/CMakeLists.txt) include:

- `SPDLOG_BUILD_SHARED` – Force shared library build (respects `BUILD_SHARED_LIBS` if undefined)
- `SPDLOG_FMT_EXTERNAL` – Link against system-installed fmt library
- `SPDLOG_FMT_EXTERNAL_HO` – Use system fmt in header-only mode
- `SPDLOG_USE_STD_FORMAT` – Enable C++20 `std::format` support (requires C++20)

## Step-by-Step Integration Methods

### Compiled Static or Shared Library

The default integration method builds spdlog as a compiled library. Add the subdirectory before defining your executable or library:

```cmake
add_subdirectory(path/to/spdlog)

```

Then link the compiled target:

```cmake
target_link_libraries(my_app PRIVATE spdlog::spdlog)

```

This approach produces either `libspdlog.a` (static) or `libspdlog.so`/`spdlog.dll` (shared) depending on your `SPDLOG_BUILD_SHARED` setting.

### Header-Only Usage

For header-only integration—useful when you want minimal build artifacts—link against the interface target instead:

```cmake
add_subdirectory(spdlog)
target_link_libraries(my_app PRIVATE spdlog::spdlog_header_only)

```

The `spdlog::spdlog_header_only` target is defined as an **INTERFACE** library in [`CMakeLists.txt`](https://github.com/gabime/spdlog/blob/main/CMakeLists.txt), meaning it carries no compiled objects but provides all necessary include paths and compiler definitions.

### Using External fmt Library

By default, spdlog bundles its own copy of the fmt library. To use a system-installed version, set the appropriate option **before** calling `add_subdirectory()`:

```cmake
set(SPDLOG_FMT_EXTERNAL ON)      # For compiled fmt

# OR

set(SPDLOG_FMT_EXTERNAL_HO ON)   # For header-only fmt

add_subdirectory(spdlog)

```

When enabled, the spdlog targets will link against `fmt::fmt` or `fmt::fmt-header-only` rather than the bundled headers in `include/spdlog/fmt/bundled/`.

## Advanced Configuration Options

### Enabling C++20 std::format Support

To use C++20's `std::format` instead of the bundled fmt library, enable `SPDLOG_USE_STD_FORMAT`. This requires C++20 compiler support:

```cmake
set(SPDLOG_USE_STD_FORMAT ON)
add_subdirectory(spdlog)

```

When this option is active, spdlog utilizes `<format>` instead of the internal formatting engine, reducing dependencies but increasing the minimum C++ standard requirement from C++11 to C++20.

### Controlling Library Type (Static vs Shared)

Control whether spdlog builds as a static or shared library using `SPDLOG_BUILD_SHARED` or the generic CMake `BUILD_SHARED_LIBS` variable:

```cmake
set(SPDLOG_BUILD_SHARED ON)  # Build libspdlog.so or spdlog.dll

add_subdirectory(spdlog)

```

If neither variable is set, the default is a static library. The [`CMakeLists.txt`](https://github.com/gabime/spdlog/blob/main/CMakeLists.txt) logic checks these variables to determine the library type when creating the `spdlog::spdlog` target.

## Complete CMake Examples

### Example 1: Compiled Static Library

```cmake
cmake_minimum_required(VERSION 3.10)
project(my_app LANGUAGES CXX)

# Build spdlog as a static library (default)

add_subdirectory(spdlog)

add_executable(my_app src/main.cpp)
target_link_libraries(my_app PRIVATE spdlog::spdlog)

```

### Example 2: Header-Only with External fmt

```cmake
cmake_minimum_required(VERSION 3.10)
project(my_app LANGUAGES CXX)

set(SPDLOG_FMT_EXTERNAL_HO ON)
add_subdirectory(spdlog)

add_executable(my_app src/main.cpp)
target_link_libraries(my_app PRIVATE spdlog::spdlog_header_only)

```

### Example 3: Shared Library with C++20 std::format

```cmake
cmake_minimum_required(VERSION 3.10)
project(my_app LANGUAGES CXX)

set(SPDLOG_BUILD_SHARED ON)
set(SPDLOG_USE_STD_FORMAT ON)
add_subdirectory(spdlog)

add_executable(my_app src/main.cpp)
target_link_libraries(my_app PRIVATE spdlog::spdlog)

```

## Key Source Files and Implementation Details

Understanding the following files in the `gabime/spdlog` repository helps with advanced customization:

- **[`CMakeLists.txt`](https://github.com/gabime/spdlog/blob/main/CMakeLists.txt)** (root) – Defines all build options, creates the `spdlog` and `spdlog_header_only` targets, handles external fmt linkage, and sets up installation rules. This file implements the logic for `SPDLOG_BUILD_SHARED`, `SPDLOG_FMT_EXTERNAL`, and `SPDLOG_USE_STD_FORMAT`.
- **`cmake/utils.cmake`** – Contains helper functions like `spdlog_extract_version()` and compiler warning configurations.
- **`cmake/ide.cmake`** – Provides IDE-specific configurations for development environments like VSCode and CLion.
- **[`include/spdlog/spdlog.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/spdlog.h)** – The primary public header that user code includes after linking the CMake targets.
- **[`example/CMakeLists.txt`](https://github.com/gabime/spdlog/blob/main/example/CMakeLists.txt)** – Demonstrates minimal usage patterns for both compiled and header-only integration modes.

The build system automatically handles threading support by linking `Threads::Threads` through the spdlog targets, eliminating the need for manual `find_package(Threads)` calls in consuming projects.

## Summary

- Use `add_subdirectory(spdlog)` to import the build system from the `gabime/spdlog` repository.
- Link `spdlog::spdlog` for compiled library usage or `spdlog::spdlog_header_only` for header-only integration.
- Set `SPDLOG_FMT_EXTERNAL` or `SPDLOG_FMT_EXTERNAL_HO` before the subdirectory call to use system-installed fmt instead of the bundled version.
- Enable `SPDLOG_BUILD_SHARED` to produce shared libraries instead of static archives.
- Enable `SPDLOG_USE_STD_FORMAT` for C++20 `std::format` support, though this requires C++20 compliance.
- The root [`CMakeLists.txt`](https://github.com/gabime/spdlog/blob/main/CMakeLists.txt) automatically propagates include directories and threading dependencies through the exported targets.

## Frequently Asked Questions

### What is the difference between spdlog::spdlog and spdlog::spdlog_header_only?

The `spdlog::spdlog` target references a compiled library (static or shared) that requires linking against built object files, while `spdlog::spdlog_header_only` is an **INTERFACE** target defined in [`CMakeLists.txt`](https://github.com/gabime/spdlog/blob/main/CMakeLists.txt) that provides all functionality through headers without compiled binaries. The header-only target is useful for reducing build complexity, whereas the compiled library reduces compilation times in larger projects by avoiding repeated template instantiation.

### How do I integrate spdlog with an external fmt library?

Set `SPDLOG_FMT_EXTERNAL=ON` for a compiled external fmt or `SPDLOG_FMT_EXTERNAL_HO=ON` for header-only external fmt **before** calling `add_subdirectory(spdlog)`. This configuration tells the spdlog build system to link against `fmt::fmt` or `fmt::fmt-header-only` targets rather than using the bundled fmt headers located in `include/spdlog/fmt/bundled/`.

### Can I build spdlog as a shared library?

Yes. Set `SPDLOG_BUILD_SHARED=ON` before adding the spdlog subdirectory, or set the generic CMake variable `BUILD_SHARED_LIBS=ON`. This causes the `spdlog::spdlog` target to reference a shared library (`libspdlog.so` on Linux, `spdlog.dll` on Windows) instead of a static archive.

### What C++ standard does spdlog require?

By default, spdlog requires C++11. However, if you enable `SPDLOG_USE_STD_FORMAT=ON`, the library requires C++20 to support the standard library's `<format>` header. The [`CMakeLists.txt`](https://github.com/gabime/spdlog/blob/main/CMakeLists.txt) enforces these requirements through `target_compile_features` checks when this option is enabled.