CMake预构建三方共享库的导出打包及find_package适配问题求解
核心问题根源
- 链接路径缺失前缀:你在
INSTALL_INTERFACE中直接填写了库文件名,CMake会将其识别为纯库名传给链接器,仅搜索系统默认库路径。只要改为填写相对于安装根目录的库路径,CMake导出时会自动拼接${_IMPORT_PREFIX}前缀。 check_required_components函数缺失:你使用了普通configure_file生成配置文件,未引入CMakePackageConfigHelpers模块的相关函数,替换为configure_package_config_file生成即可解决。
完整修正方案
1. 前置依赖引入
在CMakeLists开头添加必要模块引入:
cmake_minimum_required(VERSION 3.15) # 至少3.15保证INTERFACE目标导出兼容性 project(A VERSION 1.0.0 LANGUAGES C CXX) include(GNUInstallDirs) # 提供标准化的CMAKE_INSTALL_*路径变量 include(CMakePackageConfigHelpers) # 提供配置文件生成、check_required_components等功能
2. 目标定义修正
修改链接路径配置,新增RPATH解决运行时库找不到的问题:
add_library(A INTERFACE) add_library(A::A ALIAS A) target_include_directories(A INTERFACE "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>" "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>" ) # 修正INSTALL_INTERFACE库路径,填写相对安装根目录的路径,CMake会自动拼接前缀 target_link_libraries(A INTERFACE "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/lib/A.so>" "$<INSTALL_INTERFACE:${CMAKE_INSTALL_LIBDIR}/A.so>" "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/lib/B.so>" "$<INSTALL_INTERFACE:${CMAKE_INSTALL_LIBDIR}/B.so>" "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/lib/C.so>" "$<INSTALL_INTERFACE:${CMAKE_INSTALL_LIBDIR}/C.so>" ) # 新增RPATH配置,自动处理运行时库搜索路径 set_target_properties(A PROPERTIES INTERFACE_BUILD_RPATH "${CMAKE_CURRENT_SOURCE_DIR}/lib" INTERFACE_INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" )
3. 安装导出逻辑修正
替换普通configure_file为configure_package_config_file:
# 安装INTERFACE目标 install(TARGETS A EXPORT ATargets RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT A_Runtime LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT A_Runtime NAMELINK_COMPONENT A_Development ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT A_Development ) # 安装预编译库和头文件 install(DIRECTORY "lib/" DESTINATION ${CMAKE_INSTALL_LIBDIR} PATTERN "*.so*" PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE ) install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} ) # 生成版本文件 write_basic_package_version_file( "${CMAKE_CURRENT_BINARY_DIR}/AConfigVersion.cmake" VERSION ${PROJECT_VERSION} COMPATIBILITY SameMajorVersion ) # 导出目标配置 install(EXPORT ATargets FILE ATargets.cmake NAMESPACE A:: DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/A COMPONENT A_Development ) # 用configure_package_config_file替代普通configure_file生成配置 configure_package_config_file( AConfig.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/AConfig.cmake" INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/A ) # 安装配置文件 install(FILES "${CMAKE_CURRENT_BINARY_DIR}/AConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/AConfigVersion.cmake" DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/A COMPONENT A_Development )
4. AConfig.cmake.in 恢复功能
取消check_required_components的注释即可:
@PACKAGE_INIT@ include(CMakeFindDependencyMacro) include("${CMAKE_CURRENT_LIST_DIR}/ATargets.cmake") check_required_components(@PROJECT_NAME@)
验证效果
- add_subdirectory场景:父项目直接调用
add_subdirectory引入A的仓库,执行target_link_libraries(myapp PRIVATE A::A)即可正常编译运行,无需手动配置任何路径。 - find_package场景:打包安装deb包后,客户端项目调用
find_package(A REQUIRED),执行target_link_libraries(myapp PRIVATE A::A)即可正常编译运行,生成的ATargets.cmake会自动为链接库加上${_IMPORT_PREFIX}/${CMAKE_INSTALL_LIBDIR}前缀,IMPORTED标识和命名空间均可正常使用,无需手动修改生成文件。
内容的提问来源于stack exchange,提问作者Etienne M
相关产品推荐
相关产品推荐

