在 Linux 系统上使用 c++ 链接到共享库和静态库



我在搞砸一个测试项目,我们称之为mytest,它有一个.cpp和一个.h文件,内容并不重要 - 想象一下它包含一些简单的hello_world()类型函数......

因此,我正在制作一个通用的makefile来将其编译到各种库输出中,其中输出文件夹上的ls -l给出:

libmytest.a
libmytest.so -> libmytest.so.1.0
libmytest.so.1 -> libmytest.so.1.0
libmytest.so.1.0

到目前为止一切都很好,我的共享/静态库被创建出来了。

现在我的 make 文件中有一个make install目标,它基本上将标头复制到/usr/local/include并将所有这些库文件复制到/usr/local/lib

然后我制作了另一个名为usertest.cpp的测试 cpp 文件(抱歉不是很有想象力/描述性的名称),它链接到库文件。

我以各种方式编译:

  1. g++ -Wall -Werror -I. -lmytest
  2. g++ -Wall -Werror -I. -lmytest -static

然后我删除了 libmytest.so* 文件,所以我只有 libmytest.a 库文件/usr/local/lib然后我做了同样的测试:

  1. g++ -Wall -Werror -I. -lmytest
  2. g++ -Wall -Werror -I. -lmytest -static

最后,我删除了libmytest.a文件并复制回了.so文件,因此我只有 libmytest.so*库文件/usr/local/lib然后我做了同样的测试:

  1. g++ -Wall -Werror -I. -lmytest
  2. g++ -Wall -Werror -I. -lmytest -static

文件大小结果(以字节为单位)为:

1. 7736        - Makes sense, all libs dynamically linked
2. 19674488    - Makes sense, all libs statically linked
3. 64908       - hmm... not really sure why
4. 19674488    - Makes sense, same as 2.
5. 7736        - Makes sense, same as 1.
6. failed      - Makes sense, no .so files!

我有三个文件大小,小(7736)是完全动态链接的。大的是静态链接的。这个中等是什么(64908)?所以我有问题:

  • 对于 1.我假设系统首先查找 .so 库,然后查找 .a 库?
  • 对于 3.这里发生了什么?- 它是否动态链接系统库,但是当它看到我的 .a 库时,它会动态链接它?

请注意,所有输出都运行良好,并从库中调用函数。

对于 1。我假设系统首先查找 .so 库,然后查找 .a 库?

这大致正确,但请继续阅读。

对于 3.这里发生了什么?- 它是否动态链接系统库,但是当它看到我的 .a 库时,它会动态链接它?

静态库不能动态链接:它是静态链接的。共享(=动态)系统库是链接的, 假设链接器找到并首选的系统库实际上是共享库。

默认情况下,链接选项-lmytest指示链接器搜索名为libmytest.so(共享库)的输入文件 或libmytest.a(静态库),在命令行中指定的搜索目录中的第一个-Ldirname选项,按指定的顺序排列,然后按配置的顺序在其默认搜索目录中。 当它在其中一个目录中找到这些文件中的任何一个时,它会停止搜索。如果它发现它们都在 同一目录,然后选择共享库,libmytest.so.所选文件(如果有)将输入到链接中。 如果搜索不成功,链接器将给出错误:cannot find -lmytest

可以通过选项-static更改此默认行为。如果它出现在命令行中的任何位置,则链接器 忽略所有共享库:则只能通过查找libmytest.a来满足-lmytest,并且还必须找到静态系统库。

/usr/local/lib是链接器的默认搜索目录之一。因此,当您执行时:

g++ -Wall -Werror -I. -lmytest

在方案 (3) 中,链接器找到/usr/local/lib/libmytest.a/usr/local/lib/libmytest.so未找到,libmytest.a满足-lmytest,是联动的输入。链接器对共享库的默认首选项不受影响。

libmytest.a的链接对可执行文件大小的贡献并不明显。

静态库 - 与共享库完全不同 - 不是链接器生成的 ELF 二进制文件。是的ar archive目标文件,由ar生成:它是一个文件袋 恰好是目标文件。

默认情况下,当ar存档输入到链接器时,它会在包中查找任何对象文件 为已从对象文件生成的任何未定义的符号引用提供定义 检查存档时链接到输出文件(程序或共享库)。如果找到任何 这样的目标文件,它从存档中提取它们并将它们链接到输出文件中,就像它们一样 已在命令行中单独列出,而存档根本没有提及。除了作为袋子 可以选择目标文件,存档对链接没有任何贡献。

因此,如果libmytest.a中有N目标文件,将该存档输入链接可能会 将 0 到N个对象文件贡献给输出文件,具体取决于对 成员的未定义引用 该组目标文件在链接中较早生成,哪些对象文件为这些对象文件提供定义 引用。

即使您确切地知道链接中需要libmytest.a中的哪些对象文件,也无法 得出的结论是,它们的大小之和将添加到输出文件的大小中。目标文件是 由编译器划分为多个部分,部分是链接器输入和输出的最小单位 承认。默认情况下,仅当链接器提供链接器必须定义的某些符号的选定定义时,链接器才会保留该输入部分以进行输出。如果输入部分没有此类用途,则 链接器只会丢弃它。因此,即使链接了对象文件,链接器也可能省略冗余部分 在其中的输出文件中。

-l | --library链接器选项的行为记录在 2.1 命令行选项 的 GNUld手册

最有可能libmytest.a

不是在二进制大小增加中起主要作用的人,而是更大的标准库(这解释了为什么大小在3中没有增长太多)。

您可以使用ldd调查二进制文件的所有动态依赖项:

ldd a.out

(以及使用-static后哪些消失了)。

最新更新