我不会直接提出问题,而是公开我的用例以及我尝试(但失败)解决它的方式。
说我有:
- 3 个共享库 A、B 和 C
- A 要求 B 和 C
- A 自带一组表头
就是这样,没有额外的信息,它是由供应商提供的,不可能有任何变化(现代化/cmake 包等)。A 应始终与 B 和 C 打包。我只需要与 A 链接,cmake 应与 B 和 C 传递链接。
现在,我想让它更“现代 cmake”友好,并且能够:
- 第一个用例:创建一个包含这些库并从父项目调用 add_subdirectory() 的存储库。
- 第一个用例:创建一个包含相关 AConfig.cmake AConfigVersion.cmake 和 ATargets.cmake 的包(比如 debian pkg .deb)。然后一个简单的 pkg 系统安装和一个 find_package() 应该可以解决问题。
做了什么:
我尝试使用 INTERFACE IMPORTED 库和 INTERFACE。
因为我想支持打包libs INTERFACE IMPORTED 不能使用(据我所知/测试你不能安装它)。
INTERFACE 在第一个用例中运行良好,使用 add_subdirectory(),找到标头,所有链接,但由于用户此时可能没有,共享库是路径,例如,他无法运行测试。
然后是使共享库可用并使 find_package() 工作所需的导出部分。我成功导出/打包了 libs ABC、A 的标头和 find_package() 所需的文件。
但是,当在客户端库 D 中,find_package(A REQUIRED) 找到 lib(没有消息,例如“找不到由“A”提供的包配置文件”)它不会创建任何我可以链接的目标。我查看了生成的 ATargets.cmake:
# generated stuff before
add_library(A::A INTERFACE IMPORTED) # This is cannot be used at all, does not create a target I can link on unless I remove IMPORTED
set_target_properties(A::A PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include" # that's fine
INTERFACE_LINK_LIBRARIES "A.so;B.so.1.0;C.so.1.0" # that's not fine I need ${_IMPORT_PREFIX}/${CMAKE_INSTALL_LIBDIR}/ before each libs like it did for the headers
)
# generated stuff after
请注意,如果我删除 ATargets.cmake 的 add_library 中的 IMPORTED 并删除命名空间的东西,目标 A 可以在任何客户端 cmake 项目中使用 find_package 正确访问,但它可能无法正确链接,因为 A.so (和 B 和C) 未使用${_IMPORT_PREFIX}/lib/A.so
. 我尝试${_IMPORT_PREFIX}/lib/
在 INTERFACE_LINK_LIBRARIES 中的所有库之前添加,删除 IMPORTED 关键字和命名空间的东西,猜猜是什么,它完美地工作......现在,我该如何做到这一点而没有技巧。
AConfig.cmake.in 的内容是:
@PACKAGE_INIT@
include(CMakeFindDependencyMacro)
# Add the targets file
include("${CMAKE_CURRENT_LIST_DIR}/ATargets.cmake")
# check_required_components(@PROJECT_NAME@) # It is commented because unless I apply the fix specified earlier (IMPORTED and namespace removed), during the find_package call I get:
#################
# CMake Error at /usr/lib/cmake/A/AConfig.cmake:8 # (check_required_components):
# Unknown CMake command "check_required_components".
#################
差不多就是这样,这篇文章的其余部分是实现细节。以下代码可用于解决用例 1,但导出包和 cmake 配置/目标文件不正确。
add_library(A
INTERFACE)
add_library(A::A ALIAS A)
target_include_directories(A
INTERFACE "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<INSTALL_INTERFACE:include>")
target_link_libraries(A
INTERFACE "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/lib/A.so>"
"$<INSTALL_INTERFACE:A.so>"
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/lib/B.so>"
"$<INSTALL_INTERFACE:B.so>"
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/lib/C.so>"
"$<INSTALL_INTERFACE:C.so>")
#### install
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})
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include"
DESTINATION "include")
write_basic_package_version_file(AConfigVersion.cmake
VERSION "${PACKAGE_VERSION}"
COMPATIBILITY SameMajorVersion)
install(EXPORT ATargets
FILE ATargets.cmake
NAMESPACE A::
DESTINATION "lib/cmake/A")
configure_file(AConfig.cmake.in AConfig.cmake @ONLY)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/AConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/AConfigVersion.cmake"
DESTINATION "lib/cmake/A")
# Then some cpack stuff that is not affecting the work done earlier
在安装生成包(由cpack生成)后的客户端lib/cmake项目中:
find_package(A)
target_link_libraries(my_project PUBLIC/PRIVATE A::A) # Should bring in the headers and link with A B and C
文档:
https://gitlab.kitware.com/cmake/community/-/wikis/doc/tutorials/Exporting-and-Importing-Targets
是否可以将导入的库添加到 target_link_libraries 来处理包含目录?
https://discourse.cmake.org/t/exporting-packages-with-a-custom-find-module/3820/2
感谢阅读/帮助