17

注:完全に機能する例を以下に示します。元の質問は次のとおりです。

ldの-rpathパラメータを。で使用すると問題が発生します$ORIGIN
完全な例が見つからなかったので、後で自分や他の人が使えるように、自分で書いてみようと思いました。動作するようになったら、片付けます。

以前に質問しましたが、私の投稿は少し混乱していたと思います。

サンプルプロジェクトは、1つの共有ライブラリとそのライブラリにリンクする1つの実行可能ファイルをビルドします。
非常に小さいです(3ファイル、ビルドスクリプトを含む22行)。ここ
からプロジェクトをダウンロードできます


ファイル構造(ビルド前):

  • project/
    • src/
      • foo.cpp
      • main.cpp
    • make.sh

project/src/foo.cpp


int foo()
  { return 3; }

project/src/main.cpp


int foo();

#include <iostream>
int main()
  {
    std::cout << foo() << std::endl;
    return 0;
  }

project/make.sh


# Make directories:
mkdir -p -v obj
mkdir -p -v lib
mkdir -p -v run

# Build the library:
g++ -c -o obj/foo.o src/foo.cpp -fPIC
g++ -shared -o lib/foo.sh obj/foo.o

# Build the executable:
g++ -c -o obj/main.o src/main.cpp
g++ -o run/main.run obj/main.o -Wl,-rpath,'$ORIGIN/../../lib' -Llib -l:foo.sh

projectディレクトリから実行します(make.sh実行可能であることを確認してください)。


ファイル構造(ビルド後):

  • project/
    • src/
      • foo.cpp
      • main.cpp
    • obj/
      • foo.o
      • main.o
    • lib/
      • foo.so
    • run/
      • main.run
    • make.sh

run/main.runlib/foo.shこれで、どこからでも実行時にロードされるはずです。


問題

現在、これは部分的にしか機能しません。ファイルはコンパイルされ、リンクはOKですが、(演習のポイントである)
以外のディレクトリから実行するとリンクに失敗します。project

main.runショーでの検査readelf -d
0x0000000000000001 (NEEDED) Shared library: [lib/foo.sh]
0x000000000000000f (RPATH) Library rpath: [$ORIGIN/../../lib] どちらが近いように見えますか(私はむしろ持っていると思い[foo.sh]ます[lib/foo.sh]が、後で修正します)。

AFAICT $ORIGINinは、このrpathがになるようにすることを-Wl,-rpath,'$ORIGIN/../../lib'意味します。project/run/main.runproject/lib

私は、、、、無駄にしようとしました$ORIGIN/..$ORIGIN/../lib$ORIGIN/../..$ORIGIN/../../lib

注:私は-l:完全なライブラリファイル名を必要とするものを使用しています(他の理由の中でも、すべての関数が同じ名前形式をとる場合、変数を使用してスクリプトを作成する方が簡単です)。

なぜこれが機能しないのか誰かが知っていますか?
または、代わりに、誰かが完全な実例を持っているか知っていますか?

4

2 に答える 2

6

(私はむしろ持っていると思い[foo.sh]ます[lib/foo.sh]が、後で修正します)。

あなたの問題のほとんどがあります:/名前の中には、ダイナミックリンカーがrpathマジックを実行するのを止めます。

(rpathも間違っています。考えてみてください。シェルから、現在実行可能ファイルがあるディレクトリにいる場合、ライブラリがあるディレクトリにどのようにアクセスしますか?ここで、必要になりcd ../libます。したがって、rpathする必要があります$ORIGIN/../lib。)

オブジェクトをとして構築し、libfoo.soとリンクした-Llib -lfoo場合、リンカーは意図したとおりに機能し、正しいことを実行します。ただし、通常とは異なる命名規則を使用する場合は、次のことを支援する必要があります。

  1. ライブラリのリンク行を変更して、ライブラリのSONAMEを次のように明示的に設定しますfoo.sh

    g++ -shared -Wl,-soname,foo.sh -o lib/foo.sh obj/foo.o

  2. rpathを修正します。

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

