How to make a header-only library with cmake?
13,804
How to make a header-only library with cmake?
Like this:
add_library(project INTERFACE)
target_include_directories(project INTERFACE .)
Then in the target that uses the library:
target_link_libraries(dependee
PUBLIC/INTERFACE/PRIVATE # pick one
project)
and include the header like this:
#include <project/folder1/file.hpp>
Related videos on Youtube

Author by
Wootiae
Updated on June 07, 2022Comments
-
Wootiae 6 months
How to make a project in cmake that collects all c++ files into one header?
I have this project structure.
/ project/ folder1/ file.cpp file.hpp folder2/ ...etc CMakeLists.txt tests/ test.cpp CMakeLists.txt CMakeList.txt
root cmakelists.txt
cmake_minimum_required (VERSION 3.8) project ("CMakeProject" LANGUAGES C CXX) set(CMAKE_EXECUTABLE_SUFFIX ".exe") include(GNUInstallDirs) add_subdirectory ("project") option(ENABLE_TESTING OFF) if (ENABLE_TESTING) enable_testing() add_subdirectory("tests") endif()
CMakeLists.txt in project
cmake_minimum_required (VERSION 3.8) file(GLOB projectSRC "*/*.cpp" "*/*.hpp" "*.cpp" "*.hpp" ) add_library(project INTERFACE) message(STATUS "CMake inatall directory: " ${CMAKE_INSTALL_INCLUDEDIR}) target_include_directories(project INTERFACE $<BUILD_INTERFACE:${PROJECT_INCLUDE_DIR}> $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
and test cmakelist.txt
cmake_minimum_required (VERSION 3.8) # install Catch2 testing library # (https://github.com/catchorg/Catch2/blob/master/docs/cmake-integration.md#installing-catch2-from-git-repository or use packet manager) find_package(Catch2 REQUIRED) file(GLOB testSRC "*.cpp" ) add_executable(tests ${testSRC}) target_link_libraries(tests Catch2::Catch2 project) include(CTest) include(Catch) catch_discover_tests(tests)
How to generate one header and use it (in tests or other projects) or make this library able to have templates? The first is better.
-
Jesper Juhl over 2 yearsIf you want everything in headers, why are you putting things into .cpp files in the first place??
-
NathanOliver over 2 yearsThis might not be possible. You can define variables that are local to single cpp file and if you've done that then there is a potential you'll be redefining something if multiple cpp file define the same variable.
-
Rufus over 2 yearsA good reference with line by line explanation can be found here: dominikberner.ch/cmake-interface-lib
-
user3389943I never personally tried doing this. However, you can check open source projects on github that do this. You might get good pointers from playing with their projects. I know of 2, there is pybind11 and catch2 that are header only libraries.
-
WootiaeIf it is important I can move everything in headers but not into one.
-
-
Satrapes over 1 yearI found that in the target_link_libraries if the header only library is INTERFACE then when building the project cmake will not detect the header files of the library.
-
ToddR over 1 yearStrictly speaking, shouldn't the scope of '.' in target_include_directories be PUBLIC, vs. INTERFACE? Technically the files in that directory include other files in that directory. I understand that, practically speaking, it makes no difference, since you will never actually build this project. I suppose it would allow you to make one less change if you ever add an implementation file and change the library to PUBLIC (non-header-only).
-
X.Arthur over 1 year@ToddR If the library is an "INTERFACE", that keyword can only be "INTERFACE".
-
sebrockm about 1 yearWorth noting: Since CMake 3.19 interface libraries can be created with source files, i.e.
add_library(project INTERFACE file1.hpp file2.hpp)
. If you are working with Visual Studio, those headers will now show up under the generated project.