リンカは、スタティック ライブラリをランダム ピースの大きな古いコレクションのように扱い、そこから個々のピースを引き出して、リンク ユニットの残りの部分からのシンボル要求を満たします。
つまり、メイン プログラムが呼び出され、静的ライブラリ_foo
に_foo
しか表示されない場合_foo
、依存シンボルと共に がドラッグされます。
ただし、カテゴリ内のメソッドを呼び出す場合、Objective-C のダイナミズムにより、特定のシンボル参照はありません。
この-ObjC
フラグは、このため、スタティック ライブラリからすべてのカテゴリを取得し、それらをメイン バイナリにドロップする必要があることをリンカーに伝えます。
少し紛らわしいですが、コンパイラはこれについてもっと賢くあるべきだという前提があります(そして、確かに、開発ツールレベルで支援を提供するはずです)。いくつかのことを覚えておくことが重要です。
ヘッダー ファイルで宣言されたものは、リンカーがロールアラウンドするまでにほとんど失われます。シンボルは、ヘッダー ファイルではなく、コンパイル ユニットによって作成されます。ヘッダーファイルは、シンボルが後で具体的に作成されるか、リンクによって実行されるという約束をほとんど生成しますが、それ自体でシンボルを作成することはできません (そうしないと、すべてのコンパイルユニット - すべての .o - のコピーになってしまいます)シンボルと陽気さは、リンク時に発生します)。
Objective-C は完全に動的です。あなたが言うとき[(id)foo bar];
、唯一の要件はそれがどこか前にbar
定義されていることです。実際に実装されているかどうかは問題ではありません (とにかく実行時まで)。
カテゴリは、対応する @implementation を持つ必要はありません。カテゴリは、メソッドが存在する可能性があることを宣言するために使用できます。実際、に追加@optional
する前は、「ねえ、このオプションのメソッドは実行時に存在する可能性があります」と言わないで (ewwwwww) で@protocol
カテゴリを使用するのが一般的でした。NSObject
@implementation
コンパイルとリンクは完全に別のプロセスです。コンパイルとは、コードを展開し、それを実行可能なバイトのライブラリに変換することです。リンクとは、ライブラリ間のすべての依存関係の解決を含め、これらのライブラリを実際に実行できるものにまとめることです。コンパイラは、何かがどのようにリンクされているかを実際には認識していません。リンカは、(ハード シンボルを生成しなかった) ものがどこで定義されている可能性があるかについての情報を持っていません。
最終結果?
リンカーには、依存関係を解決するための十分な情報がありません。