Недефинирани препратки към символи в компилация на изходен код на 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