背景 我有一个使用其他较小项目的项目。这些项目本身由其他项目组成。其中很多是遗留的,或者按原样安排还有其他管理上的原因,因此将所有内容都滚动到单个项目中是不可行的。有些库是在远程共享上预编译的。
我有2个主要的子项目让我头疼:
Project Foo 是一个可执行文件和库,它链接了几个静态子项目(foo_subproject_1
,foo_subproject_n
)。这些子项目还与远程位置(some_lib
,some_other_lib
)的静态库链接。 Project Foo的可执行文件正确编译,链接并运行
项目栏是一个可执行文件,可以链接几个其他项目,包括libFoo。链接失败,原因是“未定义对foo_subproject
个函数的引用
据我所知,这两个项目的排列方式与它们的链接说明相似。如此看来,我发现将静态库与静态库shouldn't work链接起来,但是对于Project Foo如何成功编译感到困惑。
gcc和g ++ 4.9.2是编译器(已经在C中包含某些部分,而在C ++中具有某些部分的外部“ C”问题)
问题
我对CMake add_sub目录的工作方式或链接器的工作方式误解了一个或两个。有人可以解释一下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)
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)
Project Bar无法链接(编译成功)并出现以下形式的多个错误:
bar_frobulator.cpp:123: undefined reference to 'foo_subproject_1_init_frobulation'
foo_subproject_1_init_frobulation
居住在foo_subproject_1中的地方
答案 0 :(得分:3)
有人可以解释一下Foo项目是如何成功工作的,而Project Bar(不是)是按预期工作的吗?
简而言之:创建STATIC库不涉及链接步骤!
在Foo项目中,您有一个可执行文件foo_runtime
之所以有效,是因为它与适当的库(例如,与定义了foo_subproject_1
符号的库foo_subproject_1_init_frobulation
链接在一起)。
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
与已知的库链接。例如,根据参考问题How to combine several C/C++ libraries into one?的建议,共享foo_lib
或将foo_subproject_*
个库合并到存档库中。
或者,您可以在一个Foo
内构建Bar
子项目,而不是创建在{{}中创建的“正常” foo_lib
目标,而不要创建导入的foo_lib
目标。 1}}项目。在这种情况下,第
Foo
对于CMake而言,实际上意味着将target_link_libraries(bar foo_lib)
与bar
库链接起来,因为这些库是从CMake的意义上“链接”到foo_subproject_*
中的。同样,最后的“链接”仅对CMake有意义:文件foo_lib
并不知道需要foo_lib.a
库。
答案 1 :(得分:0)
Tsyvarev的答案描述得足够好,足以说明我的实际问题(而不是我以为我在做的事情),让我可以找到正确的答案来回答我的根本问题(“为什么foo_runtime可以工作,而bar_runtime却不能工作't,当两个链接都指向静态库时,链接到静态库了吗?”)
来自the CMake documentation for 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的这种行为,因为整个项目的这种行为在某种程度上具有误导性(因为看起来我在子项目级别捆绑了一堆库,然后在上级捆绑了这些库实际上,我只是告诉上层它需要的所有库是什么。
要总结:
Q “当两个链接都链接到静态库时,为什么foo_runtime起作用而bar_runtime却不起作用?”
A “ foo_runtime未链接到与静态库链接的静态库。foo_runtime被链接到的静态库比您原来认为的要多。
bar_runtime不起作用,因为您的foo_lib基本为空”