问题 如何在不创建所有符号的情况下为iOS创建静态库


之前已经问过这个问题,但是深入研究了各种开发工具的文档  可能,只是不明显。

动机:   制作一个供其他iOS开发人员使用的静态库。如果导出库中的某些符号会导致问题,所以我希望将它们作为仅内部符号。使用动态库,这很容易,只需使用 -exported_symbols_list  libtool (ld参数并列出你想要公开的那些。 libtool 文档不允许这个参数用于静态库。

Library有几个ObjectiveC .m文件,它们使用彼此的代码。只需要将组中的一个类公开给最终的.a静态库文件的用户。

试着 libtool -exported_symbols_list publicsymbols.exp 但那种说法 libtool 不支持 -static 对于静态库。

无法使符号与属性一起使用(如果它甚至可以工作),因为组中的其他.m文件需要这些符号。

好像 ld 可以获取几个.o文件并将它们链接到一个新的.o文件中(通过 -r 论证)它没有“动态唯一”的免责声明 -exported_symbols_list 论证(可能只是不清楚文档......)。

就像测试我用Xcode构建我的项目所以我制作了所有.o文件,然后尝试调用 ld 在命令行上,如下所示:

ld -r -x -all_load -static -arch armv6 -syslibroot {path} 
   -filelist /Users/Dad/ABCsdk/iphone-ABClib/build/ABCLib.build/Distribution-iphoneos/ABCLib-device.build/Objects-normal/armv6/ABCsdk.LinkFileList 
   -exported_symbols_list {exp file path} -o outputfile.o

其中{path}类型的东西有很长的路径到那里的适当位置。

但我得到如下错误:

/ usr / bin / ld_classic:/Users/Dad/ABCsdk/iphone-ABClib/build/ABCLib.build/Distribution-iphoneos/ABCLib-device.build/Objects-normal/armv6/ABCmain.o不兼容,文件包含不受支持的类型第3节(_文本,_picsymbolstub4)在加载命令0中(必须指定要使用的“-dynamic”)

那里似乎有些不对劲......

有谁知道一个聪明的方法来使这项工作?谢谢。


11002
2017-08-01 04:27


起源

你需要隐藏什么样的符号? - Macmade
如果符号已经链接到其应用程序中的相同子库可能会发生冲突(JSONkit说)。显然,我可以只包含JSONKit文件,并说如果它们还没有出现在你的项目中,也要包括它们,但是我希望将一个.h文件和.a文件添加到项目中以实现更清晰的集成。 - Dad


答案:


这真的不可能,我很遗憾地说。它与静态库的工作方式有关。静态库只不过是一堆对象 *.o 捆绑在一起的文件,但动态库是可加载的二进制映像,就像可执行文件一样。

假设你有四个文件,

  • common.c定义 common,这是“私人”
  • fn1.c定义 fn1,哪个电话 common
  • fn2.c定义 fn2,哪个电话 common
  • other.c定义 other

在动态库中, 链接器将所有内容捆绑到一大块代码中。图书馆出口 otherfn1,和 fn2。您必须加载整个库或不加载它,但是两个程序都可以加载它而无需在内存中放置多个副本。切入点 common 只是在符号表中丢失 - 您无法从库外部调用它,因为链接器无法找到它。

请注意,应用程序和共享库的格式基本相同:应用程序基本上是一个只导出一个符号的共享库, main。 (这不完全正确,但很接近。)

在静态库中, 链接器永远不会运行这些文件都被编译成* .o文件并放入* .a库归档文件中。内部参考将无法解决。

假设您的应用程序调用 fn1。链接器看到一个未解析的调用 fn1,然后查看库。它找到了一个定义 fn1 在fn1.o.然后链接器会注意到未解析的调用 common,所以它看起来很普遍。该程序不会从fn2.c或other.c获取代码,因为它不使用这些文件中的定义。

静态库非常古老,它们没有动态库的任何功能。您可以将静态库视为一个充满已编译源代码的zip文件,而不像链接在一起的动态库。没有人愿意扩展存档格式以添加符号可见性。当您链接到静态库时,您获得的结果与将库的源代码添加到程序中的结果相同。

简短版本: 动态库具有所有导出符号的一个符号表,但没有私有符号。以同样的方式,目标文件具有其所有的列表 extern 符号,但没有 static 那些。但是静态库没有符号表,它只是一个存档。因此,没有任何机制可以将代码专用于静态库(除了定义对象之外) static,但这不适用于Objective-C类)。

如果我们知道你为什么要这样做,也许我们可以给你一个建议。 (这是为了安全吗?姓名冲突?所有这些问题都有解决方案。)


14
2017-09-07 00:50



我不想写一个新的答案,因为你在这里写了一个很好的解释,但似乎解决方案似乎是将所有源文件合并到一个编译为单个单元的文件中。 (自动,不是手动。)SQLite项目执行类似这样的操作。 - benzado
@benzado:这对Objective C类不起作用。 - Dietrich Epp
很公平,所以即使他可以隐藏其他符号(函数,常量),类名仍会暴露,所以没有意义。 - benzado
谢谢@dietrich,这就是我的想法。我原本希望可能有一个我错过的聪明的解决方案,但是它似乎没有:)我考虑的另一个选择是重命名所有目标C类等等以确保它们不会发生冲突。 - Dad
@Dad我已经看到了Objective C的方法。例如,Google Protocol Buffers for iOS允许您指定一个前缀,该前缀应用于它生成的所有Objective C类,因此它们不会发生冲突。 - Bob Whiteman


XCode BuildSetting可以做到这一点! 1套 Perform Single-Object Prelink 至 YES 2.设置 Exported Symbols File 至 path_for_symbols_file

也许你应该删除 -static-exported_symbols_list 无法使用静态库,但可以对目标文件生效。


0
2017-11-22 04:44