使用父库安装预构建的静态库依赖项

Install prebuilt static library dependency with the parent library

我的项目结构如下所示:

Parent/
    CMakeLists.txt
    file.cpp
    third_party/
        dependency/
            CMakeLists.txt
            lib/
                dependency.lib

请注意 dependency.lib 是一个 precompiled/prebuilt 库:我什至没有它的资源。

当我安装 Parent 时,我希望它像这样进入 dist 文件夹(在之前的树结构中,但为清楚起见省略):

Parent/
    dist/
        Parent/
            include/
            bin/
            lib/
                cmake/
                    ParentTargets.cmake
                Parent.lib
                dependency.lib

这里的想法是将生成的库和依赖库都放在一个地方以便于安装。

Parent CMakeLists.txt 的相关部分如下所示(省略了很多内容,例如包含等):

cmake_minimum_required(VERSION 3.22)
project(Parent VERSION 0.1.0 LANGUAGES C CXX)
add_library(Parent)

target_sources(Parent PRIVATE file.cpp)

add_subdirectory("${CMAKE_SOURCE_DIR}/third_party/dependency")
target_link_libraries(Parent PRIVATE dependency)

# Manual copy of dependency.lib to install location
install(DIRECTORY "${CMAKE_SOURCE_DIR}/third_party/dependency/lib/"
    DESTINATION lib
    FILES_MATCHING
    PATTERN "dependency.lib"
)

# Install all targets to ParentTargets export set.
# (omitting install dir variables, components, etc. for clarity)
install(
    TARGETS
        Parent dependency
    EXPORT
        ParentTargets
    LIBRARY
        DESTINATION lib
    ARCHIVE
        DESTINATION lib
)

# Write ParentTargets export set to targets file directly in install folder
install(EXPORT ParentTargets
    FILE ParentTargets.cmake
    NAMESPACE Parent::
    DESTINATION lib/cmake
)

这就是我对依赖项的 CMakeLists.txt:

add_library(dependency INTERFACE)
target_link_libraries(dependency
    INTERFACE
        $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/lib/dependency.lib>
        $<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/lib/dependency.lib>
)

这几乎是可行的,问题是如果您查看生成的 ParentTargets.cmake,这就是 CMake 为 dependency 目标生成的内容:

# Create imported target Parent::dependency
add_library(Parent::dependency INTERFACE IMPORTED)

set_target_properties(Parent::dependency PROPERTIES
  INTERFACE_LINK_LIBRARIES "E:/absolute/path/Parent/dist/Parent/lib/dependency.lib"
)

...它是我的安装目录的硬编码绝对路径。这不是很好,通常对于构建的库,CMake 会生成类似 ${_IMPORT_PREFIX}/lib/dependency.lib 的路径,这是我想要的,并且对于安装可重定位很重要。

这是我的问题:

  1. 这样做正确吗?我永远找不到关于如何将依赖静态库与项目一起打包的很好的参考,而且 CMake 似乎并没有太急切地“自行”执行此操作(我什至不得不手动复制 .lib,如您所见) ;
  2. 如何让 CMake 在那里使用 ${_IMPORT_PREFIX}?我不能只在我的 CMakeLists.txt 上使用它,因为它会在生成期间评估为空字符串,而且我不能像 ${_IMPORT_PREFIX} 那样转义它,因为它仍然将转义版本放在 ParentTargets.cmake...

Is this the right way of doing this? I could never find a good reference on how to package dependency static libraries alongside your project, and CMake doesn't seem to do this "on its own" too eagerly (I even had to manually copy the .lib there as you can see);

我认为你所做的很好。如果是我,我会在主构建和包配置文件中为 dependency.lib 创建并 link 到名为 Parent::ThirdParty::dependencyIMPORTED STATIC 目标,并设置其 IMPORTED_LOCATION 属性 每个都合适。

原因是 CMake 将验证您 link 名称中包含 :: 的任何内容都是 CMake 目标。这往往会减少 link 行上的意外情况,并允许您将诸如包含路径之类的内容附加到库中。

How do I get CMake to use ${_IMPORT_PREFIX} there? [...]

您的问题在这里:

$<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/lib/dependency.lib>

CMAKE_INSTALL_PREFIX 设置为 E:/absolute/path/Parent/dist/Parent 立即 并且 CMake 没有机会用 ${_IMPORT_PREFIX} 之类的东西替换它。幸运的是,有一个生成器表达式。

$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/lib/dependency.lib>

试试看。