web-dev-qa-db-ja.com

静的ライブラリのシンボルに-fvisibilityオプションを適用する方法は?

4つの静的ライブラリ(.a)と1つのオブジェクト(.o)ファイルから構築された共有ライブラリプロジェクトがあります。 -fvisibility=hiddenオプションを追加して、出力のシンボルを、ソースで__attribute__を使用してマークしたシンボルのみに制限しようとしています。

-fvisibility=hiddenプロジェクト(.soファイルをカバーする)と.oプロジェクトのコンパイルオプションに.aオプションを追加しました。

オブジェクトファイル内のシンボルは、最終的な.soから期待どおりに削除されます。ただし、.aプロジェクトのシンボルはすべて、最終的な.soファイルに残っています。 -fvisibility=hiddenオプションを.soリンクコマンドに追加しても効果はありません。

何が悪いのですか?

ここでの目的は、.soから、ライブラリへのインターフェイス関数を除くすべてのシンボルを削除することです。

編集:私は実際にこれを解決するために バージョンマップ を実際に使用しました。ただし、外部シンボルが変更されると、バージョンスクリプトの継続的なメンテナンスが必要になります。受け入れられた答えはより良いアイデアを持っています。

47
Steve Fallows

基本的に、可視性はリンク中に処理され、リンカーは静的アーカイブにそれを課すようには見えません。 SO here )に関連する質問(重複ではありません)が尋ねられました。

リンクステージを置き換えることをお勧めします:gcc -shared -o mylib.so foo.o libbar.aを2段階のプロセスに入れ、オブジェクトファイルを取得します。

  • ar x libbar.a(おそらく適切な空のディレクトリに)
  • gcc -fvisibility=hidden -shared -o mylib.so foo.o tempdir/*.o
30
F'x

単に-Wl,--exclude-libs,ALLをgccに渡します

これにより、静的ライブラリ内のすべてのシンボルを非表示に変換するようリンカーに指示します。

--exclude-libsは、シンボルを非表示にするライブラリをより細かくするために、アーカイブのリスト(つまり、静的ライブラリ名)も受け入れます。

注:これは、GNU binutils(例:Linux)を使用するシステム、または--exclude-libsをサポートするリンカーを使用するシステムでのみ機能します(例:OSXで機能しません。 ld64)

59
fons

これはOS Xの問題に対する答えです。

Mac ld--exclude-libsをサポートしていませんが、-exported_symbol symをサポートしていますdoesこれを静的ライブラリのオブジェクトファイルに適用します。そして、パブリックAPIにフィルターをかける場合、ホワイトリストはそれを説明するのに十分なほど小さいです。

最終的に、Makefileに次のコードが含まれ、エクスポートされた各シンボルの-Wl,-exported_symbol,_api_func_1フラグが生成されました。

SYMBOLS   = api_func_1 api_func_2 api_func_3 api_func_4
SYMBOLS   += api_func_5 # add more as necessary
COMMA     = ,
LDFLAGS   += $(addprefix -Wl$(COMMA)-exported_symbol$(COMMA)_,$(SYMBOLS))

# ...

libmyapi.so: # ...
    $(CC) -shared -o $@ ... $(LDFLAGS)

次に、このバージョンのフラグとGNU ldバージョンのシステム間で検出されたリンカーを検出した後、ldバージョンの間でif-gateを実行できます。

5
Riking