ranlib,ar和ld用于创建库

时间:2017-12-20 16:45:06

标签: linker ld ar

要使用* .o文件在c ++ / unix中创建库,我注意到我的项目中有两种不同的方式(遗留代码):

ar qc libgraphics.a *.o
ranlib libgraphics.a

ld -r -o libgraphics.a *.o

两种方法之间有什么区别,哪种方法用于什么目的?

1 个答案:

答案 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前端(gccg++gfortran等)调用链接器:

关联程序:

gcc -o prog file.o ... -Ldir ... -lfoo ...

关联DSO:

gcc -shared -o libbar.so file.o ... -Ldir ... -lfoo ...

可以向链接器提供共享库和静态库 通过统一-lfoo协议,当您链接其他一些程序或DSO时。 该选项指示链接器扫描其指定的或默认的搜索目录以查找其中一个 libfoo.solibfoo.a。默认情况下,一旦找到其中任何一个,它就会将该文件输入到链接中,并且 如果它在同一个搜索目录中找到它们,它将更喜欢libfoo.so。 如果选择libfoo.so,则链接器会将该DSO添加到运行时依赖关系列表中 您正在制作的任何计划或DSO。如果选择了libfoo.a 然后链接器使用存档作为选择的目标文件进行链接 如果需要,进入输出文件,然后在那里。没有运行时依赖 libfoo.a本身是可能的;它无法映射到一个过程;它对OS加载器没有任何意义。