I have a simple project that needs to build three libraries for the header only: websocketpp , spdlog and nlohmann / json .
The structure of the project is as follows:
└── src ├── app │ ├── CMakeLists.txt │ ├── src │ └── test ├── CMakeLists.txt ├── core │ ├── CMakeLists.txt │ ├── include │ ├── src │ └── test └── vendor ├── install.cmake ├── nlohmann_json ├── spdlog └── websocketpp
The root CMakeLists.txt file is as follows:
cmake_minimum_required(VERSION 3.6.1 FATAL_ERROR) ..
The idea is that each subdirectory is a library (for example, core ), and the app "aggregates" all of them. Each library (e.g. core ) is built as follows ( core/CMakeLists.txt ):
project(foo-core VERSION 0.1 LANGUAGES CXX) add_library(foo-core src/foobar/foobar.cc src/foobaz/baz.cc) target_include_directories(foo-core PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> $<INSTALL_INTERFACE:include> PRIVATE src) target_link_libraries(foo-core websocketpp spdlog)
Notice how I link the dependencies (which are header-only libraries!). This is how I get them ( vendor/install.cmake ):
# spdlog if((NOT SPDLOG_INCLUDE_DIR) OR (NOT EXISTS ${SPDLOG_INCLUDE_DIR})) message("Unable to find spdlog, cloning...") execute_process(COMMAND git submodule update --init -- vendor/spdlog WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) set(SPDLOG_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/vendor/spdlog/include/ CACHE PATH "spdlog include directory") install(DIRECTORY ${SPDLOG_INCLUDE_DIR}/spdlog DESTINATION include) # Setup a target add_library(spdlog INTERFACE) target_include_directories(spdlog INTERFACE $<BUILD_INTERFACE:${SPDLOG_INCLUDE_DIR}> $<INSTALL_INTERFACE:include>) install(TARGETS spdlog EXPORT spdlog DESTINATION include) endif() # websocketpp if((NOT WEBSOCKETPP_INCLUDE_DIR) OR (NOT EXISTS ${WEBSOCKETPP_INCLUDE_DIR})) message("Unable to find websocketpp, cloning...") execute_process(COMMAND git submodule update --init -- vendor/websocketpp WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) set(WEBSOCKETPP_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/vendor/websocketpp/ CACHE PATH "websocketpp include directory") install(DIRECTORY ${WEBSOCKETPP_INCLUDE_DIR}/websocketpp DESTINATION include) # Setup a target add_library(websocketpp INTERFACE) target_include_directories(websocketpp INTERFACE $<BUILD_INTERFACE:${WEBSOCKETPP_INCLUDE_DIR}> $<INSTALL_INTERFACE:include>) install(TARGETS websocketpp EXPORT websocketpp DESTINATION include) endif() # nlohmann/json if((NOT NLOHMANN_JSON_INCLUDE_DIR) OR (NOT EXISTS ${NLOHMANN_JSON_INCLUDE_DIR})) message("Unable to find nlohmann/json, cloning...") execute_process(COMMAND git submodule update --init -- vendor/nlohmann_json WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) set(NLOHMANN_JSON_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/vendor/nlohmann_json/src/ CACHE PATH "nlohmann/json include directory") install(FILES ${NLOHMANN_JSON_INCLUDE_DIR}/json.hpp DESTINATION include) # Setup a target add_library(nlohmann_json INTERFACE ) target_include_directories(nlohmann_json INTERFACE $<BUILD_INTERFACE:${NLOHMANN_JSON_INCLUDE_DIR}> $<INSTALL_INTERFACE:include>) install(TARGETS nlohmann_json EXPORT nlohmann_json DESTINATION include) endif()
So far, so good: you can see that dependencies are selected as git submodules, which, fortunately, makes them easier to manage. However, when compiling my project with mkdir build && cd build && cmake ../src , I get the following errors:
CMake error: setting (EXPORT FooCoreConfig ...) includes the target foo-core, which requires the target websocketpp, which is not in the export set.
CMake error: setting (EXPORT FooCoreConfig ...) includes the target foo-core, which requires the target spdlog, which is not in the export set.
Including headers, for example. #include <spdlog/spdlog.h> or #include <nlohmann/json.hpp> throws an error stating that the header was not found.
In truth, I don't really like CMake, and I spent the last two days debugging this. It may be something really simple, but I cannot figure out how to achieve it. Actually, you can just pass it on - I'm like a compiler flag for using libraries as I want, but the CMake abstraction seems to bother me. I would be very happy if someone could explain why this does not work and, I hope, what is the right way to include these libraries in my project. Thanks in advance!