7

2つの共有ライブラリ(コンパイルしたもの)を使用するプログラムを作成し、次のように配置しました。

/home_directory_where_I_compile_and_run_everything
-->/lib/libjson_linux-gcc-4.4.6_libmt.so
-->/lib/libre2.so.0

プログラムをコンパイルするとき、次のように、これらのライブラリの相対的な場所をリンカーに渡します。

g++ ...... stuff ........ my_program.cc lib/libjson_linux-gcc-4.4.6_libmt.so lib/libre2.so.0

そしてそれはうまくコンパイルされます、しかしプログラムを実行するときそれはlibre2.soを見つけることができません、そして私がそれをlddで調べるならば、これは何が起こるかです:

....
lib/libjson_linux-gcc-4.4.6_libmt.so (0x00007f62906bc000)
libre2.so.0 => not found
....

どうやら、libjsonのパスは相対的であることを認識していますが、libre2.so.0ではそれを行いません(すべてのパスをトリミングし、libre2.so.0をそのままにします)

なぜこれが起こるのか誰かに教えてもらえますか?

また、g ++引数を介してこれを変更する方法はありますか?

一番。

*更新*おっ、これをチェックしてください!libre2.so.0の名前をstuff.soに変更してから、基本的に次のようにコンパイルしようとしました。

g++ ...... stuff ........ my_program.cc lib/libjson_linux-gcc-4.4.6_libmt.so lib/stuff.so

そしてそれはとにかく失敗します。失敗するだけでなく、「libre2.so.0」が見つからないため失敗します。

なんで?

*アップデート#2 *

の出力readelf -d the_program.o

0x0000000000000001 (NEEDED)             Shared library: [lib/libjson_linux-gcc-4.4.6_libmt.so]
0x0000000000000001 (NEEDED)             Shared library: [libre2.so.0]

さて、その[libre2.so.0]を[lib / libre2.so.0]にすることができれば、それで問題ありません。

*アップデート#3 *

@troubadourが見つけたように:

実行可能ファイルがDT_SONAMEフィールドを持つ共有オブジェクトにリンクされている場合、実行可能ファイルが実行されると、ダイナミックリンカは、リンカに指定されたファイル名を使用するのではなく、DT_SONAMEフィールドで指定された共有オブジェクトをロードしようとします。

これが、libre2.so.0ではなくlibjson.....soで機能する理由です。(libjson ..... soにはSONAMEのエントリがありません)。

そして、私はついに私が探しているものについての正確な質問を見つけました:

共有ライブラリファイルのSONAMEエントリを無視し、代わりに特定のファイルパスにリンクするようにgccリンカーに指示する方法はありますか?

4

4 に答える 4

12

最初に質問の 2 番目の部分、つまり libre2.so.0 の名前を変更しても期待どおりにならなかった理由にお答えします。

リンカーに渡すファイル名は、実行可能ファイルを実行するときには関係ありません (-sonameライブラリのビルド時に指定しない限り、以下の 2 番目の編集を参照してください)。依存関係は、「soname」と呼ばれるものから取得されます。ライブラリでコマンドを実行すると、readelfその soname を特定できます。

readelf -d libre2.so.0 | grep SONAME

ファイルの名前を変更しても問題ありません。上記のコマンドの結果は、依然として同じ soname を提供するため、プログラムが「libre2.so.0」を見つけることができなかった理由です。

あなたの質問の元の部分に関しては、ライブラリにRPATHまたはRUNPATHが組み込まれているかどうか、および/またはLD_LIBRARY_PATH環境変数の内容が何であるかにかかっています。これらは、実行時リンカー (ld.so) が共有ライブラリを見つけるために使用するものです。試す

man ld.so

詳細については。

ライブラリを自分で構築したので、最終リンク段階で-rpathまたはオプションを使用したかどうかがわかります。-runpathまたは、もう一度使用readelfします。

readelf -d libre2.so.0 | grep RPATH
readelf -d libre2.so.0 | grep RUNPATH

