gpt4 book ai didi

linker - 用于制作库的 ranlib、ar 和 ld 之间有什么区别

转载 作者:行者123 更新时间:2023-12-03 13:48:36 51 4
gpt4 key购买 nike

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

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


ld -r -o libgraphics.a *.o

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

最佳答案

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 ,
通常称为动态/共享库,并对此建立错误的期望
基础。实际上“静态库”和“动态库”根本不是相似的东西
并以完全不同的方式用于链接。

一个显着的区别是静态库不是由链接器生成的,
但来自 ar .所以没有链接发生,没有符号解析发生。存档的
目标文件没有改变:它们只是放在一个包里。

当文件被输入到由
链接器 - 例如程序或 DSO - 链接器查看包中是否有
是其中提供未解析符号引用定义的任何目标文件
在链接中较早产生的。如果找到,它会从
包并将它们链接到输出文件中,就像它们被单独命名一样
在链接器命令行和存档中根本没有提到。所以整个
存档在链接中的作用是链接器可以从中获取的目标文件包
选择它需要进行联动的那些。

默认情况下,GNU ar使其输出文件准备用作链接器输入。它添加了一个虚假的"file"
到存档,用一个神奇的假文件名,并在这个假文件中写入内容
链接器能够从定义的全局符号中读取作为查找表
通过存档中的任何对象文件到这些对象的名称和位置
存档中的文件。此查找表使链接器能够查找
存档并识别定义任何未解析符号引用的任何目标文件
它已经掌握了。

您可以使用 q 禁止创建或更新此查找表。 ( =
快速) 选项 - 实际上您已经在自己的 ar 中使用了该选项例子 - 还有
与(资本) S ( = 无符号表) 选项。如果你调用 ar创建或更新
由于任何原因没有获得(最新的)符号表的文件,那么你
可以给它一个 s选项。

ranlib

ranlib 没有
创建库。在 Linux 中, ranlib是一个遗留程序,它添加了一个(最新的)
符号表到 ar如果没有存档,请存档。它的效果正是
ar s , 与 GNU ar .历史上,之前 ar被装备生成
符号表本身, ranlib是注入(inject)神奇虚假文件的杂物
进入文件,使链接器能够从中挑选目标文件。在非 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)
    尽可能链接输入,如果 undefined symbol 引用,则不要使 linkaqe 失败
    保留在输出文件中。这种用法称为部分链接。
    ld -r ...的输出文件是一个目标文件,而不是 ar存档,和
    指定一个看起来像 ar 的输出文件名存档并没有使它成为一个。
    所以你的例子说明了一种欺骗。这个:
    ld -r -o graphics.o *.o

    会是真实的。我不清楚这种欺骗的目的是什么,
    因为即使调用 ELF 目标文件 libgraphics.a ,并通过该名称输入到链接中,
    或通过 -lgraphics ,链接器会将其正确识别为 ELF 目标文件,而不是 ar存档,并将消耗
    它使用命令行中的任何对象文件的方式:它无条件地链接它
    到输出文件中,而输入真正存档的点是链接
    存档成员仅在被引用的情况下。也许你只是
    这里是信息不灵通的链接的一个例子。

    结束...

    我们实际上只见过一种生产方式
    通常被称为库,这就是所谓的静态库的产生,
    通过归档一些目标文件并将符号表放入归档中。

    我们完全没有看到如何生产另一种最重要的东西,通常被称为
    一个库,即动态共享对象/共享库/动态库。

    与程序一样,DSO 由链接器生成。一个程序和一个 DSO
    是 ELF 二进制文件的变体,OS 加载程序可以理解这些变体并可以用来组装
    一个正在运行的进程。通常我们通过 GCC 前端之一( gccg++gfortran 等)调用链接器:

    链接程序:
    gcc -o prog file.o ... -Ldir ... -lfoo ...

    链接 DSO:
    gcc -shared -o libbar.so file.o ... -Ldir ... -lfoo ...

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

    关于linker - 用于制作库的 ranlib、ar 和 ld 之间有什么区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47910759/

    51 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com