1

这些天来,我一直在玩弄 Objective-C 运行时,试图找出一些事情是如何工作的。在我的一个“实验”中,我做了以下事情:我得到了以下代码,它位于一个名为的文件中test.m

#import <objc/Object.h>

@interface MySuperClass: Object {

}
-(int) myMessage1;
@end

@interface MyClass: MySuperClass {
    int myIvar;
}
-(void) myMessage2;
@end

@implementation MyClass
-(void) myMessage2 {
  myIvar++;
}
@end

int main() {
    MyClass *myObject;
    myObject = [[MyClass alloc] init];
    [myObject myMessage2];

    return 0;
}

并试图用clang -fobjc-nonfragile-abi -fnext-runtime -o test test.m. 可以想象,编译器会生成一个链接错误消息,因为我正在编译一个 Objective-C 文件,但我并没有告诉链接器将它链接到一个 Objective-C 运行时库(-lobjc例如,使用选项) . 但我是故意这样做的,以检查哪些 objc 运行时库符号将被引用,因此会丢失。我收到以下错误消息:

$ clang -fobjc-nonfragile-abi -fnext-runtime -o test test.m 
/tmp/test-jEfgSA.o:(__DATA, __objc_data+0x0): undefined reference to `OBJC_METACLASS_$_Object'
/tmp/test-jEfgSA.o:(__DATA, __objc_data+0x8): undefined reference to `OBJC_METACLASS_$_MySuperClass'
/tmp/test-jEfgSA.o:(__DATA, __objc_data+0x10): undefined reference to `_objc_empty_cache'
/tmp/test-jEfgSA.o:(__DATA, __objc_data+0x18): undefined reference to `_objc_empty_vtable'
/tmp/test-jEfgSA.o:(__DATA, __objc_data+0x30): undefined reference to `OBJC_CLASS_$_MySuperClass'
/tmp/test-jEfgSA.o:(__DATA, __objc_data+0x38): undefined reference to `_objc_empty_cache'
/tmp/test-jEfgSA.o:(__DATA, __objc_data+0x40): undefined reference to `_objc_empty_vtable'
/tmp/test-jEfgSA.o:(__DATA, __objc_msgrefs, coalesced+0x0): undefined reference to `objc_msgSend_fixup'
/tmp/test-jEfgSA.o:(__DATA, __objc_msgrefs, coalesced+0x10): undefined reference to `objc_msgSend_fixup'
/tmp/test-jEfgSA.o:(__DATA, __objc_msgrefs, coalesced+0x20): undefined reference to `objc_msgSend_fixup'
clang: error: linker command failed with exit code 1 (use -v to see invocation)

很容易理解为什么列出的一些符号是未定义的。objc_msgSend_fixup,例如,指的是运行时库函数。_objc_empty_cache并且_objc_empty_vtable都是在http://opensource.apple.com/source/objc4/objc4-532/runtime/objc-abi.h中声明的运行时库结构。但是,OBJC_METACLASS_$_MySuperClassOBJC_CLASS_$_MySuperClass是表示已在 中声明的类的结构test.m,因此在 Objective-C 运行时库中没有对这些符号的引用。它们应该在 中定义teste.o,但似乎不是。那么,为什么会发生这种情况?

还有一件事:没有对 no 或 的损坏OBJC_METACLASS_$_MyClass引用OBJC_CLASS_$_MyClass。因此,存在对 and 的损坏引用,Object并且MySuperClass它们在 中都有子类test.m,但对 没有损坏的引用MyClass,它没有子类。那么,为什么链接器似乎期望在运行时库中有对具有子类的类的引用,而不是对那些没有子类的引用呢?

4

2 回答 2

2

很好地尝试这些事情。稍后当您遇到类似错误并需要调试时会有所帮助。

突出的几点:

  • 这实际上与子类化无关。例如,仅通过尝试实例化一个对象,您可能会遇到类似的错误。
  • 链接器尝试(简而言之)将编译后的代码及其关联的符号表与代码中的引用进行匹配。
  • 您没有 MySuperClass 的实现,因此不会生成目标代码,并且不存在与您的 MySuperClass 接口定义匹配的符号。您可以通过实现 MySuperClass 来消除此错误。
  • MyClass 很好,因为您已经在文件中实现了 MyClass,因此链接器可以找到一个有效的符号来链接。
于 2012-08-09T21:34:00.120 回答
1

我发现OBJC_METACLASS_$_<my class name>只有在有@implementation <my class name>语句的情况下才会在目标文件中定义符号。所以,如果我添加,例如,片段:

@implementation MySuperClass
-(int) myMessage1 {
  return 0;
}
@end

test.m,链接器将生成错误消息:

$ clang -fobjc-nonfragile-abi -fnext-runtime -o class_teste class_teste.m 
/tmp/class_teste-gDWfF6.o:(__DATA, __objc_data+0x0): undefined reference to `OBJC_METACLASS_$_Object'
/tmp/class_teste-gDWfF6.o:(__DATA, __objc_data+0x8): undefined reference to `OBJC_METACLASS_$_Object'
/tmp/class_teste-gDWfF6.o:(__DATA, __objc_data+0x10): undefined reference to `_objc_empty_cache'
/tmp/class_teste-gDWfF6.o:(__DATA, __objc_data+0x18): undefined reference to `_objc_empty_vtable'
/tmp/class_teste-gDWfF6.o:(__DATA, __objc_data+0x30): undefined reference to `OBJC_CLASS_$_Object'
/tmp/class_teste-gDWfF6.o:(__DATA, __objc_data+0x38): undefined reference to `_objc_empty_cache'
/tmp/class_teste-gDWfF6.o:(__DATA, __objc_data+0x40): undefined reference to `_objc_empty_vtable'
/tmp/class_teste-gDWfF6.o:(__DATA, __objc_data+0x50): undefined reference to `OBJC_METACLASS_$_Object'
/tmp/class_teste-gDWfF6.o:(__DATA, __objc_data+0x60): undefined reference to `_objc_empty_cache'
/tmp/class_teste-gDWfF6.o:(__DATA, __objc_data+0x68): undefined reference to `_objc_empty_vtable'
/tmp/class_teste-gDWfF6.o:(__DATA, __objc_data+0x88): undefined reference to `_objc_empty_cache'
/tmp/class_teste-gDWfF6.o:(__DATA, __objc_data+0x90): undefined reference to `_objc_empty_vtable'
/tmp/class_teste-gDWfF6.o:(__DATA, __objc_msgrefs, coalesced+0x0): undefined reference to `objc_msgSend_fixup'
/tmp/class_teste-gDWfF6.o:(__DATA, __objc_msgrefs, coalesced+0x10): undefined reference to `objc_msgSend_fixup'
/tmp/class_teste-gDWfF6.o:(__DATA, __objc_msgrefs, coalesced+0x20): undefined reference to `objc_msgSend_fixup'
clang: error: linker command failed with exit code 1 (use -v to see invocation)

这是可以接受的,因为所有这些未定义的符号都是 Objective-C 运行时库的一部分。由于我的第一个版本test.m是为了测试目的,我没有在MySuperClass类中添加实现,因为我认为它不会影响目标文件的符号表。所以,这个问题与子类化无关。

于 2012-08-09T21:35:58.497 回答