OS別 Shared Library の構築・使用ガイド

シェアードライブラリの作り方・使い方というのは、 OSによってバラバラだったりします。 共通性の高そうな SVR4系 (SunOS5,NEWSOS6,EWS-UX,IRIX) でも微妙に違う。 私なりに調べてみた事項をここにまとめてみました。

$Id: dynald.html,v 1.13 2005/04/28 06:21:48 kabe Exp $


バイナリに埋め込まれた情報の取得










バイナリに埋め込まれた情報の取得
OS RPATH 依存ライブラリ 備考
SunOS 4 (なし) ldd a.out  
SunOS 5 ldd -s a.out ldd a.out  
dump -vL a.out
EWS-UX/V ldd a.out  
dump -vL a.out
NEWS-OS 6 ldd a.out
dump -Dl a.out
lddは いもづるも表示する
dump -L a.out
IRIX 5 elfdump -Dl a.out  
elfdump -L a.out
_RLD_PATH=/usr/lib/rld.debug _RLD_ARGS=-v a.out ターゲットが実行されてしまう
HP-UX 9 chatr a.out
ldd -v a.out
ldd の方が正確な情報がとれる(ような気がする)
AIX 4 dump -H a.out  
Darwin (MacOS X) (RPATHなし) otool -L a.out  
GNU binutils objdump -p a.out  
RPATH
Runtime PATH の略。 実行時にシェアードライブラリを探すディレクトリを示す。 複数のディレクトリを探すなら':'で区切り、 指定がなければ/usr/libだけを参照するような OSが多い。 実行時に環境変数 LD_LIBRARY_PATH で指定されるものと同じ。

シェアードライブラリを早くからサポートした SunOS4 では、 構築時パス (-L で指定するもの) との区別がなかったが、 SVR4系では明確に区別される。 従って、リンクは成功した(a.outはできた)が、いざ実行してみると 「ライブラリが見つからん」といって実行できないような a.outを作ってしまうことがある。

	Solaris2% gcc -c -I/usr/local/X11R6/include a.c
	Solaris2% gcc a.o -L/usr/local/X11R6/lib -lX11 -lsocket -lnsl
	# コンパイル・リンクは成功
	Solaris2% ./a.out
	ld.so.1: ./a.out: fatal: libX11.so.6.0: can't open file: errno=2
	Killed
	Solaris2% 
	

これを解消するには、実行時に LD_LIBRARY_PATH を設定して 一時的にしのぐか、

	Solaris2 % env LD_LIBRARY_PATH=/usr/local/X11R6/lib ./a.out
	Solaris2 %
	
リンク時に明示的に RPATH を指定してやらないといけない。 こちらでは LD_LIBRARY_PATH は不要。 具体的な方法はOSによって微妙に違うので、下の 実行時検索パス(RPATH)の指定 を参照のこと。
	Solaris2% env LD_RUN_PATH=/usr/local/X11R6/lib gcc a.o -L/usr/local/X11R6/lib -lX11 -lsocket -lnsl
	Solaris2 % ./a.out
	Solaris2 % 
	

ldd
実行形式がどのシェアードライブラリに依存しているかを 表示するコマンド。基本的には SunOS にしかない。 他のOSにも用意されているのは SunOSユーザーの移行を考慮 しているだけのように思える。

SunOS および NEWS-OS6 の ldd は、動作的には

	SunOS% env LD_TRACE_LOADED_OBJECTS=1 a.out
	
と同じ。SunOS5なら、lib*.soのexecute bitを立てれば シェアードライブラリに対しても ldd を実行できる。

単に環境変数を定義しているだけなので、NEWS-OS6用の ldd を IRIX に持っていっても無駄。気が向いたら作りましょう。

dump
dump というと、/usr/etc/dump (BSD) と /usr/ccs/bin/dump (SysV) があるが、 ここでは後者。IRIXは SysV系であるが dump はバックアップ用の ものを指すので elfdump となっている。 GNU binutils では objdump 。

実行時検索パス(RPATH)の埋め込み

「いもづる」というのは、 「AがBに依存しているとき、構築時にAをリンクすればBも勝手にリンクされる (もしくは実行時に探される)」ような機能を指すつもりで書いています。 マニュアルに明示的に書かれていることが少ないので正式名がわからん。

SunOS5 ばかり使っていると忘れがちですが、-Rオプションは SunOS5 でしか使えません。












