g ++:静态和动态库应该以什么顺序链接?

时间:2009-01-29 16:31:08

标签: c++ linker shared-libraries static-libraries dynamic-linking

假设我们有一个名为“my_app”的主要可执行文件,它使用了其他几个库:3个库是静态链接的,其他3个是动态链接的。 它们应该以哪种顺序与“my_app”链接?

但是这些应该以哪种顺序联系起来?

假设我们有libSA(如在静态A中)依赖于libSB,而libSC依赖于libSB:

libSA -> libSB -> libSC

和三个动态库:libDA -> libDB -> libDClibDA是基本的,libDC是最高的)

这些链接的顺序是什么?最基本的还是最后一个?

g++ ... -g libSA libSB libSC -lDA -lDB -lDC -o my_app

似乎是当前的顺序,但是这样吗?如果任何动态库与静态库或其他方式之间存在依赖关系,该怎么办?

5 个答案:

答案 0 :(得分:26)

在静态情况下,它并不重要,因为您实际上并没有链接静态库 - 您只需将一些目标文件打包在一个存档中。您只需编译目标文件,就可以立即创建静态库。

动态库的情况更复杂,有两个方面:

  1. 共享库的工作方式与静态库完全相同(共享段除外,如果它们存在),这意味着,您也可以这样做 - 只需链接您的共享库即可目标文件。这意味着例如来自libDA的符号在libDB中将显示为未定义

  2. 链接共享对象时,可以在命令行上指定要链接的库。这与1具有相同的效果,但是,将libDB标记为需要libDA。

  3. 不同之处在于,如果使用前一种方式,则必须在链接可执行文件时在命令行上指定所有三个库(-lDA,-lDB,-lDC)。如果您使用后者,则只需指定-lDC,它将在链接时自动提取其他内容。请注意,链接时间就在程序运行之前(这意味着您可以获得不同版本的符号,即使是来自不同的库)。

    这一切都适用于UNIX; Windows DLL的工作方式完全不同。

    在澄清问题后编辑:

    来自ld信息手册。

      

    链接器仅搜索存档   一次,在它所在的位置   在命令行上指定。如果   archive定义了一个符号   在某些对象中未定义   出现在档案馆之前   命令行,链接器将包含   来自的相应文件   存档。但是,一个未定义的符号   在后来出现的对象中   命令行不会导致链接器   再次搜索档案。

         

    请参阅` - ('选项以获取强制方法   链接器搜索多个存档   次。

         

    您可以列出相同的存档倍数   命令行上的次数。

         

    这种类型的档案搜索是   Unix链接器的标准。但是,如果   你在AIX上使用`ld',请注意   它与行为不同   AIX链接器。

    这意味着:

    依赖于其他库的任何静态库或对象都应放在命令行之前。如果静态库循环相互依赖,您可以例如。使用-(命令行选项,或将库放在命令行上两次(-lDA -lDB -lDA)。动态库的顺序无关紧要。

答案 1 :(得分:24)

这是一个通过一个简单的例子最好解决的问题。真!花2分钟,编写一个简单的例子,然后尝试一下!你会学到一些东西,而且比求问要快。

例如,给定文件:

a1.cc

#include <stdio.h>
void a1() { printf("a1\n"); }

a2.cc

#include <stdio.h>
extern void a1();
void a2() { printf("a2\n");  a1(); }

a3.cc

#include <stdio.h>
extern void a2();
void a3() { printf("a3\n"); a2(); }

aa.cc

extern void a3();
int main()
{
  a3();
}

运行:

g++ -Wall -g -c a1.cc
g++ -Wall -g -c a2.cc
g++ -Wall -g -c a3.cc
ar -r liba1.a a1.o
ar -r liba2.a a2.o
ar -r liba3.a a3.o
g++ -Wall -g aa.cc -o aa -la1 -la2 -la3 -L.

节目:

./liba3.a(a3.o)(.text+0x14): In function `a3()':
/tmp/z/a3.C:4: undefined reference to `a2()'

鉴于:

g++ -Wall -g -c a1.C
g++ -Wall -g -c a2.C
g++ -Wall -g -c a3.C
ar -r liba1.a a1.o
ar -r liba2.a a2.o
ar -r liba3.a a3.o
g++ -Wall -g aa.C -o aa -la3 -la2 -la1 -L.

成功。 (只是改变了-la3 -la2 -la1参数顺序。)

PS:

nm --demangle liba*.a

liba1.a:
a1.o:
                 U __gxx_personality_v0
                 U printf
0000000000000000 T a1()

liba2.a:
a2.o:
                 U __gxx_personality_v0
                 U printf
                 U a1()
0000000000000000 T a2()

liba3.a:
a3.o:
                 U __gxx_personality_v0
                 U printf
                 U a2()
0000000000000000 T a3()

来自 man nm

  • 如果是小写,则符号为本地符号;如果是大写,则符号为全局(外部)。

  • “T”符号位于文本(代码)部分。

  • “U”符号未定义。

答案 2 :(得分:2)

我参与了一个项目,其中包含许多内部库,不幸的是彼此依赖(随着时间的推移它变得更糟)。我们最终通过设置SCons来解决这个问题,以便在链接时指定所有的lib两次:

g++ ... -la1 -la2 -la3 -la1 -la2 -la3 ...

答案 3 :(得分:0)

链接库或可执行文件的依赖项必须在链接时出现,因此在libXB出现之前无法链接libXC。静态或动态无关紧要。

从最基本的一个开始,它没有(或只是你的项目之外)依赖。

答案 4 :(得分:0)

保持库彼此独立以避免链接顺序问题是一种很好的做法。