You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何导出带有依赖项包含目录的CMake目标?

解决CMake导出目标时自动传递依赖包含目录的问题

你的核心问题在于:接口库foobar_interface导出时没有让CMake自动处理其依赖项foobar_result的配置传递,导致下游项目foobar_implA调用find_package(foobar_interface)时,无法自动获取foobar_result的包含目录。下面是分步的解决方案:

关键原理

CMake不会自动在导出的包配置中添加依赖查找逻辑,你需要通过标准的CMake包配置工具CMakePackageConfigHelpers来生成包含依赖查找的配置文件,同时确保依赖通过target_link_libraries的INTERFACE/PUBLIC模式传递,这样所有相关的INTERFACE属性(包含目录、链接库等)都会被自动传递给下游项目。


1. 优化foobar_result的CMake配置(规范包导出)

首先让foobar_result生成符合CMake标准的包配置,确保它的目标属性能被正确导入:

修改foobar_result/CMakeLists.txt:

cmake_minimum_required(VERSION 3.5)
project(foobar_result)
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)

add_library(result SHARED src/result.cpp)
target_include_directories(result PUBLIC
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
  $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)

# 生成版本配置文件(可选但推荐)
write_basic_package_version_file(
  ${PROJECT_NAME}ConfigVersion.cmake
  VERSION 1.0.0
  COMPATIBILITY SameMajorVersion
)

# 导出目标到Targets文件
install(EXPORT ${PROJECT_NAME}
  DESTINATION share/${PROJECT_NAME}/cmake
  FILE ${PROJECT_NAME}Targets.cmake
)

# 配置Config.cmake模板
configure_package_config_file(
  ${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
  ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
  INSTALL_DESTINATION share/${PROJECT_NAME}/cmake
)

# 安装目标、头文件和配置文件
install(TARGETS result EXPORT ${PROJECT_NAME})
install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} FILES_MATCHING PATTERN "*.hpp")
install(FILES
  ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
  ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
  DESTINATION share/${PROJECT_NAME}/cmake
)

创建foobar_result/Config.cmake.in模板文件:

@PACKAGE_INIT@

include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
check_required_components(@PROJECT_NAME@)

2. 修复foobar_interface的CMake配置(传递依赖查找逻辑)

重点是在foobar_interface的包配置中添加对foobar_result的自动查找,确保下游项目能间接获取foobar_result的所有属性:

修改foobar_interface/CMakeLists.txt:

cmake_minimum_required(VERSION 3.5)
project(foobar_interface)
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)

# 查找依赖的foobar_result
find_package(foobar_result REQUIRED)

add_library(foobar_interface INTERFACE)
# 用INTERFACE模式链接result,确保依赖属性被传递
target_link_libraries(foobar_interface INTERFACE result)
target_include_directories(foobar_interface INTERFACE
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
  $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)

# 生成版本配置文件
write_basic_package_version_file(
  ${PROJECT_NAME}ConfigVersion.cmake
  VERSION 1.0.0
  COMPATIBILITY SameMajorVersion
)

# 导出目标
install(EXPORT ${PROJECT_NAME}
  DESTINATION share/${PROJECT_NAME}/cmake
  FILE ${PROJECT_NAME}Targets.cmake
)

# 配置Config.cmake模板,添加自动查找foobar_result的逻辑
configure_package_config_file(
  ${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
  ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
  INSTALL_DESTINATION share/${PROJECT_NAME}/cmake
)

# 安装目标、头文件和配置文件
install(TARGETS foobar_interface EXPORT ${PROJECT_NAME})
install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} FILES_MATCHING PATTERN "*.hpp")
install(FILES
  ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
  ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
  DESTINATION share/${PROJECT_NAME}/cmake
)

创建foobar_interface/Config.cmake.in模板文件:

@PACKAGE_INIT@

# 自动查找依赖的foobar_result,确保下游项目能获取其包含目录
find_dependency(foobar_result REQUIRED)

include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
check_required_components(@PROJECT_NAME@)

3. 验证foobar_implA的CMake配置(无需修改核心逻辑)

foobar_implA的原有配置无需手动添加foobar_result的查找,只需要确保通过target_link_libraries链接foobar_interface即可自动获取所有依赖属性:

cmake_minimum_required(VERSION 3.5)
project(foobar_implA)
include(GNUInstallDirs)

# 只需要查找foobar_interface,依赖会自动传递
find_package(foobar_interface REQUIRED)

add_library(foobar_implA SHARED src/foobar_implA.cpp)
target_link_libraries(foobar_implA PUBLIC foobar_interface)
target_include_directories(foobar_implA PUBLIC
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
  $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)

# 可选:同样用CMakePackageConfigHelpers优化自身导出
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
  ${PROJECT_NAME}ConfigVersion.cmake
  VERSION 1.0.0
  COMPATIBILITY SameMajorVersion
)

install(EXPORT ${PROJECT_NAME}
  DESTINATION share/${PROJECT_NAME}/cmake
  FILE ${PROJECT_NAME}Targets.cmake
)

configure_package_config_file(
  ${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
  ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
  INSTALL_DESTINATION share/${PROJECT_NAME}/cmake
)

install(TARGETS foobar_implA EXPORT ${PROJECT_NAME})
install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} FILES_MATCHING PATTERN "*.hpp")
install(FILES
  ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
  ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
  DESTINATION share/${PROJECT_NAME}/cmake
)

为什么原来的配置失效?

你之前的foobar_interface导出配置仅设置了INTERFACE_LINK_LIBRARIES "result",但CMake不知道result目标的来源——没有自动触发find_package(foobar_result),因此无法导入result的INTERFACE_INCLUDE_DIRECTORIES属性。通过在foobar_interface的Config.cmake.in中添加find_dependency(foobar_result),CMake会自动查找并导入foobar_result的所有目标属性,最终传递给foobar_implA。

内容的提问来源于stack exchange,提问作者Christian Rauch

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 07:53:47