使用 CMake 与其他静态库链接的静态库 - 一个有效,一个无效。为什么?



>背景我有一个使用其他较小项目的项目。这些项目本身是由其他项目组成的。其中很多是遗留的,或者有其他管理法令的原因按原样安排,因此将所有内容整合到一个项目中不是一种选择。某些库是在远程共享上预编译的。

我有两个主要的子项目让我头疼:

  • Project Foo是一个可执行文件和库,它链接了几个静态子项目(foo_subproject_1foo_subproject_n)。这些子项目进一步链接到远程位置的静态库(some_libsome_other_lib)。Project Foo 的可执行文件可以正确编译、链接和运行

  • Project Bar是一个可执行文件,它链接了其他几个项目,包括libFoo。链接失败,"未定义引用"foo_subproject函数

据我所知,这两个项目的排列方式与其链接说明相似。查看 SO,我发现将静态库链接到静态库应该不起作用,但随后我对 Foo 项目如何成功编译感到困惑。

gcc 和 g++ 4.9.2 是编译器(外部"C"问题,其中一些部分在 C 中,一些部分在 C++ 中已经检查过)


问题

我对 CMake add_subdirectory 的工作原理或链接器的工作原理产生了误解。有人可以解释一下 Foo 项目是如何成功工作的,以及项目栏(不)按预期工作吗?

更新我仔细看了看foo_lib.a和foo_runtime。

我应该确定一开始就有些不对劲,因为foo_runtime的大小接近 100MB,而foo_lib只有 10KB。

nm显示,foo_lib.a引用了几十个符号,其中大多数是未定义的。 foo_runtime同时引用了一切

同样令人困惑的是,foo_subproject_1.a同样大多是未定义的。同样,这是我期望看到的;但我不明白如何从中构建foo_runtime?

我仍然不清楚为什么some_library -> subproject -> foo_runtime成功,但some_library -> subproject -> foo_lib -> bar不是。在调查的这个阶段,我预计这两个命令都会失败。


Foo项目(使用CMake)是这样安排的:

cmake_minimum_required(VERSION 2.6)
project(foo)
set(FOO_SRCS
# source and headers for main foo project
)
# Project Foo libraries are subdirectories within this project
add_subdirectory(subs/foo_subproject_1)
add_subdirectory(subs/foo_subproject_2)
# Runtime executable
add_executable(foo_runtime main.c ${FOO_SRCS})
target_link_libraries(foo_runtime foo_subproject_1 foo_subproject_2)
# Library version (static library)
add_library(foo_lib STATIC ${FOO_SRCS})
target_link_libraries(foo_lib foo_subproject_1 foo_subproject_2)

Project Foo 的子目录松散地具有以下体系结构:

cmake_minimum_required(VERSION 2.6)
project(foo_subproject_<n>)
set(FOO_SUBPROJECT_<N>_SRCS
# source and headers for subproject
)
# foo_subproject's remote libraries are all static
add_library(some_lib STATIC IMPORTED)
set_target_properties(some_lib PROPERTIES IMPORTED_LOCATION /path/to/libsome_lib.a)
add_library(some_other_lib STATIC IMPORTED)
set_target_properties(some_other_lib PROPERTIES IMPORTED_LOCATION /path/to/libsome_other_lib.a)
include_directories(/paths/to/libs/include/)
# Static library for foo_subproject_N, links against static libs above
add_library(foo_subproject_<N> STATIC ${FOO_SUBPROJECT_<N>_SRCS})
target_link_libraries(foo_subproject_<N> some_library some_other_library)

项目栏的排列方式如下:

cmake_minimum_required(VERSION 2.6)
project(bar)
set(BAR_SRCS
# source and headers for main bar project
)
# Project Bar libraries are remote from Bar's perspective
add_library(foo_lib STATIC IMPORTED)
set_target_properties(foo_lib PROPERTIES IMPORTED_LOCATION /path/to/foo/libfoo_lib.a)
include_directories(/path/to/foo/include/)
# Runtime executable
add_executable(bar main.c ${BAR_SRCS} foo_lib)

