同等の名前の関数を提供する2つのライブラリがある場合はどうすればよいですか?
vorbis_...
、sf_...
、sdl_...
)。これは基本的に、C ++が名前空間付き関数のシンボル名に対して行うことです。
同等の名前の関数を提供する2つのライブラリがある場合はどうすればよいですか?
vorbis_...
、sf_...
、sdl_...
)。これは基本的に、C ++が名前空間付き関数のシンボル名に対して行うことです。
回答:
コメントを適切に:「エクスポート」とは、ライブラリにリンクしているモジュールから見えるようにすることを意味します--- extern
ファイルスコープのキーワードと同等です。これがどのように制御されるかは、OSとリンカーに依存します。そしてそれは私がいつも見上げなければならないものです。
を使用してオブジェクトファイル内のシンボルの名前を変更できますobjcopy --redefine-sym old=new file
(man objcopyを参照)。
次に、新しい名前を使用して関数を呼び出し、新しいオブジェクトファイルにリンクします。
Windowsでは、LoadLibrary()を使用してこれらのライブラリの1つをメモリにロードし、次にGetProcAddress()を使用して、呼び出す必要がある各関数のアドレスを取得し、関数ポインターを介して関数を呼び出すことができます。
例えば
HMODULE lib = LoadLibrary("foo.dll");
void *p = GetProcAddress(lib, "bar");
// cast p to the approriate function pointer type (fp) and call it
(*fp)(arg1, arg2...);
FreeLibrary(lib);
foo.dll内のbarという名前の関数のアドレスを取得して呼び出します。
Unixシステムが同様の機能をサポートしていることは知っていますが、その名前は思いつきません。
dlopen
dlsym
、およびdlclose
。ただし、Unixでのカプセル化は、Windowsほど効果的ではない場合があります。
ここに考えがあります。16進エディタで問題のあるライブラリの1つを開き、問題のある文字列のすべての出現箇所を別のものに変更します。これで、今後のすべての呼び出しで新しい名前を使用できるようになります。
更新: 私はこの目的のためにそれをやっただけで、うまくいくようです。 もちろん、私はこれを徹底的にテストしていません-hexeditショットガンで脚を吹き飛ばす本当に良い方法に過ぎないかもしれません。
Linuxを使用すると仮定すると、最初に追加する必要があります
#include <dlfcn.h>
たとえば、適切なコンテキストで関数ポインタ変数を宣言します。
int (*alternative_server_init)(int, char **, char **);
https://stackoverflow.com/a/678453/1635364で述べられているFerruccioのように、実行して、使用するライブラリを明示的にロードします(お気に入りのフラグを選択します)。
void* dlhandle;
void* sym;
dlhandle = dlopen("/home/jdoe/src/libwhatnot.so.10", RTLD_NOW|RTLD_LOCAL);
後で呼び出す関数のアドレスを読み取る
sym = dlsym(dlhandle, "conflicting_server_init");
次のように割り当ててキャストする
alternative_server_init = (int (*)(int, char**, char**))sym;
オリジナルと同じように呼び出します。最後に、実行してアンロードします
dlclose(dlhandle);
一緒に使用しないでください。私が正しく覚えていると、そのような場合にリンカがエラーを発行します。
私がしようとしませんでしたが、解決策がある可能性がありdlopen()
、dlsym()
そしてdlclose()
そのあなたがプログラムで動的ライブラリを処理することができます。2つの関数が同時に必要ない場合は、最初のライブラリを開き、最初の関数を使用して、2番目のライブラリ/関数を使用する前に最初のライブラリを閉じます。
そこに.oファイルがある場合、良い答えはここにあります:https : //stackoverflow.com/a/6940389/4705766
概要:
objcopy --prefix-symbols=pre_string test.o
.oファイル内のシンボルの名前を変更するには または
objcopy --redefine-sym old_str=new_str test.o
.oファイル内の特定のシンボルの名前を変更します。この問題が、c ++に名前空間がある理由です。同じ名前を持つ2つのサードパーティライブラリのcには、本当に素晴らしいソリューションはありません。
動的オブジェクトの場合、共有オブジェクト(LoadLibrary / dlopen / etc)を明示的にロードして、その方法で呼び出すことができる場合があります。あるいは、同じコードで同時に両方のライブラリが必要ない場合は、静的リンクを使用して何かを実行できます(.lib / .aファイルがある場合)。
もちろん、これらのソリューションはすべてのプロジェクトに適用されません。
誓う?私が知る限り、同じ名前のリンクポイントを公開する2つのライブラリがあり、両方に対してリンクする必要がある場合、できることは多くありません。
あなたはそれらの一つの周りのラッパーライブラリを書くべきです。ラッパーライブラリは、一意の名前のシンボルを公開する必要があります。一意でない名前のシンボルは公開しないでください。
もう1つのオプションは、ヘッダーファイルで関数名を変更し、ライブラリオブジェクトアーカイブでシンボルの名前を変更することです。
どちらにしても、両方を使用するには、ハックジョブになります。
質問は10年前に近づいていますが、常に新しい検索があります...
すでに答えたように、-redefine-symフラグを指定したobjcopyは、Linuxでは適切な選択です。完全なドキュメントについては、たとえば、https://linux.die.net/man/1/objcopyを参照してください。変更を加えながら基本的にライブラリ全体をコピーしており、更新のたびにこの作業を繰り返す必要があるため、少し不格好です。しかし、少なくともそれはうまくいくはずです。
Windowsの場合、ライブラリを動的にロードすることは解決策であり、Linuxのdlopen代替のような永続的なものは解決策です。ただし、dlopen()とLoadLibrary()の両方でコードが追加され、名前の重複のみが問題の場合は回避できます。ここで、Windowsソリューションはobjcopyアプローチよりもエレガントです。ライブラリ内のシンボルが他の名前で知られていることをリンカーに伝え、その名前を使用するだけです。それを行うにはいくつかのステップがあります。defファイルを作成し、EXPORTSセクションで名前の変換を提供する必要があります。https://msdn.microsoft.com/en-us/library/hyx1zcd3.aspx(VS2015、最終的には新しいバージョンに置き換えられる)を参照してください。または http://www.digitalmars.com/ctg/ctgDefFiles.html(おそらくより永続的)defファイルの完全な構文の詳細。このプロセスでは、ライブラリの1つにdefファイルを作成し、このdefファイルを使用してlibファイルを作成し、そのlibファイルにリンクします。(Windows DLLの場合、libファイルはリンクにのみ使用され、コード実行には使用されません。)libファイルをビルドするプロセスの.dllファイルとヘッダーファイルがある場合に.libファイルを作成する方法を参照してください。ここでの唯一の違いは、エイリアスの追加です。
LinuxとWindowsの両方で、名前がエイリアスされているライブラリのヘッダーの関数の名前を変更します。機能するもう1つのオプションは、新しい名前を参照するファイルで、#define old_name new_nameを実行し、#エクスポートのエイリアスが設定されているライブラリのヘッダーを含め、呼び出し元で#undef old_nameを実行することです。ライブラリを使用しているファイルが多数ある場合、より簡単な代替方法は、定義、インクルード、およびundefsをラップするヘッダーを作成し、そのヘッダーを使用することです。
この情報がお役に立てば幸いです。
私はdlsym、dlopen、dlerror、dlclose、dlvsymなどを使用したことがありませんが、manページを調べています。これは、libm.soを開いてcos関数を抽出する例を示しています。dlopenは衝突を探すプロセスを実行しますか?そうでない場合、OPは両方のライブラリを手動でロードし、ライブラリが提供するすべての関数に新しい名前を割り当てるだけです。