现在,我一直在忙着使用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_$_MySuperClass
和OBJC_CLASS_$_MySuperClass
是表示已在test.m
中声明的类的结构,因此Objective-C运行时库中没有对这些符号的引用。它们应该在teste.o
中定义,但似乎它们不是。那么,为什么会这样呢?
还有一件事:OBJC_METACLASS_$_MyClass
和OBJC_CLASS_$_MyClass
都没有被破坏的引用。因此,对Object
和MySuperClass
的引用都有缺失,并且它们都在test.m
中有子类,但没有对MyClass
的引用,它没有子类。那么,为什么链接器似乎期望在运行时库中引用具有子类的类,而不是那些没有引用的类呢?
答案 0 :(得分:2)
很好地尝试这些事情。稍后当您遇到类似错误并需要调试时,它会很有帮助。
有几点可以说明:
答案 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
类添加实现,因为我认为它不会影响目标文件的符号表。所以,问题与子类化无关。