项目栏无法链接(编译正常),并出现以下形式的多个错误:

bar_frobulator.cpp:123: undefined reference to 'foo_subproject_1_init_frobulation'

foo_subproject_1_init_frobulation住在foo_subproject_1的地方

有人可以解释一下 Foo 项目如何成功工作,以及项目栏(不)按预期工作吗?

简而言之:创建静态库不涉及链接步骤!

在Foo项目中,你有一个可执行foo_runtime,它"工作",因为它与适当的库链接(例如,与定义foo_subproject_1_init_frobulation符号的库foo_subproject_1链接)。

来自 Bar 项目的可执行bar不执行该链接,因此会失败。该行

target_link_libraries(bar foo_lib)

foo_lib的链接,但此库没有定义所需的符号foo_subproject_1_init_frobulation

注意,该行

target_link_libraries(foo_lib foo_subproject_1 foo_subproject_2)

在Foo项目中不执行实际的链接:通常,构建静态库不涉及链接步骤。

给定的行只是包含目录(和其他编译功能)从foo_subproject_*库传播到foo_lib库。

如何使其工作

由于静态库foo_lib不跟踪其依赖项,因此您需要将bar链接到知道这一点的库。 例如,共享foo_lib,或将foo_subproject_*库合并到存档库中,如引用的问题如何将多个 C/C++ 库合并为一个?。

或者,您可以在一个子项目中生成Foo子项目Bar而不是创建 IMPORTfoo_lib目标,而是使用在项目中创建的"普通"foo_lib目标Foo。在这种情况下,行

target_link_libraries(bar foo_lib)

意味着 CMake (实际上)将barfoo_subproject_*库链接,因为这些库被"链接"(在 CMake 意义上)到foo_lib中。同样,最后一个"链接"仅对 CMake 有意义:文件foo_lib.a不知道需要foo_subproject_*库。

Tsyvarev的回答很好地描述了我实际在做什么(而不是我认为我在做什么),让我查找正确的东西来回答我的根本问题("为什么foo_runtime工作,但bar_runtime不起作用,当两个链接都链接到静态库时?

来自 CMake 文档的target_link_libraries:

默认情况下,使用此签名,库依赖项是可传递的。当此目标链接到另一个目标时,链接到此目标的库也将出现在另一个目标的链接行上。

target_link_libraries不会导致静态库中的链接foo_subproject_1foo_subproject_2(静态库不调用链接器)。它的作用是使所需库的列表可用于任何尝试与foo_subproject_1foo_subproject_2链接

的内容因此,实际上,就CMake而言,我的foo_runtimefoo_libtarget_link_libraries命令是:

target_link_libraries(foo_runtime foo_subproject_1 some_library some_other_library foo_subproject_2 some_library some_other_library)
target_link_libraries(foo_lib foo_subproject_1 some_library some_other_library foo_subproject_2 some_library some_other_library)

foo_lib是静态的,不会调用链接器foo_runtime,作为一个可执行文件,确实如此。

bar是一个完全不同的项目,因此无法利用传递依赖项(并且链接失败,因为我缺少较低级别库中的所有符号)。

这种target_link_libraries行为是意料之外的,因为整个项目的行为有点误导(因为它看起来像我在子项目级别捆绑了一堆库,然后在上层捆绑了这些库。实际上,我刚刚告诉上层它需要的所有库是什么)。

去夏天:

:"为什么foo_runtime工作,而bar_runtime却不起作用,当两个链接都链接到静态库链接的静态库时?

"foo_runtime不是链接到静态库链接的静态库。foo_runtime链接到的静态库比您最初认为的要多。

bar_runtime不起作用,因为你的foo_lib基本上是空的">

最新更新