Friday, November 12, 2021

[SOLVED] CMake Include paths - library that depend on external library

Issue

Take for example this project structure

project
    CMakeLists.txt
    main.cpp
    libA
         src.cpp
         CMakeLists.txt
    libB
         foo.h
         foo.cpp
         CMakeLists.txt
       

src.cpp and main.cpp:

#include "foo.h"
.
.
.

I need both src.cpp and main.cpp to have libB in their include path, what I've tried to do is:

libB/CMakeLists.txt:

add_library(libB SHARED
    src.cpp)

libA/CMakeLists.txt:

add_library(libA SHARED
    foo.cpp)
target_link_libraries(libA libB)

project/CMakeLists.txt:

add_subdirectory(libA)
add_subdirectory(libB)
add_executable(App main.cpp)
target_include_directories(App PUBLIC libB)
target_link_libraries(App libA libB)

And yet I get an error that src.cpp: fatal error: foo.h: No such file or directory


Solution

In the top-level:

cmake_minimum_required(VERSION 3.21)
project(project)

option(BUILD_SHARED_LIBS "Build shared libs instead of static" ON)

add_subdirectory(libA)
add_subdirectory(libB)

add_executable(App main.cpp)
target_link_libraries(App PRIVATE libA libB)

In libA:

add_library(libA src.cpp)

# Use PUBLIC below if libA exposes libB's types in its API.
target_link_libraries(libA PRIVATE libB)

In libB:

add_library(libB foo.cpp)
target_include_directories(
  libB PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>"
)

PUBLIC and INTERFACE properties on targets propagate to their linkees. Thus, when we set up the include directories on libB, any target linking to it will get its source directory added it its include path.

We guard the include directory with $<BUILD_INTERFACE:...> so that if you ever install() the library somewhere it might be re-used in another CMake build, it won't remember details of your specific file system.



Answered By - Alex Reinking