30

ここでld の-rpathオプションを使用する基本的な例を作成しました(動作するバージョンについては、2 番目の応答を参照してください)。にリンクし、次に にリンクし、すべてとを使用する例を作成しようとしています。$ORIGIN main.runfoo.sobar.sorpath$ORIGIN

実行時のファイル構造は次のとおりです。

  • 事業/
    • ライブラリ/
      • dir/
        • サブ/
          • bar.so
        • foo.so
    • 走る/
      • main.run (ビルドに失敗)

以下を使用して foo.so を構築しています。

g++ -c -o obj/foo.o src/foo.cpp -fPIC
g++ -shared -o lib/dir/foo.so obj/foo.o -Wl,-soname,foo.so -Wl,-rpath,'$ORIGIN/sub' -Llib/dir/sub -l:bar.so

これは問題なく構築されます。ldd lib/dir/foo.so見つけることさえできますbar.so

しかし、 にリンクしようとするとmain.runfoo.sobar.sofoo.soが見つかりません。

以下を使用して main.so を構築しています。

g++ -c -o obj/main.o src/main.cpp
g++ -o run/main.run obj/main.o -Wl,-rpath,'$ORIGIN/../lib/dir' -Llib/dir -l:foo.so

foo.so再帰的にリンクしない別のバージョンの が使用されている場合、これは正常に機能します。(以下のプロジェクトの make.sh の行のコメントを外してテストします)。

ただし、通常の使用では、foo.soビルド時にこのエラーが発生しますmain.run:

/usr/bin/ld: 警告: lib/dir/foo.so に必要な bar.so が見つかりません (-rpath または -rpath-link を使用してみてください)

だから私の質問は:

  1. foo.so$ORIGIN内ではproject/lib/dir(where foo.sois) またはproject/run(where main.run(リンクしている実行可能ファイル) is) に解決されますか?
    ldd は、それが であることを示しているように見えますがproject/lib/dir、これが最良の方法と思われます (ただし、両方を想定してみました)。
  2. これらをリンクするにはどうすればよいですか(再配置可能性を維持しながら)-できれば-rpath-link.

プロジェクトはこちらからダウンロードできます。それは私がそれを作ることができるのと同じくらい簡単です。4 つの短いソースとスクリプト。
解凍後、./make.sh内から実行するだけproject/です。

注:を使用して-l:います。foo.soこれは、ライブラリの名前が ではなく のようになり、の代わりにでlibfoo.soランク付けされることを除いて、何も変更されません。-l:foo.so-lfoo

4

6 に答える 6

8

さて、私は何かが働いています。しかし、なぜそれが機能するのかよくわかりません。これは、ld のバグのように感じます。

strace -f -o /var/tmp/strace.out -- g++ ...main.run コンパイルを実行しました。静的リンカは実際に、20 ~ 30 のファイルの中で、文字通りの名前が "$ORIGIN/lib/dir/sub/bar.so" のようなファイルを開こうとしています。(つまり、名前が付けられた実際のディレクトリを探してい$ORIGINます。真剣です。)

また、「bar.so」だけでなく、「lib/dir/sub/bar.so」という名前の -rpath-link パスを検索しているようにも見えます。理由はわかりません。

とにかく、これは私のために働いているmain.runのリンクです:

g++ -o run/main.run obj/main.o -Wl,-rpath,'$ORIGIN/../lib/dir' -Wl,-rpath-link,. -Llib/dir -l:foo.so

それはあなたのものと同じですが、-Wl,-rpath-link,.挿入されています。

【追記】

わかりました、何が起こっているのかわかりました。まず、静的リンカ (GNU ld) は、リンク先のライブラリで $ORIGIN を尊重しません。

-lbar次に、 vsを使用したときの動作-l:bar.soが大きく異なります。

で実行readelf -afoo.soます。ビルドでは、「lib/dir/sub/bar.so」への依存関係が示されています。これが、rpath-link を「.」に設定する理由です。main.run のビルドを修正。これにより、静的リンカは「.」を検索します。見つかった「lib/dir/sub/bar.so」の場合。

bar.so の名前を libbar.so に変更し、foo.so を-lbarの代わりに使用するようにリンクする-l:bar.soと、同じ readelf は、foo.so が "libbar.so" (パス コンポーネントなし) に依存するようになったことを示します。-Wl,-rpath-link,lib/dir/subその foo.so を使用すると、静的リンカーが単に $ORIGIN を尊重しないことを知っている場合に期待するように、を使用して main.run リンクを機能させることができます。

ところで、-l:bar.soGNU ld マニュアルのどこにも文書化された構文は見当たりません。好奇心から、どうやってそれを思いついたのですか?

これがサポートされている機能であると仮定すると、これはバグのように見えます (-l:bar.so は、bar.so だけでなく、lib/dir/sub/bar.so への依存関係を作成します)。rpath-link を「.」に設定することで、このバグに対処できます。または、通常の方法で名前を変更できます (libxxx.so)。

于 2011-06-12T18:55:54.763 に答える
7

ld-linux(8)マンページから:

$ORIGIN と rpath