実行時検索パスの埋め込み
OS ldコマンドライン いもづる shlib自体のRPATH 備考
SunOS 4 ld -Lpath1 -Lpath2 有効 無視 -Lは、リンク時と実行時の両方に使われる。 出力に-Lが記録される。
SunOS 5 ld -Rpath1:path2
LD_RUN_PATH=path1:path2 ld ...
無視 無視 -Rを使用すると LD_RUN_PATHは無視される。 shlib中のRPATHも基本的に無視されるが、Undefined symbol の表示の際に 依存ライブラリの推測に使われる。
EWS-UX/V LD_RUN_PATH=path1:path2 ld ... 無視 不可  
NEWS-OS 6 ld -rpath path1:path2 有効 有効 ./so_locationsを自動更新。 -rpath ⊇ shlibのRPATH でないと bus error?
IRIX 5 ld -rpath path1:path2 有効 有効 ./so_locationsを自動更新。 出力のRPATH = shlibのRPATH ∩ -rpath
HP-UX 9 ld +bpath1:path2
ld -Lpath1 -Lpath2 +b:
不可 不可 +b:では SunOS4と同様、-Lが実行形式に記録される
AIX 4 ld -blibpath:path:/usr/lib:/lib
ld -Lpath1 -Lpath2
有効 無視 -LのみのときはSunOS4と同様、 -Lが実行形式に記録される。 検索パスは実行形式・ライブラリ毎に独立。
QNX 6.1
(GNU ld)
(処置なし) 無視 無視 RPATHの埋め込みはできるのだが、バグのため 実行時には全く使われない。 LD_LIBRARY_PATHで逃げる。
QNX 6.2
(GNU ld)
ld -rpath=path1:path2
LD_RUN_PATH=path1:path2 ld ...
有効 有効 shlibのRPATHは実行リンク時には使われる。 構築リンク時は明示的にいもづるに対する -Lか--rpath-link が必要
Darwin (MacOS X)   有効   検索パスは環境変数での設定のみ。 (dyld(1))
(GNU binutils) ld -rpath=path1:path2
LD_RUN_PATH=path1:path2 ld ...
有効 無視 実際は使われるOSによって細部は違うと思われる


shlibの構築方法

のが通常の手順になります。 下の表は libS.so の構築を例にしています。












shlibの構築方法 (コンパイル、リンク)
OS PICFLAGS -shared 備考
SunOS 4 cc -PIC ld -assert pure-text -o libS.so.1.0 *.o バージョン番号必須
SunOS 5 cc -KPIC ld -G -z text -o libS.so *.o  
EWS-UX/V cc [-Kconform_pic] ld -G -z text -o libS.so *.o  
NEWS-OS 6 cc -KPIC ld -G -o libS.so.1 *.o;
ln libS.so libS.so.1
リンク時には*.soが使われ、実行時は*.so.1 (shlibのDT_SONAME)が使われる。 -o libS.soとするとデフォルトのDT_SONAME = libS.so.1
IRIX 5 cc -KPIC ld -shared -rdata_shared -o libS.so *.o  
HP-UX 9 cc +z ld -b -o libS.sl *.o 拡張子は*.sl
AIX 4 cc [-bM:SRE] ld -btextro -bM:SRE -bE:libS.sym -o libS.a *.o -lc arもshlibもファイル名は*.a。 libS.symは dump -g arファイル を加工して 取り出す。 依存しているライブラリ (-lc) も明示が必要。
QNX 6.x qcc -shared qcc -shared -o libS.so *.o 標準では gcc/GNU ld が裏で起動されるが、 違うコンパイラでもqccでオプションの差を吸収する
Darwin (MacOS X) cc -dynamic -fPIC libtool [-v] -dynamic -o libS.dylib *.o -lc ld を直接叩くよりlibtoolがおすすめ。 拡張子は .dylib
(gcc) gcc -fPIC gcc -shared -o libS.so *.o バージョン番号の生成までは自動化されない

NEWS-OS 6 の頁にもちょこっと書きましたが、 実行時リンカ (ld(1)とかdso(5)とかdld.sl(5)) にバージョン管理機構が ある場合には、単に*.soを作るだけではだめで、 *.so.1.0を実体にして*.soをシンボリックリンクにしたり、 ld のオプションでバージョン番号 (SO_NAME) を明示的に渡してやったり しなきゃならんこともあります。 詳しくはマニュアルを見て下さい(いちいち書いとったらきりがない)。


参考文献

Why LD_LIBRARY_PATH is bad
構築パスと実行時パスの区別がなかった SunOS4時代の泥沼を 知らない人はとりあえず読んどくべし。
RPATH Considered Harmful (Debian)
ELF環境では一般に「ldconfig捨て捨て、RPATH使え」が正しいのですが、 そうではない事例もあるつーことで。 実例がかなり Debian 寄り。

かべ@sra-tohoku.co.jp

なお、当ページはHTML3 Table Modelを使用しているため、 NetscapeやMSIEでは正常に表示されない可能性があります。