リンカーが実行可能出力ファイルを生成する際のデフォルト動作は、「未定義のままのシンボルが存在するかぎり、適切なエラーメッセージを出力して処理を終了する」というものです。次のように、再配置可能オブジェクト内のシンボル参照が、シンボル定義と絶対に一致しない場合に、シンボルは定義されないままの状態になります。
$ cat main.c extern int foo(); int main() { return (foo()); } $ cc -o prog main.c Undefined first referenced symbol in file foo main.o ld: fatal: Symbol referencing errors. No output written to prog |
同様に、共有オブジェクトを使って動的実行可能ファイルを作成する場合、未解決のままのシンボル定義が存在していると、未定義シンボルエラーが発生します。
$ cat foo.c extern int bar; int foo() { return (bar); } $ cc -o libfoo.so -G -K pic foo.c $ cc -o prog main.c -L. -lfoo Undefined first referenced symbol in file bar ./libfoo.so ld: fatal: Symbol referencing errors. No output written to prog |
前の例のように未定義シンボルを許可するには、リンカーの -z nodefs オプションを使用して、デフォルトエラー条件を抑制します。
-z nodefs オプションを使用する場合は、注意が必要です。処理の実行中に使用できないシンボル参照が要求されると、重大な実行時再配置エラーが発生します。このエラーは、アプリケーションをはじめて実行およびテストした際に検出される場合があります。しかし、実行パスがより複雑であるとエラー状態の検出に時間がかかり、時間とコストが浪費される場合があります。
シンボルは、再配置可能オブジェクト内のシンボル参照が、暗黙の内に定義された共有オブジェクト内のシンボル定義に結合されている場合にも、未定義シンボルのままになる場合があります。たとえば、上記の例で使用したファイル main.c および foo.c に次のように続く場合です。
$ cat bar.c int bar = 1; $ cc -o libbar.so -R. -G -K pic bar.c -L. -lfoo $ ldd libbar.so libfoo.so => ./libfoo.so $ cc -o prog main.c -L. -lbar Undefined first referenced symbol in file foo main.o (symbol belongs to implicit \ dependency ./libfoo.so) ld: fatal: Symbol referencing errors. No output written to prog |
prog は、libbar.so に対する「明示的」な参照に基づいて構築されます。libbar.so は、libfoo.so に依存しています。したがって、libfoo.so への暗黙的参照が prog から確立されます。
main.c は、libfoo.so によって作成されたインタフェースへの特定の参照を実行するため、prog は、実際に libfoo.so に依存性を持つことになります。ただし、生成される出力ファイル内に記録されるのは、明示的な共有オブジェクトの依存関係だけです。そのため、libbar.so の新しいバージョンが開発され、libfoo.so への依存性がなくなった場合、prog は実行に失敗します。
このため、このタイプの結合は致命的とみなされます。暗黙的参照は、prog のリンク編集中に直接ライブラリを参照することで明示的に行います。この例で示した重大なエラーメッセージ内に必要な参照のヒントがあります。