ranlib、ar 和 ld 在制作库方面有什么区别
what is the difference between ranlib, ar, and ld for making libraries
为了从 *.o 文件在 c++/unix 中创建库,我注意到我的项目中有两种不同的方法(遗留代码):
ar qc libgraphics.a *.o
ranlib libgraphics.a
和
ld -r -o libgraphics.a *.o
这两种方法有什么区别,用途是什么?
ar
在Linux中,ar
是GNU通用归档器。
(在其他类 Unix OSes 中有 ar
的非 GNU 变体)。使用选项 c
ar c... archive-name file...
它创建一个包含 file...
副本的存档。 archive-name
约定俗成
但不一定具有扩展名 .a
(对于 archive)。每个 file...
可能是
任何类型的文件,不一定是目标文件。
当归档文件都是目标文件时,通常打算使用
用于将 selection 目标文件传送到 linkage of programs 的存档
或 DSO(动态共享对象)。在这种情况下,archive-name
也将按照惯例被赋予前缀 lib
,例如
libfoo.a
,以便可以通过 linker 选项 -lfoo
.
作为候选 linker 输入文件被发现
用作linker 输入文件,libfoo.a
通常称为静态库。这个
用法对于不熟练的程序员来说是一个永久的困惑源,因为它导致他们
认为存档 libfoo.a
与 DSO 非常相似,libfoo.so
,
通常称为 dynamic/shared 库 ,并在此基础上建立错误的期望
基础。事实上 "static library" 和 "dynamic library" 根本不是相似的东西
并以完全不同的方式在 linkage 中使用。
一个明显的区别是静态库不是由linker生成的,
但是 ar
。所以没有 linkage 发生,没有符号解析发生。存档的
目标文件没有改变:它们只是放在一个包里。
当存档在 link 由
linker - 例如程序或 DSO - linker 在包中查看是否有
其中是否有任何目标文件为未解析的符号引用提供定义
在 link 年龄的早期积累的。如果找到任何文件,它会从中提取这些目标文件
bag 和 links them 到输出文件中,就好像它们是单独命名的一样
在 linker 命令行和存档中根本没有提到。所以整个
linkage 中存档的作用是作为目标文件包,linker 可以从中
select 它需要继续 link 年龄。
默认情况下,GNU ar
将其输出存档准备好用作 linker 输入。它添加了一个假 "file"
到存档,带有一个神奇的假文件名,并在这个假文件中写入内容
linker 能够从定义的全局符号中读取 table
通过存档中的任何对象文件到这些对象的名称和位置
存档中的文件。此查找 table 使 linker 能够查看
存档并识别定义任何未解析符号引用的任何目标文件
它已经到手了。
您可以使用 q
( =
quick) 选项 - 实际上你已经在自己的 ar
示例中使用过 - 而且
使用 (capital) S
( = no symbol table) 选项。如果您调用 ar
来创建或更新
出于任何原因没有(最新的)符号 table 的存档,那么你
可以用 s
选项给它一个。
ranlib
ranlib
没有
完全创建库。在 Linux 中,ranlib
是一个遗留程序,它添加了一个(最新的)
符号 table 到 ar
档案,如果它没有的话。它的效果正是
与 ar s
相同,GNU ar
。从历史上看,在 ar
装备生成之前
一个符号 table 本身,ranlib
是注入魔法虚假文件的杂耍
放入存档中,使 linker 能够从中挑选目标文件。在非 GNU 中
为此,可能仍需要类 Unix OSes,ranlib
。你的例子:
ar qc libgraphics.a *.o
ranlib libgraphics.a
说:
- 通过将当前目录中的所有
*.o
文件附加到存档来创建 libgraphics.a
目录,无符号 table.
- 然后在
libgraphics.a
中加上一个符号table
在 linux 中,这与以下内容具有相同的净效果:
ar cr libgraphics.a *.o
ar qc libgraphics.a *.o
本身创建了一个存档,linker
不能使用,因为它没有符号 table.
ld
你的例子:
ld -r -o libgraphics.a *.o
其实很不正统。这说明 linker 的使用相当罕见,
ld
,通过 link 将多个输入文件合并到 合并 目标文件
一个单一的输出目标文件,其中符号解析已经尽可能,
给定输入文件。 -r
( = relocatable) 选项
指示 linker 通过以下方式生成目标文件目标(而不是程序或 DSO)
link尽可能输入,如果未定义的符号引用,不要让 linkaqe 失败
保留在输出文件中。这种用法叫做 partial linking.
ld -r ...
的输出文件是目标文件,不是ar
archive,并且
指定一个 看起来 类似于 ar
存档的输出文件名并不能使它成为一个。
所以你的例子说明了一种欺骗。这个:
ld -r -o graphics.o *.o
会说实话。我不清楚这种欺骗的目的是什么,
因为即使一个 ELF 目标文件被称为 libgraphics.a
,并以该名称输入到 linkage,
或者通过 -lgraphics
,linker 将正确地将其识别为 ELF 对象文件,而不是 ar
存档,并将使用
它在命令行中使用任何目标文件的方式:它 link 无条件地使用它
到输出文件中,而输入真正存档的目的是 link
存档成员仅在引用它们的条件下。也许你只是有
消息不灵通的例子 linking here.
总结...
我们实际上只见过 一种 生产方式
通常称为库,这就是所谓的静态库的产生,
通过归档一些目标文件并在归档中放置一个符号 table。
而且我们还没有看到如何生产另一种最重要的东西,通常被称为
一个库,即动态共享Object/sharedlibrary/dynamic库。
像程序一样,DSO 是由 linker 生成的。程序和 DSO
是 OS 加载程序理解并可用于 assemble 的 ELF 二进制变体
一个 运行 过程。通常我们通过 GCC 前端之一调用 linker(gcc
、g++
、gfortran
等):
链接程序:
gcc -o prog file.o ... -Ldir ... -lfoo ...
链接 DSO:
gcc -shared -o libbar.so file.o ... -Ldir ... -lfoo ...
共享库和静态库都可以提供给 linker
通过统一的 -lfoo
协议,当你正在 linking 一些其他程序或 DSO 时。
该选项指示 linker 扫描其指定的或默认的搜索目录以查找
libfoo.so
或 libfoo.a
。默认情况下,一旦找到其中任何一个,它就会将该文件输入到 linkage,并且
如果它在同一个搜索目录中找到两者,它会更喜欢 libfoo.so
。
如果 libfoo.so
被 selected 则 linker 将该 DSO 添加到运行时依赖列表
您正在制作的任何程序或 DSO。如果 libfoo.a
被 selected
然后 linker 使用存档作为 selection of object files for linkage
进入输出文件,如果需要,就在那里。没有运行时依赖
libfoo.a
本身是可以的;它不能映射到一个过程中;它对 OS 加载程序没有任何意义。
为了从 *.o 文件在 c++/unix 中创建库,我注意到我的项目中有两种不同的方法(遗留代码):
ar qc libgraphics.a *.o
ranlib libgraphics.a
和
ld -r -o libgraphics.a *.o
这两种方法有什么区别,用途是什么?
ar
在Linux中,ar
是GNU通用归档器。
(在其他类 Unix OSes 中有 ar
的非 GNU 变体)。使用选项 c
ar c... archive-name file...
它创建一个包含 file...
副本的存档。 archive-name
约定俗成
但不一定具有扩展名 .a
(对于 archive)。每个 file...
可能是
任何类型的文件,不一定是目标文件。
当归档文件都是目标文件时,通常打算使用
用于将 selection 目标文件传送到 linkage of programs 的存档
或 DSO(动态共享对象)。在这种情况下,archive-name
也将按照惯例被赋予前缀 lib
,例如
libfoo.a
,以便可以通过 linker 选项 -lfoo
.
用作linker 输入文件,libfoo.a
通常称为静态库。这个
用法对于不熟练的程序员来说是一个永久的困惑源,因为它导致他们
认为存档 libfoo.a
与 DSO 非常相似,libfoo.so
,
通常称为 dynamic/shared 库 ,并在此基础上建立错误的期望
基础。事实上 "static library" 和 "dynamic library" 根本不是相似的东西
并以完全不同的方式在 linkage 中使用。
一个明显的区别是静态库不是由linker生成的,
但是 ar
。所以没有 linkage 发生,没有符号解析发生。存档的
目标文件没有改变:它们只是放在一个包里。
当存档在 link 由 linker - 例如程序或 DSO - linker 在包中查看是否有 其中是否有任何目标文件为未解析的符号引用提供定义 在 link 年龄的早期积累的。如果找到任何文件,它会从中提取这些目标文件 bag 和 links them 到输出文件中,就好像它们是单独命名的一样 在 linker 命令行和存档中根本没有提到。所以整个 linkage 中存档的作用是作为目标文件包,linker 可以从中 select 它需要继续 link 年龄。
默认情况下,GNU ar
将其输出存档准备好用作 linker 输入。它添加了一个假 "file"
到存档,带有一个神奇的假文件名,并在这个假文件中写入内容
linker 能够从定义的全局符号中读取 table
通过存档中的任何对象文件到这些对象的名称和位置
存档中的文件。此查找 table 使 linker 能够查看
存档并识别定义任何未解析符号引用的任何目标文件
它已经到手了。
您可以使用 q
( =
quick) 选项 - 实际上你已经在自己的 ar
示例中使用过 - 而且
使用 (capital) S
( = no symbol table) 选项。如果您调用 ar
来创建或更新
出于任何原因没有(最新的)符号 table 的存档,那么你
可以用 s
选项给它一个。
ranlib
ranlib
没有
完全创建库。在 Linux 中,ranlib
是一个遗留程序,它添加了一个(最新的)
符号 table 到 ar
档案,如果它没有的话。它的效果正是
与 ar s
相同,GNU ar
。从历史上看,在 ar
装备生成之前
一个符号 table 本身,ranlib
是注入魔法虚假文件的杂耍
放入存档中,使 linker 能够从中挑选目标文件。在非 GNU 中
为此,可能仍需要类 Unix OSes,ranlib
。你的例子:
ar qc libgraphics.a *.o
ranlib libgraphics.a
说:
- 通过将当前目录中的所有
*.o
文件附加到存档来创建libgraphics.a
目录,无符号 table. - 然后在
libgraphics.a
中加上一个符号table
在 linux 中,这与以下内容具有相同的净效果:
ar cr libgraphics.a *.o
ar qc libgraphics.a *.o
本身创建了一个存档,linker
不能使用,因为它没有符号 table.
ld
你的例子:
ld -r -o libgraphics.a *.o
其实很不正统。这说明 linker 的使用相当罕见,
ld
,通过 link 将多个输入文件合并到 合并 目标文件
一个单一的输出目标文件,其中符号解析已经尽可能,
给定输入文件。 -r
( = relocatable) 选项
指示 linker 通过以下方式生成目标文件目标(而不是程序或 DSO)
link尽可能输入,如果未定义的符号引用,不要让 linkaqe 失败
保留在输出文件中。这种用法叫做 partial linking.
ld -r ...
的输出文件是目标文件,不是ar
archive,并且
指定一个 看起来 类似于 ar
存档的输出文件名并不能使它成为一个。
所以你的例子说明了一种欺骗。这个:
ld -r -o graphics.o *.o
会说实话。我不清楚这种欺骗的目的是什么,
因为即使一个 ELF 目标文件被称为 libgraphics.a
,并以该名称输入到 linkage,
或者通过 -lgraphics
,linker 将正确地将其识别为 ELF 对象文件,而不是 ar
存档,并将使用
它在命令行中使用任何目标文件的方式:它 link 无条件地使用它
到输出文件中,而输入真正存档的目的是 link
存档成员仅在引用它们的条件下。也许你只是有
消息不灵通的例子 linking here.
总结...
我们实际上只见过 一种 生产方式 通常称为库,这就是所谓的静态库的产生, 通过归档一些目标文件并在归档中放置一个符号 table。
而且我们还没有看到如何生产另一种最重要的东西,通常被称为 一个库,即动态共享Object/sharedlibrary/dynamic库。
像程序一样,DSO 是由 linker 生成的。程序和 DSO
是 OS 加载程序理解并可用于 assemble 的 ELF 二进制变体
一个 运行 过程。通常我们通过 GCC 前端之一调用 linker(gcc
、g++
、gfortran
等):
链接程序:
gcc -o prog file.o ... -Ldir ... -lfoo ...
链接 DSO:
gcc -shared -o libbar.so file.o ... -Ldir ... -lfoo ...
共享库和静态库都可以提供给 linker
通过统一的 -lfoo
协议,当你正在 linking 一些其他程序或 DSO 时。
该选项指示 linker 扫描其指定的或默认的搜索目录以查找
libfoo.so
或 libfoo.a
。默认情况下,一旦找到其中任何一个,它就会将该文件输入到 linkage,并且
如果它在同一个搜索目录中找到两者,它会更喜欢 libfoo.so
。
如果 libfoo.so
被 selected 则 linker 将该 DSO 添加到运行时依赖列表
您正在制作的任何程序或 DSO。如果 libfoo.a
被 selected
然后 linker 使用存档作为 selection of object files for linkage
进入输出文件,如果需要,就在那里。没有运行时依赖
libfoo.a
本身是可以的;它不能映射到一个过程中;它对 OS 加载程序没有任何意义。