Include headers with a library in CMake

12,796

Solution 1

As @Anedar mentioned, to resolve this situation one needs target_include_directories with PUBLIC or INTERFACE options in the library CMakeLists.txt. That populates INTERFACE_INCLUDE_DIRECTORIES of the library target, which is used by target_link_libraries on the consuming side.

My working configuration:

/my_project/CMakeLists.txt

cmake_minimum_requared(VERSION 3.8)
project(my_project)
add_subdirectory(utils)
add_executable(main main.c)
target_link_libraries(main utils base_c base_cpp)

/my_project/utils/CMakeLists.txt

add_subdirectory(base_c)
add_subdirectory(base_cpp)
add_library(utils)
target_sources(utils PUBLIC common.h)
target_include_directories(utils INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})

/my_project/utils/base_c/CMakeLists.txt

add_library(base_c base_c.c)
target_sources(base_c PUBLIC base_c.h)
target_include_directories(base_c INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})

/my_project/utils/base_cpp/CMakeLists.txt

add_library(base_cpp base_cpp.cpp)
target_sources(base_cpp PUBLIC base_cpp.hpp)
target_include_directories(base_cpp INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(base_cpp base_c)

Solution 2

target_include_directories) is what you are looking for, but not the PRIVATE option.

According to the target_include_directories() documentation the PRIVATE option is for directories only used in that target, INTERFACE is for directories only used by dependent targets and PUBLIC is for both.

I suggest using in /my_project/utils/base_c/CMakeLists.txt

target_include_directories(base_c INTERFACE ${CMAKE_CURRENT_LIST_DIR})

This way you "link" the include directory to the target it belongs to and all targets dependent on it automatically include the directory.

Additionally you might want to move your public headers to their own subfolder /my_project/utils/base_c/base_c/ and then include them as #include "base_c/base_c.h". This introduces kind of a "namespace" to headers, preventing headers with the same name from different projects from beeing ambigous.

Share:
12,796

Related videos on Youtube

voddan
Author by

voddan

Updated on June 04, 2022

Comments

  • voddan
    voddan 7 months

    My project has two utility library in it. I am looking for the best way to write CMake configurations for the libraries.

    /my_project
     --> CMakeLists.txt
     --> main.cpp
     --> /utils
          --> CMakeLists.txt
          --> common.h
          --> /base_c
               --> CMakeLists.txt
               --> base_c.c
               --> base_c.h
          --> /base_cpp
               --> CMakeLists.txt
               --> base_cpp.cpp
               --> base_cpp.hpp
    

    My current CMake files:

    /my_project/CMakeLists.txt

    cmake_minimum_requared(VERSION 3.8)
    project(my_project)
    add_subdirectory(utils)
    add_executable(main main.c)
    target_link_libraries(main utils base_c base_cpp)
    

    /my_project/utils/CMakeLists.txt

    add_subdirectory(base_c)
    add_subdirectory(base_cpp)
    add_library(utils)
    target_sources(utils PUBLIC common.h)
    

    /my_project/utils/base_c/CMakeLists.txt

    add_library(base_c base_c.c)
    target_sources(base_c PUBLIC base_c.h)
    

    /my_project/utils/base_cpp/CMakeLists.txt

    add_library(base_cpp base_cpp.cpp)
    target_sources(base_cpp PUBLIC base_cpp.hpp)
    find_library(BASEC base_c ../base_c)
    target_link_libraries(base_cpp BASEC)
    

    The problem is that base_cpp does not find includes from base_c. How should I fix the configuration?

    I managed to make it work with target_include_directories(base_cpp PRIVATE ../base_c), but that's ugly and shouldn't be necessary, according to INTERFACE_INCLUDE_DIRECTORIES documentation.

    • Tsyvarev
      Tsyvarev over 5 years
      How documentation for INTERFACE_INCLUDE_DIRECTORIES implies that target_include_directories is not needed? I am curious how you have managed to compile even single library without include_directories or target_include_directories.
    • voddan
      voddan over 5 years
      @Tsyvarev I may be totally wrong on this. Could you explain how I can use INTERFACE_INCLUDE_DIRECTORIES of a library?
    • Anedar
      Anedar over 5 years
      Which build system do you use after CMake? Makefiles? Visual Studio projects? Can you examine those files which directories are actually passed as include-directories?
  • voddan
    voddan over 5 years
    Do I need to do anything on the consuming side in base_cpp? Currently find_library returns BASEC-NOTFOUND
  • Anedar
    Anedar over 5 years
    you dont need find_library in the same project. just use target_link_libraries(base_cpp base_c)
  • voddan
    voddan over 5 years
    Ok, I did that, but it can't resolve the headers. Maybe I need target_include_directories(base_cpp <something>)?
  • Tsyvarev
    Tsyvarev over 5 years
    @voddan: it can't resolve the headers. - Looks like your code includes headers in unexpected manner. Update your question post with new CMake code and actual error message.
  • voddan
    voddan over 5 years
    This is a correct answer, but the explanation is off, so I didn't get it when I needed it :(