2012-06-18 30 views
10

对于苹果这种技术答疑&答:http://developer.apple.com/library/mac/#qa/qa1490/_index.html为什么-ObjC链接器标志需要链接静态库中的类别? (LLVM)

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

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

回答

14

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

I.e.如果主程序调用_foo_foo只出现在静态库,然后_foo,与任何相关的符号一起,将在拖动。

然而,当你在一个类别调用一个方法,没有特定的符号引用由于Objective-C的活力。

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


这是一个有点混乱,假设是编译器应该是这个聪明(和,无疑,它应该给在开发工具一级的援助)。重要的是要记住一些事情:

  • 在链接器滚动时,头文件中声明的任何内容都会丢失。符号由编译单元创建,而不是由头文件创建。头文件很大程度上产生了一个承诺,即一个符号将在后面被具体创建或由该链接完成,但不能自己创建符号(否则每个编译单元 - 每个.o)最终会得到链接时会出现符号和欢闹)。

  • Objective-C是完全动态的。当你说[(id)foo bar];时,唯一的要求是bar被定义为某处之前。无论它是否实际上实现(无论如何,直到运行时)都无关紧要。

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

  • 编译和链接是完全独立的过程。编译完全是关于扩展代码并将其转换为可执行字节的库。链接是关于将这些库合并成一些可以实际运行的库,包括解决库之间的所有依赖关系。编译器并不真正了解链接的方式,链接器也没有关于可能已经定义了哪些东西(不会产生硬符号)的任何信息。

最终结果?

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

+0

但编译器知道它看到了一个在类别中定义的方法的调用,所以它*可以*创建一个特定的符号引用,以便在链接时使用 - 这就是我的问题所在。我想了解这一点比我所链接的技术问答中已经描述的更深。 – jhabbott

+0

很好的答案 - 一个问题。什么足以导致编译器链接静态库中的符号。只需'#import'或者只是定义一个变量'MyClass c;',或者你需要调用一个类['myMethod]'的方法吗?如果该类仅在界面构建器中引用,那么该怎么办? – Robert

+1

@Robert链接器需要看到一个通过与库的硬链接解决的符号。如果它是在运行时动态解析的符号,它将不会计数(如IB)。它不一定是一个方法调用,但这是最容易使用的机制。即例如'[MyClass class];'。 – bbum

相关问题