Answers:
ranlib
用于创建和修改库。通常通过在命令行中传递库的位置和/或名称来由链接器使用。有关详细信息,请参见gcc 的-L
和-l
参数。
ar
吗?有什么不同?
该描述看起来很清楚:http : //sourceware.org/binutils/docs/binutils/ranlib.html
因此,如果您归档目标文件的集合,请说:
$ ar r fruits.a apple.o orange.o pineapple.o
然后跑步
$ ranlib fruits.a
创建一个fruits.a内容的索引,并将索引存储在fruits.a中。这对于链接以及对象之间相互调用很有用。
tar
,我想说的不是很清楚。
AR
在Linux中,ar
是GNU通用归档程序。(ar
在其他类似Unix的操作系统中有非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
(通常称为动态/共享库)与DSO大致相同,并且在此基础上建立了错误的期望。实际上,“静态库”和“动态库”根本不相似,它们以完全不同的方式用于链接。
一个明显的区别是,静态库不是由链接程序生成的,而是由链接程序生成的ar
。因此,不会发生链接,也不会发生符号解析。归档的目标文件保持不变:它们只是放在一个袋子里。
当存档是在东西联动输入是通过链接器生成-如程序或DSO -链接程序会在袋子,看看是否有任何目标文件,对于已计提未解决的符号引用提供的定义在链接的早期。如果找到,就从包里取出这些目标文件和链接它们到输出文件,就好像他们是在命令行连接单独命名,并在所有的档案没有提及。因此,归档文件在链接中的全部作用是作为目标文件包,链接程序可以从中选择进行链接所需的文件。
默认情况下,GNU ar
使输出档案准备好用作链接器输入。它将带有伪造假名文件名的伪造“文件”添加到存档中,并且在该伪造文件中,它写入链接程序能够从存档中任何对象文件定义的全局符号中作为查找表读取的内容这些对象文件在归档中的名称和位置。该查找表使链接器可以在存档中查找并标识任何对象文件,这些对象文件定义了已获取的任何未解析的符号引用。
您可以使用q
(=
quick)选项(实际上是您在自己的ar
示例中使用的)以及(capital)S
(= no symbol table)选项禁止创建或更新此查找表。而且,如果ar
出于任何原因调用创建或更新没有符号表(最新的)的归档文件,则可以给该文件一个s
选项。
兰利布
ranlib
根本不创建库。在Linux中,ranlib
是一个遗留程序,ar
如果没有,它将向归档文件中添加(最新)符号表。它的效果ar s
与GNU 完全相同ar
。从历史上看,在ar
能够自动生成符号表之前,ranlib
是将魔术幻象文件注入到存档文件中以使链接程序从其中选择目标文件的库尔德人。在非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
(= 重定位)选项指示所述接头通过链接输入尽可能而不是如果未定义的符号引用保持在输出文件中失败的linkaqe以产生一个对象文件目标(而不是节目,或DSO)。这种用法称为部分链接。
的输出文件ld -r ...
是目标文件,而不是 ar
归档文件,并且指定看起来像ar
归档文件的输出文件名不会使它成为文件名。因此,您的示例说明了一种欺骗。这个:
ld -r -o graphics.o *.o
会是真实的。我不清楚这种欺骗的目的是什么,因为即使ELF对象文件被调用libgraphics.a
,并通过该名称或通过-lgraphics
链接输入到链接,链接器也会正确地将其标识为ELF对象文件。而不是ar
档案,它将像在命令行中使用任何目标文件一样使用它:它无条件地将其链接到输出文件,而输入真正档案的目的是仅在引用档案成员的情况下链接档案成员。也许您在这里仅是一个信息不灵通的示例。
包起来...
实际上,我们只看到了一种生成某些东西的方法,通常将其称为库,这就是所谓的静态库的生成,方法是将一些目标文件存档并将符号表放入存档中。
而且,我们还没有看到如何产生通常称为库的另一种最重要的东西,即动态共享对象/共享库/动态库。
像程序一样,链接器会生成DSO 。程序和DSO是ELF二进制程序的变体,OS加载程序可以理解这些变体,并且可以使用它们来组装正在运行的进程。通常我们通过一个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加载程序没有任何意义。