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
を見つけることができないのはなぜですか?
ローダーは、_$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!
実行可能ファイルと同じディレクトリから共有オブジェクトをロードするには、次のコマンドを実行します。
$ LD_LIBRARY_PATH=. ./binary
注:システムのLD_LIBRARY_PATH変数は変更されません。変更は、これにのみ影響し、プログラムの実行にも影響します。
まだ答えなしで苦労している人のために、私は自分自身を次の提案で見つけました:
次を使用してld.so.cacheを更新してみてください:Sudo ldconfig -v
私のために働いた。
ビルドに CMake を使用している人は、CMAKE_EXE_LINKER_FLAGS
を次のように変更します。
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath='$Origin'")
これにより、すべてのビルドタイプ(デバッグ、リリースなど)のリンカーフラグが適切に伝播され、現在の作業ディレクトリで最初に.soファイルが検索されます。
ダイナミックリンカーは、ライブラリを探す場所を決定します。 Linuxの場合、ダイナミックリンカーは通常GNU ld.so
(または互換性の理由で通常同じように動作する代替物)です。
ウィキペディアから引用するには:
GNU Cライブラリの動的リンカーは、次の場所で共有ライブラリを検索します。
- 存在する場合、バイナリの
DT_RPATH
動的セクション属性に(コロンで区切られた)パスがあり、DT_RUNPATH
属性が存在しない。- 実行可能ファイルが
setuid
/setgid
バイナリでない限り、環境変数LD_LIBRARY_PATH
内の(コロンで区切られた)パス。この場合は無視されます。LD_LIBRARY_PATH
は、オプション--library-pathを使用して動的リンカーを呼び出すことでオーバーライドできます(例:/lib/ld-linux.so.2 --library-path $ HOME/mylibs myprogram)。- 存在する場合、バイナリの
DT_RUNPATH
動的セクション属性の(コロンで区切られた)パス。- ldconfigキャッシュファイル(多くの場合
/etc/ld.so.cache
にあります)に基づくルックアップ。これには、以前に拡張ライブラリパスで見つかった候補ライブラリのコンパイル済みリストが含まれています。 (/etc/ld.so.conf
によって設定)。ただし、バイナリが-z nodefaultlib
リンカーオプションでリンクされている場合、デフォルトのライブラリパスのライブラリはスキップされます。- 信頼されたデフォルトパス
/lib
、次に/usr/lib
。バイナリが-z nodefaultlibリンカーオプションでリンクされている場合、この手順はスキップされます。