#符号 #静态 #合并 #归档 #隐藏 #ar #控制

构建 armerge

静态库合并和控制可见性的工具

26 个稳定版本

2.0.0 2024年2月26日
1.5.1 2022年7月8日
1.3.8 2022年4月1日
1.3.7 2022年3月30日
1.1.8 2020年9月22日

#1#ar

Download history • Rust 包仓库 569/week @ 2024-03-13 • Rust 包仓库 583/week @ 2024-03-20 • Rust 包仓库 628/week @ 2024-03-27 • Rust 包仓库 592/week @ 2024-04-03 • Rust 包仓库 664/week @ 2024-04-10 • Rust 包仓库 745/week @ 2024-04-17 • Rust 包仓库 623/week @ 2024-04-24 • Rust 包仓库 468/week @ 2024-05-01 • Rust 包仓库 419/week @ 2024-05-08 • Rust 包仓库 548/week @ 2024-05-15 • Rust 包仓库 726/week @ 2024-05-22 • Rust 包仓库 4046/week @ 2024-05-29 • Rust 包仓库 1179/week @ 2024-06-05 • Rust 包仓库 705/week @ 2024-06-12 • Rust 包仓库 611/week @ 2024-06-19 • Rust 包仓库 710/week @ 2024-06-26 • Rust 包仓库

每月下载量 3,729

MIT/Apache

49KB
1K SLoC

armerge

crates.io Apache 2 licensed MSRV CI

您可以使用 armerge 将多个静态库合并成一个单一的 ar 归档。
可选地,armerge 可以接受一个您想要导出的符号列表,并将其他符号本地化(隐藏)。

这允许您隐藏您的私有符号和依赖项的符号。
例如,如果您的静态库 libfoo.a 使用 OpenSSL 的 libcrypto.a,armerge 可以创建一个单一的 libfoo_merged.a 归档,将两者合并,但其中所有 OpenSSL 符号都被隐藏,只有您选择的公共 libfoo 符号被导出。

用法

合并 libfoo.alibcrypto.a 的示例命令,只保留以 libfoo_ 开头的符号为公共

armerge--保留-符号'^libfoo_' --输出 libfoo_merged.a libfoo.a libcrypto.a

选项和用法

USAGE:
    armerge [FLAGS] [OPTIONS] --output <output> [--] [INPUTS]...

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information
    -v, --verbose    Print verbose information

OPTIONS:
    -k, --keep-symbols <keep-symbols>...    Accepts regexes of the symbol names to keep global, and localizes the rest
    -o, --output <output>                   Output static library

ARGS:
    <INPUTS>...    Static libraries to merge

平台支持

支持 Linux/Android 和 macOS/iOS ar 归档,使用各自的宿主工具链。
当本地化符号(-k 选项)时,只支持包含 ELF 或 Mach-O 对象的归档(在这种情况下,输出归档将包含一个可重定位对象 merged.o)。

此工具需要 ranlibldllvm-objcopy 来处理 Linux 静态库。
对于 macOS 库,使用 libtool 和 Apple 的 ld
如果安装了正确的工具链,您可以使用 armerge 在 macOS 主机上处理 Linux/Android 归档。

您可以使用 LD 环境变量指定不同的链接器,以及使用 ARMERGE_LDFLAGS 设置链接器标志。
您可以使用 OBJCOPY 环境变量指定不同的 objcopy 实现。

工作原理

合并静态库

当您不关心控制静态库导出的符号时,合并它们非常简单。在所有主要平台上,静态库实际上是一个归档文件(类似于 .zip 文件,但在 ar 格式下)。
(实际上,一些项目有时会使用自定义的 shell 脚本来处理合并静态库,这些脚本会调用 ar 工具。)

基本上,armerge 要做的只是将多个 .a 文件组合成一个,这需要提取内部的目标文件(注意不要覆盖具有相同名称的不同文件,即使在单个归档中也是允许的,shell 脚本经常忘记处理这一点),并在新的 ar 归档中将它们全部添加进去。

出于性能考虑,ar 归档通常还会有一个索引,所以我们会在合并时注意重建它。

控制导出符号

当您创建动态库时,您可以选择要导出哪些符号以及要保留哪些符号内部。
这允许保持依赖和实现细节的私有性,并防止难以调试的符号冲突。
例如,一个 libfoo.so 库可以没有问题地捆绑 OpenSSL 的副本,但前提是它不导出那些符号。
在 Android 上隐藏符号尤其重要(Android 有助于加载其自己的版本的一些流行的动态库,如 OpenSSL),尽管冲突可能发生在任何平台上。

不幸的是,原生 C 和 C++ 工具链没有提供隐藏静态库中符号的选项。
这是因为——与动态库不同——静态归档不是一个完整的整体,而只是一堆目标文件。在静态库级别没有导出控制的概念,只有目标级别。
所以如果符号在目标级别被天真地本地化,静态库在您使用它时会简单地失败链接,因为每个目标现在都会强烈地保持其符号的私有性,即使是在同一个库中。

解决方案是做动态库同样的事情:使其由一个单独的目标文件组成。因此,除了将多个归档文件合并成一个之外,当您要求 armerge 本地化符号时,它将所有输入库中的目标文件传递给链接器,并创建一个单一代码重定位对象文件,称为可重定位对象。

这导致静态库(例如 libfoo.a)包含一个单独的 merged.o 目标。
由于所有输入对象已经预先链接在一起,现在整个库只有一个符号表(就像动态库一样),因此我们可以请求工具链为我们本地化符号,而不会出现任何问题。

在这个过程中,armerge 实际上委托了大部分工作给链接器和像 objcopy 这样的实用工具。
控制静态库中符号导出的功能实际上与动态库使用的相同机制(两者实际上都是目标文件),所以您的系统工具链一直都有这种支持。

但是,由于传统的链接器输出包含多个对象的静态库,而不是单个预链接对象,它们创建了一个历史的不对称性,即在动态库中隐藏符号总是很容易,而在静态库中隐藏符号从未得到工具链的支持。

因此,armerge 首先通过要求链接器预先链接对象来纠正不对称性,然后才要求它隐藏符号。

依赖项

~10–22MB
~328K SLoC