前回の記事 でソースから GCC をインストールして、それを使って LLVM やら SML# やらをビルドしたのだけど、 その時のライブラリパスの設定について少し考え込んでしまったのでメモ。
ソースからインストールしたGCCはそのままでは使えない
ソースからインストールした GCC でコンパイルしたバイナリをいいかげんに起動すると、
smlsharp: /usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.18' not found (required by smlsharp)
smlsharp: /usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.17' not found (required by smlsharp)
smlsharp: /usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.14' not found (required by smlsharp)
smlsharp: /usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.15' not found (required by smlsharp)
smlsharp: /usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.20' not found (required by smlsharp)
などというエラーが出る。 GCC の FAQ 曰く、これはそういうものらしい。 (どこかで見かけたが 3.4.20 とかのバージョン番号は gcc と連動して設定されているようだ。)
rpath のことは知っていたけど、 他の状況でこの手のエラーが出たら適当に (DY)LD_LIBRARY_PATH を設定するとか ldconfig してお茶を濁していたので、勉強になった。
一方で、 GCC のようにOSのファイルと衝突するツールをインストールする時には悩ましい問題がある。 (RHEL の Python2 とか)
GCC の場合、 OSが持つデフォルトの libgcc や libstdc++ (消せない) と衝突するので、 それらでコンパイルしたファイルを実行する時は rpath や LD_LIBRARY_PATH でサーチパスの優先度を上書きすることになる。 .bashrc とかで /usr/local/lib にパスを通すのは普通のことだし、 libgcc 等に限ってはバイナリ互換性もあるようだが (実際、 Ubuntu で 古い gcc を入れると、libgcc 等は /usr/lib へのシンボリックリンクになり、特に rpath 等は設定されない)、さすがに /usr/local/lib を /usr/lib より優先するのは安全ではないのではないか (いや、よくやる気もするけど…どうしてたっけ)。
どうすればよかったか
結局、単に GCC のみインストールパスを特殊化して、状況に応じて優先度を上げる、つまり gcc は /usr/local 直下とかにはインストールせず /usr/local/gcc-x.y.z 等に置き、適宜 LD_LIBRARY_PATH や rpath を設定するのが良さそうという結論に至った。
次のようにすればよかったと思われる (結局 Vine Linux の利用を辞めることに成功したので一部しか試していない)。
- 新しい GCC をビルドする時は、 ./configure --prefix=/usr/local/gcc-4.9.4 等として、デフォルトの野良インストール先とは区別する
- 新しい GCC を使う時だけ、次のようにして rpath (または LD_LIBRARY_PATH) を GCC のインストールパスにのみ優先的に設定する
例:
# rpath を GCC のライブラリ置き場に設定
export LDFLAGS='-Wl,-rpath=/usr/local/gcc-4.9.4/lib64 -L/usr/local/lib/gcc-4.9.4/lib64'
# LLVM ビルドが参照する gcc, g++ のパスを設定
cmake -DCMAKE_C_COMPILER=/usr/local/gcc-4.9.4/bin/gcc -DCMAKE_CXX_COMPILER=/usr/local/gcc-4.9.4/bin/g++ -G”Unix Makefiles” $PWD/../llvm-3.7.1.src
# SML# ビルドが参照する gcc, g++ のパスを設定
CC=/usr/local/gcc-4.9.4/bin/gcc CXX=/usr/local/gcc-4.9.4/bin/g++ ./configure --with-llvm=/usr/local
GCC の LINK_SPEC の設定など無駄に深追いしてしまったけど、考えてみれば簡単なことだった。 しかし特に、前回の記事 の最後のようにユーザーが与えた環境変数を書き換えてしまうと、 SML# のようなコンパイラの場合、問題の特定が難しくなるため、今回のような原則でやっていくほうが良いように思った。
#余談
GCC と共にインストールされる他のライブラリに
- libasan (Address Sanitizer)
- libcilkrts (Intel(R) Cilk(TM) Plus runtime library)
- libgomp (GNU Offloading and Multi Processing Runtime Library)
- libitm (Intel の Transactional Memory)
- liblsan (Leak Sanitizer)
- libquadmath (Quad-Precision Math)
- libssp (Stack Smashing Protector)
- libtsan (Thread Sanitizer)
- libubsan (Undefined Behavior Sanitizer)
- libvtv (virtual table verification)
等がある。 一つずつ調べてみると、 色んな技術やら企業 (Intel, Google) が関係しているのが垣間見れて面白かった。 特にソフトウェアの安全性を動的に確保するライブラリが多いようだ。
(以上)