对Objective-C源代码编译的符号的未定义引用

时间:2012-08-09 19:15:50

标签: objective-c objective-c-runtime

现在,我一直在忙着使用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中定义,但似乎它们不是。那么,为什么会这样呢?

还有一件事:OBJC_METACLASS_$_MyClassOBJC_CLASS_$_MyClass都没有被破坏的引用。因此,对ObjectMySuperClass的引用都有缺失,并且它们都在test.m中有子类,但没有对MyClass的引用,它没有子类。那么,为什么链接器似乎期望在运行时库中引用具有子类的类,而不是那些没有引用的类呢?

2 个答案:

答案 0 :(得分:2)

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

有几点可以说明:

  • 这不是关于子类化的。例如,您可以通过尝试实例化对象来获得类似的错误。
  • 链接器尝试(简化术语)以匹配已编译的代码及其关联的符号表,以及代码中的引用。
  • 您没有MySuperClass的实现,因此不会生成任何对象代码,也不存在与MySuperClass的接口定义匹配的符号。您可以通过实现MySuperClass来消除此错误。
  • MyClass没问题,因为您已在文件中实现了MyClass,因此链接器可以找到要链接的有效符号。

答案 1 :(得分: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类添加实现,因为我认为它不会影响目标文件的符号表。所以,问题与子类化无关。