何が起こっているかを確認するために実行すると便利ですldd main/main.run。元の失敗したケースでは、次のようなものが表示されます。

    lib/foo.sh (0xNNNNNNNN)

=> /some/resolved/pathパス解決が行われていないことを示すものがない)。固定の場合、次のように表示されます。

    foo.sh => /your/path/to/run/../lib/foo.sh (0xNNNNNNNN)
于 2011-06-10T20:22:36.380 に答える
5

$ORIGINこれは、でを使用した相対パスリンク(ldを使用)の例ですrpath

rpathは、バイナリファイル(共有ライブラリ(.so)および実行可能ファイル)に埋め込まれたパス(またはパスのセット)です。
これらのパスは、実行時にバイナリをリンクする必要がある共有ライブラリの最も重要な検索パスです。

$ ORIGINは、rpathパスの潜在的な開始ディレクトリです。実行中のファイルを含むディレクトリに解決されます。(例$ORIGIN/lib:)

rpathサンプルプロジェクトは、とを使用して上記のライブラリにリンクする1つの共有ライブラリと1つの実行可能ファイルを構築します$ORIGINここ
からプロジェクトをダウンロードできます。


ファイル構造(ビルド前):

  • project/
    • src/
      • foo.cpp
      • main.cpp
    • make.sh

project/src/foo.cpp


int foo()
  { return 3; }

project/src/main.cpp


int foo();

#include <iostream>
int main()
  {
    std::cout << foo() << std::endl;
    return 0;
  }

project/make.sh


# Make directories:
mkdir -p -v obj
mkdir -p -v lib/dir
mkdir -p -v run

# Build the library:
g++ -c -o obj/foo.o src/foo.cpp -fPIC
g++ -shared -o lib/dir/foo.so -Wl,-soname,foo.so obj/foo.o

# Build the executable:
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

projectディレクトリから実行します(実行make.shされない場合は、make.sh実行権限があることを確認してください)。

すべて問題がなければ、への絶対パス(どこにでも移動できます)や現在の作業ディレクトリ(どこからでも実行できます)に関係なく、実行時にmain.runロードする必要があります。lib/dir/foo.soproject


ノート:

  • -fPIC再配置可能オブジェクトファイルをビルドするようにコンパイラに指示します(共有ライブラリにビルドされるオブジェクトファイルは再配置可能である必要があります)。
  • -Wl,-soname,<NAME><NAME>生成されたライブラリに埋め込みます。これは、このライブラリにリンクするとき に、-lまたはオプションに指定する名前と一致する必要があります。-l:
  • -Wl,-rpath,'<PATH>'<PATH>生成されたライブラリにランタイムライブラリ検索パス(またはrpath-上記を参照)として埋め込みます。
  • -Lビルド時ライブラリ検索パスリストにパスを追加します。(注:rpathビルド時に-Lは無関係であり、実行時には無関係です)。
  • -l:リンク先のライブラリのファイル名(パスなし)を追加します。(完全なファイル名が必要なこと-lを除いて、と同様です。-l:

ファイル構造(ビルド後):

  • project/
    • src/
      • foo.cpp
      • main.cpp
    • obj/
      • foo.o
      • main.o
    • lib/
      • dir/
        • foo.so
    • run/
      • main.run
    • make.sh

注:私は-l:完全なライブラリファイル名を必要とするものを使用しています(他の理由の中でも、すべての関数が同じ名前形式をとる場合、変数を使用してスクリプトを作成する方が簡単です)。
を使用するのがより一般的で-lあり、これ-l<NAME>はlib.soを示します。

制限事項

私が知っている限り(間違っている場合は訂正してください)、検索パス内のサブディレクトリ内にライブラリを追加する方法はありません(そのディレクトリをサブパスとして追加する場合を除く)。-Lこれは、ビルド時( )と実行時()の両方の-rpath検索パスに当てはまります。

したがって、同じ名前で場所が異なる2つのライブラリがある場合、両方をリンクすることはできません。(私が間違っているか、これが修正されることを願っています)。

于 2011-06-12T16:56:39.993 に答える