这是可能的!正如Dietrich所说,静态库中所有导出的符号
.o
文件都是公开的,如果一个文件需要引用另一个
.o
文件中的符号,则需要从该文件导出(因此是公共的)。但是有一个简单的解决方法 - 预链接所有的
.o
文件到一个单独的文件中。然后您只需要导出公共符号即可。
这显然称为“单个对象预链接”,在XCode中有一个选项可以执行,由treert提到。但是您可以仅使用标准命令行工具来执行它(示例存储库
在这里):
检查一下(这是在Mac上)。
首先让我们创建一些测试文件。
$ cat private.c
int internal_private_function() {
return 5;
}
$ cat public.c
extern int internal_private_function();
int public_function() {
return internal_private_function();
}
编译它们。
$ clang -c private.c -o private.o
$ clang -c public.c -o public.o
将它们添加到静态库中(它基本上是一个 ZIP 文件,但采用了几十年前的格式)。
$ ar -r libeverything_public.a public.o private.o
检查其中包含哪些符号。
$ objdump -t libeverything_public.a
libeverything_public.a(private.o): file format Mach-O 64-bit x86-64
SYMBOL TABLE:
0000000000000000 g F __TEXT,__text _internal_private_function
libeverything_public.a(public.o): file format Mach-O 64-bit x86-64
SYMBOL TABLE:
0000000000000000 g F __TEXT,__text _public_function
0000000000000000 *UND* _internal_private_function
可以看到,这两个函数都是可见的,并且两个符号都是g
,表示全局。
现在让我们将其预链接成一个单独的文件,然后将其放在一个静态库中。
$ ld -r -o prelinked.o private.o public.o
$ ar -r libeverything_public_prelinked.a prelinked.o
$ objdump -t libeverything_public_prelinked.a
libeverything_public_prelinked.a(prelinked.o): file format Mach-O 64-bit x86-64
SYMBOL TABLE:
0000000000000020 l O __TEXT,__eh_frame EH_Frame1
0000000000000038 l O __TEXT,__eh_frame func.eh
0000000000000060 l O __TEXT,__eh_frame EH_Frame1
0000000000000078 l O __TEXT,__eh_frame func.eh
0000000000000000 g F __TEXT,__text _internal_private_function
0000000000000010 g F __TEXT,__text _public_function
类似的结果-它们在同一个文件中,但两者仍然存在且是全局的。最后让我们将它们过滤掉(这是针对Mac系统的)。我们需要导出一份符号列表:
$ cat exported_symbols_osx.lds
_public_function
然后使用-exported_symbols_list
选项。
$ ld -r -exported_symbols_list exported_symbols_osx.lds -o prelinked_filtered.o private.o public.o
$ ar -r libfiltered_prelinked.a prelinked_filtered.o
ar: creating archive libfiltered_prelinked.a
$ objdump -t libfiltered_prelinked.a
libfiltered_prelinked.a(prelinked_filtered.o): file format Mach-O 64-bit x86-64
SYMBOL TABLE:
0000000000000000 l F __TEXT,__text _internal_private_function
0000000000000020 l O __TEXT,__eh_frame EH_Frame1
0000000000000038 l O __TEXT,__eh_frame func.eh
0000000000000060 l O __TEXT,__eh_frame EH_Frame1
0000000000000078 l O __TEXT,__eh_frame func.eh
0000000000000010 g F __TEXT,__text _public_function
哇塞!_internal_private_function
现在是一个本地符号了。您可以添加 -x
选项(或者运行 strip -x
)来将其名称更改为随机无意义的值(这里使用 l001
)。
$ ld -r -x -exported_symbols_list exported_symbols_osx.lds -o prelinked_filtered.o private.o public.o
$ objdump -t prelinked_filtered.o
prelinked_filtered.o: file format Mach-O 64-bit x86-64
SYMBOL TABLE:
0000000000000000 l F __TEXT,__text l001
0000000000000020 l O __TEXT,__eh_frame EH_Frame1
0000000000000038 l O __TEXT,__eh_frame func.eh
0000000000000060 l O __TEXT,__eh_frame EH_Frame1
0000000000000078 l O __TEXT,__eh_frame func.eh
0000000000000010 g F __TEXT,__text _public_function
以下是苹果的链接器对于
-x
的说明:
不要将非全局符号放入输出文件的符号表中。非全局符号在调试和获取回溯符号名称时很有用,但在运行时不使用。如果与-r一起使用
-x
,则非全局符号名称不会被删除,而是替换为一个独特的虚拟名称,该名称在链接到最终的链接映像时将自动删除。这允许死代码剥离(dead code stripping)正常工作,并提供源符号名称被删除的安全性。
Linux上的所有内容都相同,只不过使用
-exported_symbols_list
代替。在Linux上,我认为您需要使用如下文件的
--version-script
:
V0 {
global:
_public_function;
local:
*;
};
但我尚未测试过这个。此文件和exported_symbols_list
文件都支持通配符。