我正在寻找限制导出到Linux静态库(存档)的C符号数量的方法.我想将这些仅限于那些属于该库官方API的符号.我已经使用'static'将大多数函数声明为static,但是这会将它们限制为文件范围.我正在寻找一种限制图书馆范围的方法.
我可以使用Ulrich Drepper的" 如何编写共享库"中的技术为共享库执行此操作,但我无法将这些技术应用于静态存档.在他早期的图书馆设计良好实践论文中,他写道:
唯一的可能性是使用'ld -r'将需要某些内部资源的所有目标文件合并为一个,然后限制由此组合目标文件导出的符号.GNU链接器可以选择执行此操作.
谁能帮助我发现这些选项可能是什么?我使用'strip -w -K prefix_*'取得了一些成功,但这感觉很野蛮.理想情况下,我想要一个适用于GCC 3和4的解决方案.
谢谢!
对于使用GCC 3.x或4.x编译的代码,静态库无法执行您想要的操作.
如果您可以使用共享对象(库),GNU链接器将通过称为版本脚本的功能来执行您所需的操作.这通常用于提供特定于版本的入口点,但是退化情况只是区分公共和私有符号而没有任何版本控制.使用ld的--version-script =命令行选项指定版本脚本.
版本脚本的内容使得入口指向foo和bar为public并隐藏所有其他接口:
{ global: foo; bar; local: *; };
请参阅ld doc:http://sourceware.org/binutils/docs/ld/VERSION.html#VERSION
我是共享库的主要倡导者,这种限制全局变量可见性的能力是他们的伟大优点之一.
提供共享对象的更多优点但是为Solaris编写的文档(由Greg Nakhimovsky撰写的快乐记忆)位于http://developers.sun.com/solaris/articles/linker_mapfiles.html
我希望这有帮助.
我不相信GNU ld有任何这样的选择; 乌尔里希一定意味objcopy
,那里有很多这样的选项:--localize-hidden
,--localize-symbol=symbolname
,--localize-symbols=filename
.
的--localize-hidden
特别允许一个具有非常精细地控制哪些符号被暴露.考虑:
int foo() { return 42; } int __attribute__((visibility("hidden"))) bar() { return 24; } gcc -c foo.c nm foo.o 000000000000000b T bar 0000000000000000 T foo objcopy --localize-hidden foo.o bar.o nm bar.o 000000000000000b t bar 0000000000000000 T foo
因此bar()
不再从对象中导出(即使它仍然存在并可用于调试).你也可以bar()
一起删除所有objcopy --strip-unneeded
.
这个答案的优点将取决于您使用静态库的原因.如果允许链接器稍后删除未使用的对象,那么我几乎无法添加.如果它是为了组织的目的 - 最小化必须传递给链接应用程序的对象的数量 - 这种对Employed Russian的答案的扩展可能是有用的.
在编译时,可以使用以下命令设置编译单元中所有符号的可见性:
-fvisibility=hidden -fvisibility=default
这意味着可以编译具有默认可见性的单个文件"interface.c"和具有隐藏可见性的大量实现文件,而无需注释源.然后,可重定位链接将生成单个目标文件,其中非api函数被"隐藏":
ld -r interface.o implementation0.o implementation1.o -o relocatable.o
现在可以对组合的目标文件进行objcopy:
objcopy --localize-hidden relocatable.o mylibrary.o
因此,我们有一个目标文件"library"或"module",它只公开预期的API.
上述策略与链接时间优化适度地相互作用.使用-flto编译并通过编译器将-r传递给链接器来执行可重定位链接:
gcc -fuse-linker-plugin -flto -nostdlib -Wl,-r {objects} -o relocatable.o
使用objcopy像以前一样本地化隐藏的符号,然后最后一次调用链接器来剥离本地符号以及它可以在post-lto对象中找到的任何其他死代码.遗憾的是,relocatable.o不太可能保留任何与lto相关的信息:
gcc -nostdlib -Wl,-r,--discard-all relocatable.o mylibrary.o
lto的当前实现在可重定位链接阶段期间似乎是活动的.使用lto,隐藏的=>本地符号被最终的可重定位链接剥离.没有lto,hidden => local符号在最终的可重定位链接中幸存下来.
lto的未来实现似乎可能通过可重定位链接阶段保留所需的元数据,但是目前可重定位链接的结果似乎是一个普通的旧目标文件.