Добавление только заголовочных зависимостей с помощью CMake

У меня есть простой проект, который требует три библиотеки только для заголовка для компиляции: websocketpp, spdlog а также nlohmann / JSON.

Структура проекта выглядит следующим образом:

└── src
├── app
│   ├── CMakeLists.txt
│   ├── src
│   └── test
├── CMakeLists.txt
├── core
│   ├── CMakeLists.txt
│   ├── include
│   ├── src
│   └── test
└── vendor
├── install.cmake
├── nlohmann_json
├── spdlog
└── websocketpp

Корень CMakeLists.txt выглядит следующим образом:

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)

Идея заключается в том, что каждый подкаталог является библиотекой (например, core), а также app «объединяет» их всех. Каждая библиотека (например, core) построен так (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)

Обратите внимание, как я связываю зависимости (которые являются библиотеками только для заголовков!). Вот так я их и получаю (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()

Пока все хорошо: вы можете видеть, что зависимости выбираются как подмодули git, что, к счастью, облегчает управление ими. Тем не менее, когда я собираю свой проект с mkdir build && cd build && cmake ../srcУ меня есть следующие ошибки:

CMake Ошибка: установка (EXPORT FooCoreConfig …) включает цель
foo-core, для которого требуется целевой websocketpp, которого нет в экспорте
задавать.

CMake Ошибка: установка (EXPORT FooCoreConfig …) включает цель
foo-core, для которого требуется целевой spdlog, которого нет в наборе экспорта.

Включая заголовки, например #include <spdlog/spdlog.h> или же #include <nlohmann/json.hpp> выдает ошибку о том, что заголовок не найден.

По правде говоря, мне не очень комфортно с CMake, и я потратил последние два дня на его отладку. Это может быть что-то действительно простое, но я не могу понять, как этого добиться. В действительности, можно просто передать -I как флаг компилятора, чтобы использовать библиотеки так, как я хочу, но абстракция CMake, кажется, смущает меня. Я был бы очень рад, если бы кто-то мог объяснить, почему это не работает, и, надеюсь, как правильно включить эти библиотеки в мой проект. Заранее спасибо!

8

Решение

Как вы и сказали: вы не устанавливали свои цели в наборе экспорта. Другими словами, вам не хватает install(EXPORT ... строка для ваших целей только для заголовка. Например, учитывая вашу библиотеку только для заголовков websocketpp, у тебя должно быть:

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)

То же самое относится и к другим библиотекам.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]