ld.so は、rpath 仕様 (DT_RPATH または DT_RUNPATH) 内の文字列 $ORIGIN (または同等の ${ORIGIN}) を、アプリケーションの実行可能ファイルを含むディレクトリを意味するものと認識します。したがって、somedir/app にあるアプリケーションは、gcc -Wl,-rpath,'$ORIGIN/../lib' でコンパイルできるため、somedir がディレクトリ内のどこにあるかに関係なく、somedir/lib で関連付けられた共有ライブラリを見つけることができます。階層。これにより、特別なディレクトリにインストールする必要がなく、代わりに任意のディレクトリに展開して独自の共有ライブラリを見つけることができる「ターンキー」アプリケーションの作成が容易になります。

したがって、最初の質問への回答として、 : の値は 1 つだけ$ORIGINですproject/run

したがって、2 番目の質問に対する答えは、次のコマンドを使用してリンクすることfoo.soです。

g++ -shared -o lib/dir/foo.so obj/foo.o -Wl,-soname,foo.so -Wl,-rpath,'$ORIGIN/../lib/dir/sub' -Llib/dir/sub -l:bar.so
于 2014-07-14T16:10:37.697 に答える
5

まず、問題を引き起こしている可能性のある $ 記号の展開に関する問題があります。私はソースからPythonを構築していますが、これを行います:

export LDFLAGS='-Wl,-rpath,\$${ORIGIN}/../lib -Wl,-rpath,\$${ORIGIN}/../usr/lib -Wl,--enable-new-dtags'

実行する前にmake。これは正常に機能し、第 1 レベルの依存関係が検出されます。この種のマクロ展開の問題に対処するときは、一重引用符と二重引用符に注意してください。

次に、objdump -xバイナリまたはライブラリで実行すると、実際に含まれている RPATH ヘッダーを確認できます。実行するobjdump -x path/to/python |grep RPATHと、これが表示されます。RPATH ${ORIGIN}/../lib:${ORIGIN}/../usr/lib`

バイナリをチェックして、実際に RPATH ヘッダーに何が入っているかを確認することをお勧めします。残念ながら、これで問題が解決するとは思いません。これは私が実行したときに私が見るものですldd path/to/python:

libpython2.7.so.1.0 => /data1/python27/bin/../lib/libpython2.7.so.1.0 (0x00002ad369d4f000)
libpthread.so.0 => /lib/libpthread.so.0 (0x00002ad36a12f000)
libdl.so.2 => /lib/libdl.so.2 (0x00002ad36a34d000)
libutil.so.1 => /lib/libutil.so.1 (0x00002ad36a551000)
libm.so.6 => /lib/libm.so.6 (0x00002ad36a754000)
libc.so.6 => /lib/libc.so.6 (0x00002ad36a9d8000)
/lib64/ld-linux-x86-64.so.2 (0x00002ad369b2d000)

ご覧のとおり、第 1 レベルの依存関係は によって正しく処理されrpathますが、第 2 レベルの依存関係、つまり libpython の依存関係はシステム ライブラリに戻ります。はい、libpython のバイナリにはまったく同じ RPATH ヘッダーがあります。rpath recursiveディストリビューションに依存しないパッケージを作成するという私の問題を解決しようとグーグルで検索しているときに、あなたの質問を見つけました。

後で追加ヘッダー はrpath、ライブラリを検索する最初のパスのみを変更します。そこで見つからない場合、ローダーは通常の場所で検索を続けます。ldd検索の結果見つかったライブラリの実際のパスのみをリストします。rpathこれらのライブラリをディレクトリにコピーすると、すべてが機能しました。基本的に、すべての依存関係を見つけてコピーする整然とした方法はありませんldd -v path/to/python。その出力を解析するだけです。

于 2011-06-14T18:38:27.330 に答える
1

私もこれを調べてきましたが、-rpath-linkORIGIN 展開を使用するすべてのパスに使用する必要があると言えます。例えば:

CC -shared (other flags) -R'$ORIGIN/../lib/' -o /buildpath/lib/libmylib1.so
CC -shared (other flags) -R'$ORIGIN/../lib/' -lmylib1 -o /buildpath/lib/libmylib2.so
# This fails to link 'somebinary'
CC (various flags) -R'$ORIGIN/../lib/' -lmylib2 -o /buildpath/bin/somebinary
# This works correctly
CC (various flags) -R'$ORIGIN/../lib/' -Wl,-rpath-link,/buildpath/lib/mylib1 -lmylib2 -o /buildpath/bin/somebinary
# The text above the carets to the right is a typo: ------------------^^^^^^
# I'm fairly sure it should read like this (though it has been awhile since I wrote this):
# (...) -Wl,-rpath-link,/buildpath/lib -lmylib1 (...)

ld$ORIGINを使用して指定されたパス内、-rpath-linkまたはサブ依存関係の RPATH から取得したパス内では展開されません。上記の例では、にmylib2依存しmylib1ます。リンクsomebinary中に、libmylib2.so に埋め込まれ たリテラル/展開されていない文字列を使用しldて検索を試みます。実行時にしますが、そうではありません。mylib1$ORIGIN/../lib/ld.sold

また-L、サブ依存 librar(y|ies) を検索するために指定されたパスも使用しません。

于 2012-07-03T19:44:10.800 に答える