同じ名前の関数を提供する2つのライブラリがある場合、どうすればよいですか?
コメントを適切に:「エクスポート」とは、ライブラリにリンクしているモジュールから見えるようにすることを意味します。ファイルスコープの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システムが同様の機能をサポートしていることは知っていますが、その名前を考えることはできません。
ここに考えがあります。 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番目のライブラリ/関数を使用する前に最初のライブラリを閉じます。
この問題が、c ++に名前空間がある理由です。同じ名前を持つ2つのサードパーティライブラリのcには、実際には優れたソリューションはありません。
動的オブジェクトの場合、共有オブジェクト(LoadLibrary/dlopen/etc)を明示的にロードし、その方法で呼び出すことができる場合があります。あるいは、同じコードで両方のライブラリを同時に必要としない場合は、静的リンクで何かを行うことができます(.lib/.aファイルがある場合)。
もちろん、これらのソリューションはすべてのプロジェクトに当てはまりません。
誓う?私の知る限り、同じ名前のリンクポイントを公開する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ファイル内の特定のシンボルの名前を変更します。それらの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ファイルはリンクにのみ使用され、コードの実行には使用されません。) 。dllファイルとヘッダーファイルがある場合の.libファイルの作成方法 libのビルドプロセスを参照してください。ファイル。ここでの唯一の違いは、エイリアスを追加することです。
LinuxとWindowsの両方で、名前がエイリアスされているライブラリのヘッダー内の関数の名前を変更します。動作する別のオプションは、新しい名前を参照するファイルで、#define old_name new_name、#includeがエクスポートされているライブラリのヘッダーを含める、そして呼び出し元で#undef old_nameを使用することです。ライブラリを使用するファイルが多数ある場合は、定義、インクルード、およびundefsをラップするヘッダーを作成してから、そのヘッダーを使用する方が簡単です。
この情報がお役に立てば幸いです!
Dlsym、dlopen、dlerror、dlclose、dlvsymなどを使用したことはありませんが、manページを見て、libm.soを開いてcos関数を抽出する例を示します。 dlopenは衝突を探すプロセスを経ますか?そうでない場合、OPは両方のライブラリを手動でロードし、ライブラリが提供するすべての機能に新しい名前を割り当てることができます。