>背景我有一个使用其他较小项目的项目。这些项目本身是由其他项目组成的。其中很多是遗留的,或者有其他管理法令的原因按原样安排,因此将所有内容整合到一个项目中不是一种选择。某些库是在远程共享上预编译的。
我有两个主要的子项目让我头疼:
-
Project Foo是一个可执行文件和库,它链接了几个静态子项目(
foo_subproject_1
,foo_subproject_n
)。这些子项目进一步链接到远程位置的静态库(some_lib
,some_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 (实际上)将bar
与foo_subproject_*
库链接,因为这些库被"链接"(在 CMake 意义上)到foo_lib
中。同样,最后一个"链接"仅对 CMake 有意义:文件foo_lib.a
不知道需要foo_subproject_*
库。
Tsyvarev的回答很好地描述了我实际在做什么(而不是我认为我在做什么),让我查找正确的东西来回答我的根本问题("为什么foo_runtime工作,但bar_runtime不起作用,当两个链接都链接到静态库时?
来自 CMake 文档的target_link_libraries:
默认情况下,使用此签名,库依赖项是可传递的。当此目标链接到另一个目标时,链接到此目标的库也将出现在另一个目标的链接行上。
target_link_libraries不会导致静态库中的链接foo_subproject_1
和foo_subproject_2
(静态库不调用链接器)。它的作用是使所需库的列表可用于任何尝试与foo_subproject_1
或foo_subproject_2
链接
的内容因此,实际上,就CMake而言,我的foo_runtime
和foo_lib
target_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基本上是空的">