CMake 导出依赖于外部库的包

CMake export package that relies on external library

本文关键字:外部 依赖于 CMake      更新时间:2023-10-16

我有一个使用 C++ 和 CMake 编写的项目,使用 Boost,我正在尝试制作一个独立的二进制/标头包,以允许其他人链接到我的工作。我为此使用 cmake 安装程序。但是,当我的库链接到外部库时,我遇到了install(EXPORTS ...)问题。特别是,Boost 库和标头目录位置被硬编码到导出的文件中,我不知道如何让它更好地工作。

举个例子。(未经测试;如果不清楚,我可以详细说明或修复它。

CMakeLists.txt:

package(MyLibrary)
set(MyLibrary_VERSION 1.0)
find_component(BOOST 1.55.0 REQUIRED COMPONENTS serialization)
set(INSTALL_INCLUDE_DIR "C:/MyLibrary/include")
set(INSTALL_SRC_DIR "C:/MyLibrary/include")
set(INSTALL_BIN_DIR "C:/MyLibrary/bin")
set(INSTALL_LIB_DIR "C:/MyLibrary/lib")
set(INSTALL_CMAKE_DIR "C:/MyLibrary/cmake")
set(HEADERS myfile.hpp)
set(SOURCES myfile.cpp)
install(FILES ${HEADERS} DESTINATION ${INSTALL_INCLUDE_DIR} COMPONENT headers)
install(FILES ${SOURCES} DESTINATION ${INSTALL_SRC_DIR} COMPONENT sources)
add_library(MyLibrary STATIC
    ${HEADERS} ${SOURCES})
target_link_libraries(MyLibrary
    ${Boost_SERIALIZATION_LIBRARY})
target_include_directories(MyLibrary
    PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR};${Boost_INCLUDE_DIRS}>"
    PUBLIC "$<INSTALL_INTERFACE:include;${Boost_INCLUDE_DIRS}>")

install(TARGETS MyLibrary EXPORT MyLibrary-depends
    DESTINATION ${INSTALL_LIB_DIR} COMPONENT libraries)
configure_package_config_file(MyLibraryConfig.cmake.in
    "${CMAKE_CURRENT_BINARY_DIR}/MyLibraryConfig.cmake" 
    INSTALL_DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/MyLibraryConfigVersion.cmake" 
    VERSION ${MyLibrary_VERSION}
    COMPATIBILITY AnyNewerVersion)
install(FILES
    "${CMAKE_CURRENT_BINARY_DIR}/MyLibraryConfig.cmake"
    "${CMAKE_CURRENT_BINARY_DIR}/MyLibraryConfigVersion.cmake"
    DESTINATION "${INSTALL_CMAKE_DIR}")
install(EXPORT MyLibrary-depends
    FILE MyLibrary-depends.cmake
    DESTINATION "${INSTALL_CMAKE_DIR}")

MyLibraryConfig.cmake.in

@PACKAGE_INIT@
if (NOT MyLibrary_FOUND)
    set(MyLibrary_FOUND 1)
    find_package(Boost 1.55.0 COMPONENTS SERIALIZATION)
    include(MyLibrary-depends.cmake)
    # random directory stuff, etc.
endif()

问题是MyProject-depends.cmake最终得到的值 ${Boost_INCLUDE_DIRS}${Boost_SERIALIZATION_LIBRARY} ,这都是绝对路径,并且破坏了安装的可移植性。


我尝试了几件事,似乎没有一件能解决我所有的问题。

target_include_directories

我尝试转义$,希望MyProject-depends.cmake能在包含时间内获取Boost_INCLUDE_DIRS变量的值:

target_include_directories(MyProject
    PUBLIC "$<INSTALL_INTERFACE:include;${Boost_INCLUDE_DIRS}>"
    ...)

但是,当然,INSTALL_INTERFACE认为${Boost_INCLUDE_DIRS}是一条相对路径,并以此为前缀,{$_IMPORT_DIR}破坏一切。

我可以完全放弃MyProject-depends.cmake路线,并将其添加到MyProjectConfig.cmake.in

CMakeLists.txt:

target_include_directories(MyProject
    PUBLIC "$<INSTALL_INTERFACE:include>"
    PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR};${Boost_INCLUDE_DIRS>")

和 MyProjectConfig.cmake.in:

include(MyProject-depends.cmake)
set_target_properties(MyProject
    INTERFACE_INCLUDE_DIRECTORIES "${Boost_INCLUDE_DIRS}")

这个选项似乎有效,但很痛苦。


target_link_libraries

我在库链接方面遇到了更多麻烦。我尝试了同样的技巧,将内容移动到MyProjectConfig.cmake.in文件中以进行更多控制,但是

target_link_libraries(MyProject ${Boost_SERIALIZATION_LIBRARIES})

不适用于导入的库,并且

set_target_properties(MyProject INTERFACE_LINK_LIBRARIES ${Boost_SERIALIZATION_LIBRARY})

失败是因为${Boost_SERIALIZATION_LIBRARY}扩展到类似 optimized;C:/boost/stage/lib/boost_serialization.lib;debug;C:/boost/stage/lib/boost_serialization.libd 的内容,而set_target_properties不喜欢这些关键字。

现在我留下了某种重新映射

"$<$<CONFIG:DEBUG>:${Boost_SERIALIZATION_LIBRARY_DEBUG}>$;<$<CONFIG:RELEASE>:${Boost_SERIALIZATION_LIBRARY_RELEASE}>"

但我还必须检测是否指定了调试库......这是可行的,但对我来说似乎是牦牛剃须。

所以,堆栈的圣贤...有什么建议吗?是否有一些明显的模块或聪明的方法被我忽略了?(并感谢您一路走来!


另外:cmake install(EXPORTS ...)文档包含有用的行"如果库目标包含在导出中,但不包括它链接到的目标,则未指定行为。是的,基本上,我正在寻找解决方法。

我最终得到了最后一个target_link_libraries答案,完全放弃了内置的导入结构,并编写了CMake模块来重新映射

optimized;C:/boost/stage/lib/boost_serialization.lib;debug;C:/boost/stage/lib/boost_serialization.libd

$<$<CONFIG:DEBUG>:${Boost_SERIALIZATION_LIBRARY_DEBUG}>$;<$<CONFIG:RELEASE>:${Boost_SERIALIZATION_LIBRARY_RELEASE}>

一点也不漂亮,但这是我能想到的最好的。就这样过去了。