【问题标题】:Why is the -ObjC linker flag needed to link categories in static libraries? (LLVM)为什么需要 -ObjC 链接器标志来链接静态库中的类别? (LLVM)
【发布时间】:2012-06-18 20:31:58
【问题描述】:

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

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

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

【问题讨论】:

    标签: objective-c llvm llvm-3.0


    【解决方案1】:

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

    即如果主程序调用_foo,而_foo只出现在静态库中,那么_foo和任何依赖符号都会被拖进来。

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

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


    这有点令人困惑,假设编译器应该对此更聪明(当然,它应该在开发工具级别提供帮助)。请务必记住以下几点:

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

    • Objective-C 是完全动态的。当您说[(id)foo bar]; 时,唯一的要求是bar 是在某处 之前定义的。是否真正实现并不重要(直到运行时)。

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

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

    最终结果?

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

    【讨论】:

    • 但是编译器知道它看到了对在类别中定义的方法的调用,因此它可以创建一个特定的符号引用以在链接时使用 -这就是我的问题所在。我想比我链接的技术问答中已经描述的更深入地理解这一点。
    • 很好的答案 - 一个问题。什么足以使编译器从静态库链接符号。只是#import 或者只是定义一个变量MyClass c;,还是你必须在你的类[c myMethod] 上调用一个方法?如果这个类只是在接口生成器中被引用呢?
    • @Robert 链接器需要查看通过与库硬链接解决的符号。如果它是在运行时动态解析的符号,则不会计数(如 IB)。它不一定是方法调用,但这是最容易使用的机制。 IE。以[MyClass class]; 为例。
    猜你喜欢
    • 2011-10-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-18
    • 2015-07-16
    • 2021-10-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多