【问题标题】:CMake static library dependencies not propagating with ExternalProject_AddCMake 静态库依赖项不随 ExternalProject_Add 传播
【发布时间】:2015-01-30 16:58:20
【问题描述】:

我目前正在尝试让可执行文件与它所需的所有依赖项正确链接。

这是一个依赖结构的示例:

exe -> libA -> libB

exelibA 有自己的存储库。 exe 拉入 libA 是这样的:

add_executable(exe ${sources})

ExternalProject_Add(
    libA
    GIT_REPOSITORY http://some/git/url/libA.git
    ...
)

target_include_directories(exe PRIVATE ${libA_includes})
target_link_libraries(exe ${libA_libs}/libA.a)

add_dependencies(exe libA)

libA 以类似的方式拉入libB

add_library(libA STATIC ${sources})

ExternalProject_Add(
    libB
    URL http://some/artifact/repo/libB.tgz
    ...
)

target_include_directories(libA PRIVATE ${libB_includes})
target_link_libraries(libA ${libB_libs}/libB.a)

add_dependencies(libA libB)

我可以很好地构建libA,以及与libB 正确链接的测试可执行文件。但是,当我尝试构建 exe 时,它只链接到 libA 而不是 libB。如何让 CMake 知道 libAlibB 之间的依赖关系不应该通过 ExternalProject 丢失?

编辑:

我创建了一些依赖关系图,希望能阐明我想要什么:

实际:

我的期望:

任何帮助将不胜感激。谢谢。

编辑 2:

我最终使用以下解决方案:

在 libA 的 CMakeLists.txt 中(${MODULE_NAME} 是 libA 中某个模块的名称):

export(TARGETS ${MODULE_NAME}
       NAMESPACE "${CMAKE_PROJECT_NAME}-"
       APPEND FILE ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}-targets.cmake)

在exe的CMakeLists.txt中:

ExternalProject_Add(
    libA ...
)

ExternalProject_Get_Property(libA source_dir)
ExternalProject_Get_Property(libA binary_dir)

target_include_directories(${PROJECT_NAME} PRIVATE ${source_dir})

set(LIBA_TARGETS_FILE ${binary_dir}/libA-targets.cmake)
if(EXISTS ${LIBA_TARGETS_FILE})
    include(${LIBA_TARGETS_FILE})
    target_link_libraries(${MODULE_NAME} libA-module_in_liba)
endif()

add_dependencies(${MODULE_NAME} libA)

注意:这确实需要使用两次运行 cmake 来构建项目,如下所示:

mkdir build; cd build
cmake .. # initial configuration
make # download the external projects
cmake .. # be able to include targets cmake file from external projects
make # this should now link everything properly

【问题讨论】:

  • 我在下面的回答是没有看到图表 :-) 但我想我明白了。

标签: c linker cmake


【解决方案1】:

据我所知,没有办法通过使用单个配置运行和 ExternalProject 功能来实现您想要做的事情。您似乎只是使用${libA_libs}/libA.a,当然没有任何进一步的信息。由于项目 libA 和 libB 可能来自完全不同的供应商,因此无法在配置时从您的主项目中判断 LibA 甚至包含链接依赖项 libB(偶然也包含在 libA 中)。

我将假设您想要使用传递链接的(相当自然的)想法。 根据您是否自己开发 libA/libB,有不同的选择。我将解释这样做的“最干净”的方式。缺点是这也需要修改 libA 项目 cmake。 [如果您不能这样做,则需要手动将 libB.a 添加为硬编码的链接库;即解决传递性..对不起!]

传递链接的关键是您需要导入由CMake在libA中创建的实际目标,然后将target_link_libraries信息正确地传递给libB,一切都会起作用。 libA 的目标配置可以使用 cmake 中的 INSTALL(.. EXPORT ) 功能提供,然后您可以使用 find_package(LIBA CONFIG) 导入目标。那么,你的 exe CMakeLists.txt 应该看起来像

find_package(LIBA CONFIG QUIET)
if (NOT LIBA_FOUND)
    AddExternalProject(libA .....)
    return
else()
    add_executable(exe ${sources})
    target_link_libraries(exe <libA-target-name>)

这将在链接时包含 libB 并设置正确的包含路径(如果在 target_include_directories(libA PUBLIC ${LIBA_INCDIR}.. 中定义了 PUBLIC)

关键问题是在相同的配置运行中添加一个外部项目当然不能产生将由 find_package 设置的所有内容,因为尚未编译/安装任何内容。外部项目背后的想法是,您告诉它在哪里放置东西,以便您随后知道应该在哪里找到东西,但不幸的是,这永远不会包括链接库之类的传递性东西。

有(一如既往)更快和更肮脏的解决方案,但是,模块化包并通过 find_package 在 CONFIG 模式下将它们作为目标提供的“新” cmake 方式是将支持 cmake 的项目包含到的最佳且简单的方式彼此。

【讨论】:

  • 我已将我使用的解决方案添加到原始问题中,但它基于此答案。
  • 嘿!这似乎可行,虽然它有“脏”的感觉 :-) 我只是偶然发现了导出命令的“EXPORT_LINK_INTERFACE_LIBRARIES”标志;因为您一直在 libA CMakeLists.txt 中插入东西,所以可能尝试插入它并查看导出的配置文件?!
  • 不幸的是,由于我们的构建服务器,我只能使用 CMake 2.8.11,我认为该标志是在 2.8.12 中添加的。我在本地试了一下,没有发现任何区别。
  • 是什么让你觉得它很脏?为了让 find_package 正常工作,我想我遗漏了一些东西。
  • 脏因为:如果你正确地导入一个目标,任何公共的包含目录都将被使用,而无需编写一行代码。另外,直接包含 XXx-targets.cmake 文件不是您应该做的。相反,将 find_package 与 CMAKE_PREFIX_PATH 结合使用,让它查看这些文件的 libA 的导出位置。导出配置的命名约定有些不精确,我建议使用“-config.cmake”;在此处查看文档以获取更多信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-03
  • 1970-01-01
相关资源
最近更新 更多