LinuxでPythonをビルドするときの --enable-shared オプションについて

  • 87
    いいね
  • 0
    コメント

Linux で Python をビルドするとき、 --enable-shared という configure オプションがありるので、その解説とTipsを紹介します。
具体例として Python を挙げていますが、話の内容のほとんどは他の言語やライブラリでも共通だと思います。

--enable-shared とはなにか

このオプションを指定しない場合、主要なバイナリファイルとして python という実行ファイルと libpython2.7.a (Python 2.7の場合) というライブラリファイルができます。
--enable-shared をつけた場合、 libpython2.7.so というダイナミックリンク用の shared object も生成され、 python はこの shared object をダイナミックリンクするようになります。

Debian などの Linux ディストリビューションでは、たいていこのオプションがついた状態で Python がビルドされています。たくさんのプログラムが Python を利用できるようにビルドされていて、 libpython2.7.a を直接リンクしてしまうと Python のバージョンアップをするときにそれらを全部アップデートしないといけなくなるからです。

個人で Python をビルドする場合、あまりこの利点は生きてこず、むしろ複数のバージョンを並列して使いたい人にとってはじゃまになることがあるので、 --enable-shared はお勧めしません。何らかの理由があって shared object を使いたい人以外は続きは読まなくて大丈夫です。

--enable-shared を使った時の問題点

python 実行ファイルや、 mod_wsgi のように Python をライブラリとしてリンクするプログラムが libpython2.7.so に依存するようになると、実行しているプログラムが思い通りの libpython2.7.so を使ってくれないという状態になる可能性があります。

例えば、 --prefix=/usr/local/Python-2.7.3 でビルドしてインストールした場合、 /usr/local/Python-2.7.3/bin/python を実行すると、設定や環境変数によっては /usr/lib/libpython2.7.so/usr/local/Python-2.7.2/lib/libpython2.7.so が使われてしまう可能性があります。

環境変数 LD_LIBRARY_PATH を使うと優先して読み込むライブラリの場所を指定することができますが、複数のバージョンの Python を並列して使っている場合は環境変数の切り替えを自分でやるのも面倒ですし、同じサーバーを他の人も使っている場合はその人が混乱する場合もあります。

対策1 rpath を設定する

多分これが正攻法です。
python 実行ファイルなど、ダイナミックリンクをする側に、リンクする libpython2.7.so の場所をフルパスで記録させてしまいます。

rpathを設定するには、 configure するときに LDFLAGS を指定するのが楽です。

$ ./configure --prefix=$HOME/python27 --enable-shared \
    LDFLAGS=-Wl,-rpath,$HOME/python27/lib

一点だけ、 rpath を使う欠点として、 cp -r などで Python をまるごと別のディレクトリにコピーして bin/ の中のスクリプトの shebang を書き換えるだけで動くというポータビリティーが犠牲になります。
virtualenv では libpython2.7.so が元の場所にあれば動き続けるので問題ないのですが、 virtualenv を使うといつまで古いバージョンの Python が使われてるかわからなくてなかなか消せなくなるのが嫌だからまるごとコピーして使う、という人にはお勧めできません。

対策2 libpython を静的リンクしてしまう

shared object は何らかの目的で必要なんだけど、 python 実行ファイルがそれをダイナミックリンクする必要はない、という人は、 python をビルドするときに libpython2.7.a の方をリンクしてしまう方法があります。それには、 configure 後に Makefile を開いて、

BLDLIBRARY=     -L. -lpython$(VERSION)

となっているところを

BLDLIBRARY=     libpython$(VERSION).a

に書き換えてやります。

Debian パッケージの python もこれと似たやり方でビルドされているらしく、 libpython2.7.so があるのに python は libpython を静的リンクしています。
shared object は PIC になっていてパフォーマンスが低かったのが理由らしいです。 (vim で Python 2 と 3 を同時に使えないのもこれが原因)