2つの異なる共有ライブラリにリンクしています。両方のライブラリは、名前を共有するが実装が異なるいくつかのシンボルを定義します。ライブラリごとに独自の実装を使用することはできません。
たとえば、両方のライブラリは、それぞれが内部的に呼び出すグローバル関数bar()
を定義します。ライブラリ1はfoo1()
から呼び出し、ライブラリ2はfoo2()
から呼び出します。
Lib1.so:
_T bar
T foo1() // calls bar()
_
Lib2.so:
_T bar
T foo2() // calls bar()
_
アプリケーションをLib1.soにリンクし、次にLib2.soにリンクすると、foo2()
を呼び出している場合でも、Lib1.soからのバー実装が呼び出されます。一方、アプリケーションをLib2.soにリンクし、次にLib1.soにリンクした場合、barは常にLib2.soから呼び出されます。
ライブラリに他のライブラリよりも常に独自の実装を優先させる方法はありますか?
これを解決するにはいくつかの方法があります。
-Bsymbolic
または-Bsymbolic-functions
をリンカ。これにはグローバルな効果があります。ライブラリ内のシンボルに解決できる(-Bsymbolic-functions
の関数型の)グローバルシンボルへのすべての参照は、そのシンボルに解決されます。これにより、LD_PRELOADを使用してこれらのシンボルへの内部ライブラリ呼び出しを挿入する機能が失われます。 シンボルは引き続きエクスポートされるため、ライブラリの外部から参照できます。
バージョンスクリプトを使用して、ライブラリに対してシンボルをlocalとしてマークします。 {local: bar;};
のようなものを使用し、--version-script=versionfile
をリンカーに渡します。 シンボルはエクスポートされません
シンボルを適切なvisibility( GCC info page for visibility )でマークします。これはのどちらかになりますhidden、internal、またはprotected。 protected可視性シンボルは.protected
としてエクスポートされます、hiddenシンボルはエクスポートされません、およびinternalシンボルはエクスポートされず、関数ポインタを介して間接的にさえ、ライブラリの外部からそれらを呼び出さないように妥協します。
エクスポートされるシンボルはobjdump -T
で確認できます。
既存の各ライブラリに1つずつ、2つの「ラッパー」共有ライブラリを作成する必要があります。それぞれは、APIを定義する競合しないいくつかのシンボルのみをリストする--dynamic-listで構築する必要があります。グローバルな組み合わせを回避するには、-Bsymbolicも必要です。
同様に、適切なオプションを使用してdlopen経由で結果のライブラリにアクセスする方がストレスが少ないかもしれません。
この問題を解決する別の方法は、マクロを使用して名前空間を変更することです。
前提条件
ソリューション
-DLibNS=LibNSv1
を使用し、もう1つのケースでは-DLibNS=LibNSv2
を使用します。コードでライブラリを使用する場合は、現在の状況に応じてマクロを定義します。
#define LibNS LibNSv1
#include "my_lib.h"
#undef LibNS
他のソリューションの代わりにこれを使用する理由
潜在的な問題
#include "my_lib.h"
は、おそらくマクロを使用して複数の包含から保護し、それらを未定義にしてこれを回避します。これにより、さまざまな問題が発生する可能性があります(ライブラリの作成者が将来マクロ名を変更する、ヘッダーが他のマクロを定義するなど)。LibNS
は、ライブラリ内の他の何か(変数、関数など)に使用される場合があります。その場合、この名前もLibNSv1
またはLibNSv2
に変更されます。ライブラリとその使用方法によっては、他の問題が発生する可能性があります。注意事項