Я также не могу найти идеальный способ сделать это. Но вот обходной путь, который я использую сейчас. Это дополнительная работа, а не СУХОЙ, но я думаю, что она правильная.
Imagine lib B
зависит от стороннего пользователя A
. A
либо имеет определенный модуль поиска, либо мы можем реализовать для него настраиваемый модуль поиска. Оба выполнимы. Предположим, что мы уже написали FindA.cmake
и занесены в ${CMAKE_SOURCE_DIR}/cmake
.Кроме того, предположим, что когда вы запускаете cmake для создания системы сборки B
, вы предоставляете A_ROOT
, чтобы помочь cmake найти A
.
Затем в верхнем уровне Б CMakeLists.txt
нам нужно:
# Use FindA.cmake, defined in the cmake/ directory.
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
find_package(A REQUIRED)
# ... (define the B target here)...
# Copy the config file to the build dir
configure_file(cmake/BConfig.cmake cmake/BConfig.cmake @ONLY)
# Copy A's find module (skip this step if FindA is not custom).
configure_file(cmake/FindA.cmake cmake/FindA.cmake COPYONLY)
# Create the target export.
export(EXPORT BTargets
FILE ${CMAKE_BINARY_DIR}/cmake/BTargets.cmake
NAMESPACE B::
)
# Register B so cmake can find B's config file.
export(PACKAGE B)
Сейчас в cmake/BConfig.cmake
:
# Get the exported find module onto the module path.
# This step is unnecessary if the find module is part of cmake.
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
# Store the root so that find_package will work.
# You may have to store other variables here, too, but
# the principle is just more of the same.
set(A_ROOT @[email protected]) # **Could optionally cache this.
find_package(A MODULE REQUIRED)
# The usual one-liner for a config file.
include("${CMAKE_CURRENT_LIST_DIR}/BTargets.cmake")
Просто ехать домой решение, давайте посмотрим на второй пример, Rocket
на этот раз с помощью Boost
, у которого уже определен модуль поиска.
CMakeLists.txt
:
option(Boost_USE_MULTITHREADED ON)
option(Boost_USE_STATIC_LIBS OFF)
find_package(Boost REQUIRED COMPONENTS filesystem program_options)
add_library(Rocket rocket.cpp)
target_link_libraries(Rocket
PUBLIC Boost::filesystem
PRIVATE Boost::program_options
)
configure_file(cmake/BConfig.cmake cmake/BConfig.cmake @ONLY)
export(EXPORT RocketTargets
FILE ${CMAKE_BINARY_DIR}/RocketTargets.cmake
NAMESPACE Rocket::
)
export(PACKAGE Rocket)
Тогда cmake/RocketConfig.cmake
бы:
set(BOOST_ROOT @[email protected] CACHE PATH "In case boost was relocated.")
set(Boost_USE_MULTITHREADED @[email protected])
set(Boost_USE_STATIC LIBS @[email protected])
find_package(Boost REQUIRED COMPONENTS filesystem program_options)
include("${CMAKE_CURRENT_LIST_DIR}/RocketTargets.cmake")
Так что да. Похоже, слишком много печатается. Кажется, что cmake должен иметь возможность генерировать весь этот код из инструкции export
в CMakeLists.txt
. Но эта стратегия, похоже, достигает цели.
Кроме того, я еще не проверял, но я подозреваю, что, если транзитивной зависимостью использует CONFIG
вместо MODULE
для find_package
, это должно быть очень легко просто добавить в CMAKE_PREFIX_PATH
в файле конфигурации, а также.
Одна из проблем заключается в том, что он не позволяет устанавливать целевые свойства, такие как INTERFACE_INCLUDE_DIRECTORIES – RiaD