为什么需要-ObjC链接器标志来链接静态库中的类别? (LLVM)

时间:2012-06-18 20:31:59

标签: objective-c llvm llvm-3.0

关于Apple的技术Q& A: http://developer.apple.com/library/mac/#qa/qa1490/_index.html

我认为编译器可以在编译时标记对类别中定义的方法的调用(它知道它们是在类别中定义的而不是主类,因为原型在@interface Class (Category)部分中) - 所以它可以在“外部类别方法”的目标文件中构建一个表。然后链接器在进行正常链接之后,应该能够连接/合并并处理来自所有对象的“外部类别方法”表,并在所有链接的框架/库/对象的匹配类类别中查找匹配的符号,然后它可以拉入尚未进入目标的那些。

一定有我遗失的东西,但它是什么?为什么这不可能?

1 个答案:

答案 0 :(得分:14)

链接器将静态库视为一个大的旧随机片段集合,它将从中抽取单个片段以满足链接单元其余部分的任何符号请求。

即。如果主程序调用{​​{1}}且_foo仅出现在静态库中,则会拖入_foo以及任何相关符号。

但是,当您在类别中调用方法时,由于Objective-C的活力,没有特定的符号引用。

_foo标志告诉链接器,因此,它应该从静态库中获取所有类别并将它们放入主二进制文件中。


这有点令人困惑,并且假设编译器应该更聪明(并且,当然,它应该在开发工具级别提供帮助)。记住一些事情很重要:

  • 链接器滚动时,头文件中声明的任何内容都会丢失。符号由编译单元创建,而不是由头文件创建。头文件几乎产生了一个承诺,即符号将在以后具体创建或由链接实现,但不能在其自身中创建符号(或者每个编译单元 - 每个.o - 最终会得到一个副本符号和欢闹会在链接时发生。)

  • Objective-C是完全动态的。当您说-ObjC时,唯一的要求就是[(id)foo bar];先前已定义某处。如果它实际上是实际实现的(无论如何直到运行时)都没关系。

  • 类别不必具有相应的@implementations;一个类别可用于声明方法可能存在,事实上,在将bar添加到@optional之前,通常使用@protocol上的类别(ewwwwww)而不使用NSObject {1}}说“嘿,这个可选方法可能在运行时存在”。

  • 编译和链接是完全独立的过程。编译就是扩展代码并将其转换为可执行字节库。链接是关于获取这些库并将它们组合成可以实际运行的东西,包括解析库之间的所有依赖关系。编译器并不真正了解某些内容可能如何链接,并且链接器没有任何关于可能已定义事物(不产生硬符号)的信息。

最终结果?

链接器没有足够的信息来解析依赖关系。