LDのオプション-RPATHを$ Originで使用する単純な(ハローワールド風)例を構築する
質問
注:以下の完全な作業例。元の質問は次のとおりです。
LDの使用に問題があります -rpath
でパラメーター $ORIGIN
.
私は完全な例を見つけることができなかったので、私と他の人が後でそれを使用できるように、自分で書くことを試みると思いました。私がそれを機能させたら、私はそれを片付けます。
私 前にこれについて尋ねました, 、しかし、私の投稿は少し混乱していたと思います。
この例プロジェクトは、1つの共有ライブラリと、上記のライブラリにリンクする1つの実行可能ファイルを構築します。
非常に小さい(3つのファイル、22行のbuildscript)。
プロジェクトをダウンロードできます ここ
ファイル構造(建物の前):
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.run
これでロードする必要があります lib/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 the $ORIGIN
の -Wl,-rpath,'$ORIGIN/../../lib'
意味 project/run/main.run
したがって、このrpathはなるはずです project/lib
.
私が試してみました $ORIGIN/..
, $ORIGIN/../lib
, $ORIGIN/../..
, $ORIGIN/../../lib
無駄に。
注:私は使用しています -l:
完全なライブラリファイル名が必要です(他の理由の中でも、すべての関数が同じ名前形式を取るときに変数をスクリプト化する方が簡単です)。
なぜこれが機能していないのか知っている人はいますか?
または、代わりに、誰かが完全な作業例を持っているか知っているか、知っていますか?
解決
(私はむしろ持っています
[foo.sh]
よりも[lib/foo.sh]
しかし、後で修正します)。
あなたの問題のほとんどがあります: /
名前では、ダイナミックリンカーがRPathマジックを実行するのを止めます。
(あなたのrpathも間違っています。それについて考えてください:シェルから、あなたが現在あなたの実行可能な場所にあるディレクトリにいたなら、あなたはあなたのライブラリがどこにあるかディレクトリにどのように到達しますか? cd ../lib
. 。したがって、あなたのrpathはそうあるべきです $ORIGIN/../lib
.)
あなたがあなたのオブジェクトをとして構築した場合 libfoo.so
とリンクしています -Llib -lfoo
, 、リンカーはあなたが意図していたものを解決し、正しいことをします。しかし、あなたが異常な命名規則を使用する場合、あなたはそれを助ける必要があります:
ライブラリのリンクラインを変更して、ライブラリのソナメを明示的に設定して、
foo.sh
:g++ -shared -Wl,-soname,foo.sh -o lib/foo.sh obj/foo.o
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)
他のヒント
これは、使用して(LDを使用して)相対パスリンクの例です。 $ORIGIN
で rpath
.
rpath バイナリファイル(共有ライブラリ(.so)および実行可能ファイル)に埋め込まれたパス(またはパスのセット)です。
これらのパスは、バイナリが実行時にリンクする必要がある共有ライブラリの最も重要な検索パスです。
$ origin RPATパスの潜在的な開始ディレクトリです。実行ファイルを含むディレクトリに解決します。 (例えば: $ORIGIN/lib
)
この例プロジェクトは、1つの共有ライブラリと、上記のライブラリにリンクする1つの実行可能ファイルを構築します rpath
と $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.so
実行時に、絶対的なパスに関係なく project
(どこにでも移動できます)、現在の作業ディレクトリに関係なく(どこからでも実行できます)。
ノート:
-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つのライブラリがあるが、異なる場所がある場合、両方をリンクすることはできません。 (私は間違っていることを願っていますか、これが修正されることを願っています)。