1つの共有ライブラリにリンクする静的ライブラリがいくつかあります。そのうちの1つ、たとえばlibUsefulFunc.aには、libUsingFunc.aでホストされているusingFunc.cにある、別の静的ライブラリ、たとえばusingFunc()からのみ使用される関数usefulFunc()を含むオブジェクトファイルusefulFunc.oが含まれています。
問題は、リンカが役に立つFunc.oを破棄し、「未定義の参照」というエラーが発生することです。両方のリンク順序を試しました。
考えられる最も単純なファイルを使用して状況を再現しました。
ああ
extern int foo();
交流
#include "a.h"
int foo()
{
return 13;
}
紀元前
#include "a.h"
extern int b()
{
return print("a = %d\n", foo());
}
すべてを構築する:
gcc -c a.c -o a.o
gcc -c b.c -o b.o
ar q b.a b.o
ar q a.a a.o
ld -shared -o test.so ./b.a ./a.a
nm ./test.so
00001034 A __bss_start
00001034 A _edata
00001034 A _end
アーカイブの代わりにオブジェクトファイルを提供する場合:
ld -shared -o test.so ./a.o ./b.o
nm ./test.so
00001220 a _DYNAMIC
00000000 a _GLOBAL_OFFSET_TABLE_
00001298 A __bss_start
00001298 A _edata
00001298 A _end
000001a0 T b
00000194 T foo
U print
すべてのオブジェクトファイルを一覧表示せずに、リンカに未使用と思われるオブジェクトファイルを破棄しないように指示する方法はありますか?--whole-archiveオプションがあることは知っていますが、Android NDKプロジェクトの一部としてライブラリをビルドし、特定のライブラリにこのオプションを渡す方法が見つかりませんでした。
更新元の問題を完全に理解し、正しい解決策を見つけました。上記の私の例の最初に、リンカーはエントリポイントから開始し、使用するすべてのシンボルを検索します。これらは現在のライブラリで検索されます。見つかったら、使用する記号をリストに追加して強制します。ライブラリは1回だけ処理され、コマンドラインに表示される順序で処理されます。したがって、2番目のライブラリが最初のライブラリのシンボルを使用する場合、リンカーは戻らないため、シンボルは未定義のままになります。したがって、私の例では、b()が外部から呼び出されることを彼に伝える必要がありました。これは、-undefined=bを使用して行うことができます。
ld -shared -o test.so --undefined=b ./b.a ./a.a
元の問題では、2つの静的ライブラリ間に循環参照がありました。まるで私がbアーカイブにfoo()から呼び出される関数foo_b()を持つファイルb1.cを持っているかのように。そのような場合、私が見つけた3つの可能な解決策があります。
- bを2回リストします。ld-shared-otest.so --undefined = b ./ba ./aa ./ba
- --whole-archiveを使用します
- --start-grouparchives--end-groupオプションを使用します。指定されたアーカイブは、新しい未定義の参照が作成されなくなるまで繰り返し検索されます。
Android NDKライブラリの場合、NDKのmakefileはアーカイブグループを指定する方法を提供しないため、最初と2番目のオプションのみが使用可能であるように見えます
これが他の人にも役立つことを願っています!