web-dev-qa-db-ja.com

実行ファイルと同じディレクトリに.soが見つかりませんか?

libtest.soと動的にリンクする必要がある実行可能ファイルがあるので、それらを同じディレクトリに置いてから、

cd path_to_dir
./binary

しかし、これを得た:

error while loading shared libraries: libtest.so: cannot open shared object file: No such file or directory

実行可能ファイル自体と同じディレクトリに既にあるlibtest.soを見つけることができないのはなぜですか?

47
linuxer

ローダーは、_$LD_LIBRARY_PATH_を介して明示的に指示されない限り、共有オブジェクトの現在のディレクトリを確認しません。詳細については、ld.so(8)のマニュアルページを参照してください。

LD_LIBRARY_PATHを設定して、ダイナミックリンカーに参照先を知らせることができますが、より優れたオプションがあります。共有ライブラリを標準の場所の1つに配置できます。これらの場所のリストについては、/etc/ld.so.conf(Linuxの場合)および/usr/bin/crle(Solarisの場合)を参照してください。

バイナリを構築するときに-R <path>をリンカーに渡すことができます。これにより、共有ライブラリをスキャンするディレクトリのリストに<path>が追加されます。例を示します。まず、問題を示します。

libtest.h:

void hello_world(void);

libtest.c:

#include <stdio.h>
void hello_world(void) {
  printf("Hello world, I'm a library!\n");
}

こんにちはC:

#include "libtest.h"
int main(int argc, char **argv) {
  hello_world();
}

Makefile(タブを使用する必要があります):

all: hello
hello: libtest.so.0
%.o: %.c
        $(CC) $(CFLAGS) -fPIC -c -o $@ $<
libtest.so.0.0.1: libtest.o
        $(CC) -shared -Wl,-soname,libtest.so.0 -o libtest.so.0.0.1 libtest.o
libtest.so.0: libtest.so.0.0.1
        ln -s $< $@
clean:
        rm -f hello libtest.o hello.o libtest.so.0.0.1 libtest.so.0

実行してみましょう:

$ make
cc  -fPIC -c -o libtest.o libtest.c
cc -shared -Wl,-soname,libtest.so.0 -o libtest.so.0.0.1 libtest.o
ln -s libtest.so.0.0.1 libtest.so.0
cc     hello.c libtest.so.0   -o hello
$ ./hello 
./hello: error while loading shared libraries: libtest.so.0: cannot open shared object file: No such file or directory

それを修正するには?リンカーフラグに-R <path>を追加します(ここでは、LDFLAGSを設定します)。

$ make clean
(...)
$ make LDFLAGS="-Wl,-R -Wl,/home/maciej/src/tmp"
(...)
cc   -Wl,-R -Wl,/home/maciej/src/tmp  hello.c libtest.so.0   -o hello
$ ./hello 
Hello world, I'm a library!

バイナリを見ると、libtest.so.0が必要であることがわかります。

$ objdump -p hello | grep NEEDED
  NEEDED               libtest.so.0
  NEEDED               libc.so.6

バイナリは、標準の場所とは別に、指定されたディレクトリでライブラリを探します。

$ objdump -p hello | grep RPATH
  RPATH                /home/maciej/src/tmp

バイナリを現在のディレクトリで検索する場合は、RPATHを$Originに設定できます。ドル記号がmakeによって解釈されないようにする必要があるため、これは少しトリッキーです。これを行う1つの方法を次に示します。

$ make CFLAGS="-fPIC" LDFLAGS="-Wl,-rpath '-Wl,\$\$Origin'"
$ objdump -p hello | grep RPATH
  RPATH                $Origin
$ ./hello 
Hello world, I'm a library!
59
automatthias

実行可能ファイルと同じディレクトリから共有オブジェクトをロードするには、次のコマンドを実行します。

$ LD_LIBRARY_PATH=. ./binary

注:システムのLD_LIBRARY_PATH変数は変更されません。変更は、これにのみ影響し、プログラムの実行にも影響します。

18
SwanS

まだ答えなしで苦労している人のために、私は自分自身を次の提案で見つけました:

次を使用してld.so.cacheを更新してみてください:Sudo ldconfig -v

私のために働いた。

4
Ian Frisbie

ビルドに CMake を使用している人は、CMAKE_EXE_LINKER_FLAGSを次のように変更します。

set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath='$Origin'")

これにより、すべてのビルドタイプ(デバッグ、リリースなど)のリンカーフラグが適切に伝播され、現在の作業ディレクトリで最初に.soファイルが検索されます。

4

ダイナミックリンカーは、ライブラリを探す場所を決定します。 Linuxの場合、ダイナミックリンカーは通常GNU ld.so(または互換性の理由で通常同じように動作する代替物)です。

ウィキペディアから引用するには:

GNU Cライブラリの動的リンカーは、次の場所で共有ライブラリを検索します。

  1. 存在する場合、バイナリのDT_RPATH動的セクション属性に(コロンで区切られた)パスがあり、DT_RUNPATH属性が存在しない。
  2. 実行可能ファイルがsetuid/setgidバイナリでない限り、環境変数LD_LIBRARY_PATH内の(コロンで区切られた)パス。この場合は無視されます。 LD_LIBRARY_PATHは、オプション--library-pathを使用して動的リンカーを呼び出すことでオーバーライドできます(例:/lib/ld-linux.so.2 --library-path $ HOME/mylibs myprogram)。
  3. 存在する場合、バイナリのDT_RUNPATH動的セクション属性の(コロンで区切られた)パス。
  4. ldconfigキャッシュファイル(多くの場合/etc/ld.so.cacheにあります)に基づくルックアップ。これには、以前に拡張ライブラリパスで見つかった候補ライブラリのコンパイル済みリストが含まれています。 (/etc/ld.so.confによって設定)。ただし、バイナリが-z nodefaultlibリンカーオプションでリンクされている場合、デフォルトのライブラリパスのライブラリはスキップされます。
  5. 信頼されたデフォルトパス/lib、次に/usr/lib。バイナリが-z nodefaultlibリンカーオプションでリンクされている場合、この手順はスキップされます。

出典: https://en.wikipedia.org/wiki/Rpath

0
Mecki