要使用* .o文件在c ++ / unix中创建库,我注意到我的项目中有两种不同的方式(遗留代码):
ar qc libgraphics.a *.o
ranlib libgraphics.a
和
ld -r -o libgraphics.a *.o
两种方法之间有什么区别,哪种方法用于什么目的?
答案 0 :(得分:22)
<强> AR 强>
在Linux中,ar
是GNU通用归档程序。
(在其他类Unix操作系统中有ar
的非GNU变体。使用选项c
ar c... archive-name file...
它会创建一个包含file...
副本的存档。传统上archive-name
但不一定有扩展名.a
(对于存档)。每个file...
都可以
任何类型的文件,不一定是目标文件。
当归档文件都是目标文件时,通常打算使用
存档用于将选择的目标文件传递到程序的链接中
或DSO(动态共享对象)。在这种情况下,archive-name
通常也会被赋予前缀lib
,例如
libfoo.a
,以便通过链接器选项-lfoo
将其作为候选链接器输入文件发现。
用作链接器输入文件,libfoo.a
通常称为静态库。这个
对于不熟练的程序员来说,使用是一种永久的混淆源,因为它引导着他们
认为档案libfoo.a
与DSO libfoo.so
大致相同,
通常称为动态/共享库,并对此构建错误的期望
基础。实际上是一个静态库&#34;和一个动态图书馆&#34;根本不是类似的东西
并以完全不同的方式用于联系。
一个显着的区别是链接器不会产生静态库,
但是ar
。因此没有链接发生,没有符号解析发生。存档
目标文件不变:它们只是放在一个袋子里。
当在 生成的内容的链接中输入存档时 链接器 - 例如程序或DSO - 链接器在包中查看是否存在 是其中的任何目标文件,提供未解析的符号引用的定义 在联系中早先累积的。如果找到,则从中提取这些对象文件 包和他们链接到输出文件中,就像它们被单独命名一样 在链接器命令行和根本没有提到的存档中。所以整个 归档在链接中的作用是链接器可以从中获取的目标文件包 选择它需要进行连接的那些。
默认情况下,GNU ar
使其输出存档可以用作链接器输入。它添加了一个虚假的文件&#34;
到档案馆,有一个神奇的虚假文件名,并在这个虚假文件中写入内容
链接器能够从定义的全局符号中读取查找表
由归档中的任何目标文件到这些对象的名称和位置
存档中的文件。此查找表使链接器能够查看
存档并标识定义任何未解析的符号引用的任何目标文件
它掌握在手中。
您可以使用q
(=来禁止创建或更新此查找表
快速)选项 - 实际上您已经在自己的ar
示例中使用过了 - 也是
使用(大写)S
(= 无符号表)选项。如果您调用ar
来创建或更新
由于任何原因,没有(最新的)符号表的存档,然后是你
可以使用s
选项给它一个。
<强> ranlib的强>
ranlib
没有
创建库。在Linux中,ranlib
是一个遗留程序,它添加了(uptodate)
符号表到ar
存档,如果它没有。它的效果正是如此
与ar s
相同,GNU ar
。历史上,在ar
生成之前
一个符号表本身,ranlib
是注入魔术文件的kludge
进入存档以使链接器从中选择对象文件。在非GNU中
类似Unix的操作系统,ranlib
可能仍然需要用于此目的。你的例子:
ar qc libgraphics.a *.o
ranlib libgraphics.a
表示:
libgraphics.a
个文件附加到存档来创建*.o
目录,没有符号表。libgraphics.a
在linux中,它具有与以下相同的净效果:
ar cr libgraphics.a *.o
单独使用ar qc libgraphics.a *.o
创建链接器的存档
无法使用,因为它没有符号表。
<强> LD 强>
你的例子:
ld -r -o libgraphics.a *.o
实际上非常不正统。这说明了很少使用链接器,
ld
,通过将多个输入文件链接到,生成合并的对象文件
单个输出目标文件,其中符号分辨率已尽可能 ,
给定输入文件。 -r
( = relocatable)选项
指示链接器生成目标文件目标(而不是程序或DSO)
尽可能地链接输入,如果未定义的符号引用,则不会使linkaqe失败
保留在输出文件中。此用法称为部分链接。
ld -r ...
的输出文件是一个目标文件,而不是 ar
存档,以及
指定外观的输出文件名,就像ar
存档一样,不会使其成为一个。
所以你的例子说明了一个欺骗。这样:
ld -r -o graphics.o *.o
是真实的。我不清楚这种欺骗的目的是什么,
因为即使ELF对象文件被称为libgraphics.a
,并且通过该名称输入到链接,
或者通过-lgraphics
,链接器将正确地将其标识为ELF对象文件,而不是ar
存档,并将消耗
它在命令行中使用任何目标文件的方式:它无条件地链接它
到输出文件,而输入真正的存档的点是链接
归档成员仅在引用的条件下。也许你就是这样
这里不明智的联系的一个例子。
结束......
我们实际上只看过一种制作东西的方法 通常称为库,它是所谓的静态库的产生, 通过归档一些目标文件并将符号表放在存档中。
我们还没有看到如何制作传统上称之为另一种最重要的东西 库,即动态共享对象/共享库/动态库。
与程序类似,DSO由链接器生成。一个程序和一个DSO
是OS加载器理解并可用于组装的ELF二进制变体
正在运行的过程。通常我们通过一个GCC前端(gcc
,g++
,gfortran
等)调用链接器:
关联程序:
gcc -o prog file.o ... -Ldir ... -lfoo ...
关联DSO:
gcc -shared -o libbar.so file.o ... -Ldir ... -lfoo ...
可以向链接器提供共享库和静态库
通过统一-lfoo
协议,当您链接其他一些程序或DSO时。
该选项指示链接器扫描其指定的或默认的搜索目录以查找其中一个
libfoo.so
或libfoo.a
。默认情况下,一旦找到其中任何一个,它就会将该文件输入到链接中,并且
如果它在同一个搜索目录中找到它们,它将更喜欢libfoo.so
。
如果选择libfoo.so
,则链接器会将该DSO添加到运行时依赖关系列表中
您正在制作的任何计划或DSO。如果选择了libfoo.a
然后链接器使用存档作为选择的目标文件进行链接
如果需要,进入输出文件,然后在那里。没有运行时依赖
libfoo.a
本身是可能的;它无法映射到一个过程;它对OS加载器没有任何意义。