Adding header-only dependencies using CMake

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) .. # External 3rd party libs that we include include(vendor/install.cmake) add_subdirectory(core) add_subdirectory(app) 

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) # <- see here, using spdlog & websocketpp # 'make install' to the correct location install(TARGETS foo-core EXPORT FooCoreConfig ARCHIVE DESTINATION lib LIBRARY DESTINATION lib RUNTIME DESTINATION bin) install(DIRECTORY include/ DESTINATION include) install(EXPORT FooCoreConfig DESTINATION share/FooCore/cmake) export(TARGETS foo-core FILE FooCoreConfig.cmake) 

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!

+5
source share
1 answer

As you said: you did not set your goals in the export set. In other words, you are missing the install(EXPORT ... line for header-only purposes. For example, given your websocketpp header websocketpp , you should have:

 add_library(websocketpp INTERFACE) target_include_directories(websocketpp INTERFACE $<BUILD_INTERFACE:${WEBSOCKETPP_INCLUDE_DIR}> $<INSTALL_INTERFACE:include>) install(TARGETS websocketpp EXPORT websocketpp-config DESTINATION include) # here is the missing line: install(EXPORT websocketpp-config DESTINATION share/websocketpp/cmake) 

The same goes for other libraries.

+1
source

Source: https://habr.com/ru/post/1261945/


All Articles