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
每月下载量 3,729
49KB
1K SLoC
armerge
您可以使用 armerge 将多个静态库合并成一个单一的 ar
归档。
可选地,armerge 可以接受一个您想要导出的符号列表,并将其他符号本地化(隐藏)。
这允许您隐藏您的私有符号和依赖项的符号。
例如,如果您的静态库 libfoo.a
使用 OpenSSL 的 libcrypto.a
,armerge 可以创建一个单一的 libfoo_merged.a
归档,将两者合并,但其中所有 OpenSSL 符号都被隐藏,只有您选择的公共 libfoo
符号被导出。
用法
合并 libfoo.a
和 libcrypto.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
)。
此工具需要 ranlib
、ld
和 llvm-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