静态库通过CMake与其他静态库链接-一种有效,一种无效。为什么?

Kid*_*ris 5 c++ linker g++ cmake

背景 我有一个使用其他较小项目的项目。这些项目本身由其他项目组成。其中很多是遗留的,或者按原样安排还有其他管理上的原因,因此将所有内容都滚动到单个项目中是不可行的。有些库已在远程共享上进行了预编译。

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

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

  • Project Bar是可执行文件,可链接其他几个项目,包括libFoo。链接失败,并带有“对foo_subproject函数的未定义引用”

据我所知,这两个项目的链接说明相似。从SO的角度来看,我发现将静态库与静态库链接不起作用,但是对于如何成功编译Project Foo感到困惑。

gcc和g ++ 4.9.2是编译器(已经检查了C中有某些部分,C ++中有一些部分的外部“ C”问题)


我对CMake add_subdirectory的工作方式或链接程序的工作方式或两者都有误解。有人可以解释一下Foo项目是如何成功工作的,而Project Bar(不是)是按预期的工作方式吗?

更新我仔细看了看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)
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

项目栏就这样排列:

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)
Run Code Online (Sandbox Code Playgroud)

Project Bar无法链接(编译成功)并出现以下形式的多个错误:

bar_frobulator.cpp:123: undefined reference to 'foo_subproject_1_init_frobulation'
Run Code Online (Sandbox Code Playgroud)

其中,foo_subproject_1_init_frobulation住在foo_subproject_1

Tsy*_*rev 5

有人可以解释一下Foo项目是如何成功工作的,而Project Bar(不是)是按预期的工作方式吗?

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

细节

在Foo项目中,您有一个可执行文件foo_runtime,之所以“有效”是因为它与适当的库(例如foo_subproject_1,定义foo_subproject_1_init_frobulation符号的库)链接。

barBar项目中的可执行文件不会执行该链接,因此会失败。线

target_link_libraries(bar foo_lib)
Run Code Online (Sandbox Code Playgroud)

与链接foo_lib,但此库未定义所需的符号foo_subproject_1_init_frobulation

注意,那行

target_link_libraries(foo_lib foo_subproject_1 foo_subproject_2)
Run Code Online (Sandbox Code Playgroud)

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

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

如何运作

由于静态库foo_lib不会跟踪其依赖关系,因此您需要链接bar一个知道这一点的库。例如,如参考问题所述,建议foo_libfoo_subproject_*库共享或合并到存档库中如何将多个C / C ++库合并到一个库中?

或者,您可以FooBar一个项目中构建子项目,而不foo_lib使用foo_lib创建Foo项目中创建的“正常” 目标来代替创建导入目标。在这种情况下,

target_link_libraries(bar foo_lib)
Run Code Online (Sandbox Code Playgroud)

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