コマンド実行時にリンカーエラー

これはbmdtoolsをビルドした時の話。 /usr/local/lib がディストリビューションのよってはライブラリ検索パスに追加されていないため

$ ./bmdcapture 
./bmdcapture: error while loading shared libraries: libx265.so.130: cannot open shared object file: No such file or directory

と言われてしまい実行できない。 これを解決するまでの話。

参考:

ライブラリ検索パスに /usr/local/lib を追加する

これは

原因はライブラリのパスが正しく設定されていないためです. ライブラリパスが通っているかどうかは ldd コマンドで確認できます.not found となっているものは正しく設定されていないです.

$ ldd ./a.out
...
libcudart.so.7.0 => not found
...

対応としては,環境変数設定としてライブラリパスを通してください.

lddをしてみると、


$ ldd bmd*
bmdcapture:
	linux-vdso.so.1 =>  (0x00007fffd939d000)
	libx265.so.130 => not found
	libx264.so.152 => /usr/local/lib/libx264.so.152 (0x00007f400e339000)
	libfdk-aac.so.1 => not found
	libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f400e02f000)
	libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f400de2b000)
	libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f400dc0d000)
	libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f400d88b000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f400d4c1000)
	/lib64/ld-linux-x86-64.so.2 (0x000055a7303e3000)
	libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f400d2aa000)
bmdgenlock:
	linux-vdso.so.1 =>  (0x00007ffe121f0000)
	libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f3329975000)
	libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f3329758000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f332938d000)
	/lib64/ld-linux-x86-64.so.2 (0x0000563c40872000)
bmdplay:
	linux-vdso.so.1 =>  (0x00007ffdde3e0000)
	libx265.so.130 => not found
	libx264.so.152 => /usr/local/lib/libx264.so.152 (0x00007fd3f3eb9000)
	libfdk-aac.so.1 => not found
	libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fd3f3baf000)
	libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fd3f39ab000)
	libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fd3f378d000)
	libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fd3f340b000)
	libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fd3f31f5000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd3f2e2a000)
	/lib64/ld-linux-x86-64.so.2 (0x000055fa7c802000)

libx265.so.130 及び libfdk-aac.so.1 のリンク切れが起きていることが確認できる。

ライブラリ検索パスを設定する方法はいくつかある。 /usr/local/lib をパスに追加するオススメ順に紹介する。

/etc/ld.so.conf に設定ファイルを追加する

/etc/ld.so.conf に追加

echo "/usr/local/lib" > /etc/ld.so.conf.d/usr-local-lib.conf

再起動するか # ldconfig -v を実行する

昨日のXalanで /usr/local/lib/libxalan-c.so.110 を参照してもらえなかったマシンがあったので。

#マシンごとに設定が違うのやられるなぁ

これは全ユーザ/グループが影響を受ける設定方法になる。 なので予期せぬバグが発生することがあるが、 /usr/local/lib であれば一般的に利用されるインストール先なので問題ないと判断した。

/usr/local/lib に独自開発したライブラリをインストールする場合などは気をつけねばならない。

 $ sudo vi /etc/ld.so.conf.d/usr-local-lib.conf

以下を書き込んで保存

/usr/local/lib

設定を反映。更新されているか確認する。

$ sudo ldconfig -v 
/usr/local/lib:
	libopus.so.0 -> libopus.so.0.6.1
	libx265.so.130 -> libx265.so.130
	libx264.so.152 -> libx264.so.152
	libfdk-aac.so.1 -> libfdk-aac.so.1.0.0

LD_LIBRARY_PATH にパスを追加する

環境変数 LD_LIBRARY_PATH を設定する

.bash_profile に以下を記述

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib

これも一般的な方法。しかし

  1. envした時にそもそもLD_LIBRARY_PATHが存在していなかった
  2. .bash_profile の内容が肥大化していく
  3. 動的リンク用の変数なのでビルド時指定だけでは意味がない
  4. /usr/local/lib であれば全体に適用して大丈夫だろうと判断した

といった理由で採用しなかった。

コンパイル時にLDFLAGS="-L/usr/local/lib -Wl,-rpath /usr/local/lib"を指定する

What you want is: LDFLAGS="-L$DIR/lib/ -R$DIR/lib/"

“libevent not found”

I trusted you to read the man page, but you didn’t. The -R flag means RUNPATH to linker on Solaris, but it means something else to Linux linker.

What you want then is:

LDFLAGS="-L$DIR/lib/ -Wl,--rpath=$DIR/lib/"

それぞれのバイナリをテキストエディタ眺めてみると、ライブラリを見つけてもらえない場合は、 /usr/local/imlib2/lib という文字が含まれてないことがわかりました。

そこで objdump -p binary で調べてみると、見つけてもらえる場合は、以下のようなのが含まれていました。

Dynamic Section:
  RPATH                /usr/local/imlib2/lib

リンク時に gcc-Wl,-rpath /path/to/lib を渡すことで、RPATH を渡せることがわかり無事解決しました。

-Wl,-rpath /usr/local/imlib2/lib

無事リンクできて、めでたしめでたし。

参考リンク:

とあるエンジニアの備忘log: Shared Object 入門
http://masahir0y.blogspot.jp/2013/01/shared-object.html
知っていると便利な gcc のオプション
http://www.unixuser.org/~euske/doc/gccopts/

-Wl,-rpathをコンパイル時に指定してあげれば、動的リンクするライブラリの場所が 生成されるバイナリに書き込まれるので環境変数などでパスが通ってなくても問題ない。

なぜLDFLAGSかというと

./configure --helpを見てください。

LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory

LIBS linker flags, e.g. -l.{a,so} if you have nonstandard libraries to link

とあります。

これらの変数は最終的に Makefile

$(CC) $(LD_FLAGS) -o taget $(LIBS)

のように使われます。 ですからgccに与えるオプションをそのままわたせばいいと思います。

一般的な使い方としては, ライブラリのある位置をLD_FLAGSで指定して, 特別にライブラリを追加してリンクする時はLIBSを指定すればいいのではないでしょうか? (ただ、LIBSを指定するのがどんな時なのかちょっと想像できませんね)

以下のようにすれば/home/hoge/lib以下のライブラリも検索するようになります。

LD_FLAGS="-L/home/hoge/lib" ./configure

ただ、この方法ではソフトウェアをビルドする度に忘れず引数の指定をしなければならなくなる。