1

最近、私は Objective-C ランタイムをいじり回して、いくつかのことがどのように機能するかを調べようとしています。私の「実験」の 1 つで、次のことを行いました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およびhttp://opensource.apple.com/source/objc4/objc4-532/runtime/objc-abi.h_objc_empty_vtableで宣言されている両方のランタイム ライブラリ構造体です。ただし、とは で宣言されたクラスを表す構造体であるため、Objective-C ランタイム ライブラリにはこれらのシンボルへの参照はありません。で定義する必要がありますが、そうではないようです。それで、なぜこれが起こるのですか?OBJC_METACLASS_$_MySuperClassOBJC_CLASS_$_MySuperClasstest.mteste.o

もう 1 つ: どちらにも、または への壊れた参照はありませOBJC_METACLASS_$_MyClassOBJC_CLASS_$_MyClass。したがって、 と への壊れた参照が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 に答える