読者です 読者をやめる 読者になる 読者になる

同名だが(違う場所にあって)異なるダイナミックリンク(共有)ライブラリの問題(適切な解決法を求む)

FreeBSDにおいて、プログラムの起動時に次のようなエラーで起動に失敗することがあります。

/lib/libgcc_s.so.1: version GCC_4.6.0 required by /usr/local/lib/gcc48/libgfortran.so.3 not found

GCCgcc-4.8 を使っている場合)

原因は、libgcc_s.so.1 として /usr/local/lib/gcc48/libgfortran.so.3 が本来期待している /usr/local/lib/gcc48/libgcc_s.so.1 ではなく、/lib/libgcc_s.so.1 をロードしてしまっていることにあります。

実行ファイルが libgfortran のみに依存していれば、libgfortran.so.3 に埋め込まれている依存性によって正しいライブラリが読み込まれます。

(参考)

$ ldd /usr/local/lib/gcc48/libgfortran.so.3
/usr/local/lib/gcc48/libgfortran.so.3:
	libquadmath.so.0 => /usr/local/lib/gcc48/libquadmath.so.0 (0x801717000)
	libm.so.5 => /lib/libm.so.5 (0x801952000)
	libgcc_s.so.1 => /usr/local/lib/gcc48/libgcc_s.so.1 (0x801b7b000)
	libc.so.7 => /lib/libc.so.7 (0x800821000)

しかし、実行ファイル自身が libgcc_s に依存している場合、通常の libgcc_s は /lib/libgcc_s.so.1 ですから、そちらへの依存が優先されてしまい、前述のようなエラーになります。以下のようにして再現できました。

$ cat sample.c
#include <stdio.h>

extern void *__deregister_frame;
extern void *_gfortran_matmul_l4;

int
main(void)
{
  printf("%p\n", __deregister_frame);
  printf("%p\n", _gfortran_matmul_l4);

  return 0;
}

$ cc sample.c -L/usr/local/lib/gcc48 -lgfortran

$ ldd ./a.out
./a.out:
	libgfortran.so.3 => /usr/local/lib/gcc48/libgfortran.so.3 (0x80081f000)
	libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x800b36000)
	libc.so.7 => /lib/libc.so.7 (0x800d44000)
	libquadmath.so.0 => /usr/local/lib/gcc48/libquadmath.so.0 (0x8010f0000)
	libm.so.5 => /lib/libm.so.5 (0x80132b000)

$ ./a.out
/lib/libgcc_s.so.1: version GCC_4.6.0 required by /usr/local/lib/gcc48/libgfortran.so.3 not found

一応は「混ぜるな危険」ということであるわけですが(ワークアラウンドとしては LD_LIBRARY_PATH=/usr/local/lib/gcc48 を付ければ一応は動く)、

しかし、可能であれば、それぞれの場所にあるライブラリが別々にロードされるようにすべきかと思います。が、可能でしょうか?