Неопределенные ссылки на символы при компиляции исходного кода Objective-C

В эти дни я возился со средой выполнения 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, у которого нет подкласса. Итак, почему компоновщик, кажется, ожидает, что в библиотеке времени выполнения будут ссылки на классы, у которых есть подклассы, но не на те, у которых их нет?


person LuisABOL    schedule 09.08.2012    source источник


Ответы (2)


Хорошо экспериментировать с такими вещами. Это будет полезно позже, когда вы получите подобные ошибки и вам нужно будет отладить.

Несколько моментов, которые бросаются в глаза:

  • Это не совсем о подклассах. Вы можете получить подобные ошибки, просто пытаясь создать экземпляр объекта, например.
  • Компоновщик пытается (упрощенно) сопоставить скомпилированный код и связанную с ним таблицу символов со ссылками в коде.
  • У вас нет реализации MySuperClass, поэтому не создается объектный код и не существует символов, соответствующих вашему определению интерфейса MySuperClass. Вы можете устранить эту ошибку, реализовав MySuperClass.
  • С MyClass все в порядке, потому что вы реализовали MyClass в файле, поэтому компоновщик может найти допустимый символ для ссылки.
person Adam B    schedule 09.08.2012
comment
Да, вы абсолютно правы. Это то, что я только что узнал... Спасибо! - person LuisABOL; 10.08.2012

Я обнаружил, что символы 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, так как думал, что это не повлияет на таблицу символов объектного файла. Таким образом, проблема не имеет ничего общего с подклассами.

person LuisABOL    schedule 09.08.2012