上記の 2 つのコマンドは何も返さないと思います。

私の推測ではLD_LIBRARY_PATH、実行時リンカーが lib/libjson_linux-gcc-4.4.6_libmt.so を見つけられるが、libre2.so.0 を見つけられない現在のディレクトリがあると思います。あなたの質問に対する私のコメントに、あなたLD_LIBRARY_PATHが空であると言って返信したことに気付きました。それは変です。

おそらく、libjson の soname に接頭辞 "lib/" が付けられているのではないでしょうか? つまりreadelf、SONAME リターンのコマンドを実行しました

lib/libjson_linux-gcc-4.4.6_libmt.so

だけではなく

libjson_linux-gcc-4.4.6_libmt.so

また、実行して soname に関してプログラムが必要とするものを確認します

readelf -d my_progam | grep NEEDED

gcc に渡した方法が原因で、「lib/」プレフィックスがそこにある可能性があります。その場合、@enobayram から提供された gcc コマンドを使用すると、条件が整います。つまり、libjson の検索も失敗します。

最初に確立することは、libre2.so.0 が見つからない理由ではなく、libjson をどのように見つけているかです。別のディレクトリから実行可能ファイルを実行しようとすると、それはまだ機能しますか、それとも libjson でも失敗しますか? または、実行可能ファイルの横に libre2.so.0 をコピーすると、何かが変わりますか?

編集

Fedora フォーラムへの投稿では、ld.so の Fedora バージョンには現在のディレクトリが組み込みの検索パスとして含まれていることが示唆されています。私はこれを確認できませんでしたが、 ld.so が使用する他のすべてのものがあなたのケースに存在しないことを考えると、なぜあなたがライブラリを拾っているのかを説明するでしょう.

編集 2

私のシステムのld manページから

-soname=名前

ELF 共有オブジェクトを作成するときは、内部 DT_SONAME フィールドを指定された名前に設定します。実行可能ファイルが DT_SONAME フィールドを持つ共有オブジェクトにリンクされている場合、実行可能ファイルが実行されると、ダイナミック リンカーは、リンカーに指定されたファイル名を使用するのではなく、DT_SONAME フィールドで指定された共有オブジェクトをロードしようとします。

Copyright (c) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.

この文書は、GNU Free Documentation License、バージョン 1.3、または Free Software Foundation によって発行されたそれ以降のバージョンの条件に基づいて、コピー、配布、および/または変更する許可が与えられています。不変セクションなし、表紙テキストなし、裏表紙テキストなし。ライセンスのコピーは、「GNU Free Documentation License」というタイトルのセクションに含まれています。

したがって、あなたのコメントの理論は正しいです。ライブラリの構築時にno-sonameが明示的に指定されている場合、共有オブジェクトに SONAME は存在せず、実行可能ファイルの NEEDED フィールドには、リンカに指定されたファイル名が含まれているだけです。この場合、先頭の「lib/」が含まれています。

于 2012-04-17T22:15:42.833 に答える
3

共有ライブラリ (.so) に対してリンクする場合、これらはプログラムの実行時にライブラリ ロード パスに存在する必要があります。リンク時に指定した場所は、実行可能ファイルに「記憶」されていません。

代替ソリューション:

  • .so ファイルを実行可能ファイルと同じディレクトリに配置します。
  • で実行LD_LIBRARY_PATH=lib ./program
  • /usr/local/libプログラムを実行する前に、ライブラリ パス内の場所 (たとえば、.so ファイル) に .so ファイルをインストールします。
  • 静的にリンクする
于 2012-04-17T21:34:23.603 に答える
0

正しいコンパイラ コマンド ラインは次のようになります。

g++ ...... stuff ........ my_program.cc -Llib -ljson_linux-gcc-4.4.6_libmt -lre2

また、共有オブジェクトを標準ディレクトリ (/usr/lib など) に配置するか、それらのパスをに追加してLD_LIBRARY_PATH、実行可能ファイルを実行できるようにする必要があります。

于 2012-04-17T21:34:44.293 に答える