在 Linux 系统上使用 C++ 链接到共享库和静态库
Linking to shared and static libraries with c++ on a Linux system
我正在搞一个测试项目,我们称它为 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
目标,它基本上将 header 复制到 /usr/local/include
并将所有这些库文件复制到 /usr/local/lib
然后我制作了另一个名为 usertest.cpp
的测试 cpp 文件(对不起 not-very-imaginative/descriptive 名称),它链接到库文件。
我通过各种方式编译:
g++ -Wall -Werror -I. -lmytest
g++ -Wall -Werror -I. -lmytest -static
然后我删除了libmytest.so*文件所以我在/usr/local/lib
中只有libmytest.a库文件然后我做了同样的测试:
g++ -Wall -Werror -I. -lmytest
g++ -Wall -Werror -I. -lmytest -static
最后我删除了 libmytest.a 文件并 复制回 .so 文件 所以我只有 libmytest.so* 库文件在 /usr/local/lib
然后我做了同样的测试:
g++ -Wall -Werror -I. -lmytest
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 库时,它动态链接它?
注意 所有输出 运行 正常并从库中调用函数。
很可能 libmytest.a
不是那个在二进制文件大小增加中起主要作用的人,而是更大的标准库(这解释了为什么大小在 3. 中没有增加太多)。
您可以使用 ldd
:
调查二进制文件的所有动态依赖关系
ldd a.out
(使用 -static
后它们中的哪些正在消失)。
For 1. I assume the system looks for .so libraries first and .a libraries second?
大致正确,但请继续阅读。
For 3. What happened here? - is it dynamically linking the system libs but when it sees my .a lib it dynamically links it?
静态库不能动态链接:它是静态链接的。共享(=动态)系统库是链接的,
假设链接器找到并喜欢的系统库实际上是共享库。
默认情况下,链接选项 -lmytest
指示链接器搜索名为 libmytest.so
的输入文件(共享库)
或 libmytest.a
(静态库),首先在您在命令行中指定的搜索目录中
-Ldirname
选项,按照指定的顺序,然后在其默认搜索目录中,按照配置的顺序。
当它在其中一个目录中找到这些文件中的任何一个时,它就会停止搜索。如果它发现它们都在
相同的目录,然后它选择共享库 libmytest.so
。所选文件(如果有)被输入到链接中。
如果搜索不成功,链接器会给出一个错误:cannot find -lmytest
.
此默认行为可以通过选项 -static
更改。如果它出现在命令行的任何地方,链接器
忽略所有共享库:那么-lmytest
只能找libmytest.a
满足,静态系统库也必须找
/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 Command Line Options 中
GNU ld
manual
我正在搞一个测试项目,我们称它为 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
目标,它基本上将 header 复制到 /usr/local/include
并将所有这些库文件复制到 /usr/local/lib
然后我制作了另一个名为 usertest.cpp
的测试 cpp 文件(对不起 not-very-imaginative/descriptive 名称),它链接到库文件。
我通过各种方式编译:
g++ -Wall -Werror -I. -lmytest
g++ -Wall -Werror -I. -lmytest -static
然后我删除了libmytest.so*文件所以我在/usr/local/lib
中只有libmytest.a库文件然后我做了同样的测试:
g++ -Wall -Werror -I. -lmytest
g++ -Wall -Werror -I. -lmytest -static
最后我删除了 libmytest.a 文件并 复制回 .so 文件 所以我只有 libmytest.so* 库文件在 /usr/local/lib
然后我做了同样的测试:
g++ -Wall -Werror -I. -lmytest
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 库时,它动态链接它?
注意 所有输出 运行 正常并从库中调用函数。
很可能 libmytest.a
不是那个在二进制文件大小增加中起主要作用的人,而是更大的标准库(这解释了为什么大小在 3. 中没有增加太多)。
您可以使用 ldd
:
ldd a.out
(使用 -static
后它们中的哪些正在消失)。
For 1. I assume the system looks for .so libraries first and .a libraries second?
大致正确,但请继续阅读。
For 3. What happened here? - is it dynamically linking the system libs but when it sees my .a lib it dynamically links it?
静态库不能动态链接:它是静态链接的。共享(=动态)系统库是链接的, 假设链接器找到并喜欢的系统库实际上是共享库。
默认情况下,链接选项 -lmytest
指示链接器搜索名为 libmytest.so
的输入文件(共享库)
或 libmytest.a
(静态库),首先在您在命令行中指定的搜索目录中
-Ldirname
选项,按照指定的顺序,然后在其默认搜索目录中,按照配置的顺序。
当它在其中一个目录中找到这些文件中的任何一个时,它就会停止搜索。如果它发现它们都在
相同的目录,然后它选择共享库 libmytest.so
。所选文件(如果有)被输入到链接中。
如果搜索不成功,链接器会给出一个错误:cannot find -lmytest
.
此默认行为可以通过选项 -static
更改。如果它出现在命令行的任何地方,链接器
忽略所有共享库:那么-lmytest
只能找libmytest.a
满足,静态系统库也必须找
/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 Command Line Options 中
GNU ld
manual