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>
Share:
13,804

Related videos on Youtube

Wootiae
Author by

Wootiae

Updated on June 07, 2022

Comments

  • Wootiae
    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
      Jesper Juhl over 2 years
      If you want everything in headers, why are you putting things into .cpp files in the first place??
    • NathanOliver
      NathanOliver over 2 years
      This 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
      Rufus over 2 years
      A good reference with line by line explanation can be found here: dominikberner.ch/cmake-interface-lib
    • user3389943
      user3389943
      I 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.
    • Wootiae
      Wootiae
      If it is important I can move everything in headers but not into one.
  • Satrapes
    Satrapes over 1 year
    I 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
    ToddR over 1 year
    Strictly 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
    X.Arthur over 1 year
    @ToddR If the library is an "INTERFACE", that keyword can only be "INTERFACE".
  • sebrockm
    sebrockm about 1 year
    Worth 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.

Related