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

cod*_*der 3 c++ shared-libraries static-libraries lib

我正在搞一个测试项目,让我们称之为它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
Run Code Online (Sandbox Code Playgroud)

到目前为止一切顺利,我的共享/静态库已创建。

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

然后我制作了另一个测试 cpp 文件usertest.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!
Run Code Online (Sandbox Code Playgroud)

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

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

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

Mik*_*han 5

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

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

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

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

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

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

/usr/local/lib是链接器的默认搜索目录之一。所以当你执行:

g++ -Wall -Werror -I. -lmytest
Run Code Online (Sandbox Code Playgroud)

在场景 (3) 中,/usr/local/lib/libmytest.a被链接器找到,但/usr/local/lib/libmytest.so不是, libmytest.a满足-lmytest并且被输入到链接。链接器对共享库的默认首选项不受影响。

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

静态库与共享库非常不同,它不是链接器生成的 ELF 二进制文件。它是 ar archive目标文件,由以下人员生成ar:它是一包恰好是目标文件的文件。

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

因此,如果 中存在N目标文件libmytest.a,则将该存档输入到链接可能会在 0 和N目标文件之间贡献到输出文件,具体取决于链接中较早产生的对该组目标文件的成员的未定义引用以及哪些目标文件提供这些参考文献的定义。

即使您确切地知道libmytest.a链接中需要哪些对象文件,您也不能断定它们的大小总和将添加到输出文件的大小中。目标文件由编译器划分为多个部分,一个部分是链接器识别的最小输入和输出单元。默认情况下,仅当输入节提供了链接器对链接必须定义的某些符号的选定定义时,链接器才会保留该输入节用于输出。如果输入节没有这样的用处,链接器将丢弃它。因此,即使链接了目标文件,链接器也可能会从输出文件中省略其中的冗余部分。

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