Python でパッケージのインストール時に rpath を設定する方法

libmysqlclient を static リンクする方法 を紹介したばかりですが、 MySQL 5.6 だとこの方法でビルドしても Import エラーになるという報告がありました。

static link は動的ライブラリの検索パスを考えなくて良くなる代わりに、動的ライブラリなら芋づる式に ロードしてくれるライブラリが欠けてしまってエラーに成った時に解決が面倒です。

ld.so.conf とかを弄らなくても動的ライブラリをリンクするまっとうな方法は、リンクオプションで rpath を指定して、 動的ライブラリの検索パスを追加することです。 (環境変数の LD_LIBRARY_PATH などを使う方法は、 cron を使うとか、Webアプリを動かすときとかにハマります)

python では build_ext の -R (--rpath) オプションで、リンクオプションの rpath を指定できます。

このオプションは設定ファイルで指定することができ、通常パッケージのディレクトリに setup.cfg という ファイルを書くことが多いですが、こういった環境とごとの問題はパッケージの外に書いたほうが楽です。 ドキュメント にある通り、 $HOME/.pydistutils.cfg か、 Python をインストールした場所の lib/pythonver/distutils/distutils.cfg に書いてしまいましょう。

設定ファイルは ini 形式で、 コマンド名がセクション名になります。 例えば次みたいになります。

[build_ext]
rpath = /usr/local/mysql-5.6.33/lib

これで、 pip install MySQL-python するだけで、 /etc/ld.so.conf に設定されていない場所にある libmysqlclient.so を使うことができます。

追記

ただし、設定ファイルを使ってしまうと、 MySQL と関係ないライブラリをビルドするときにも rpath が設定されてしまいます。 そのライブラリを import するときに、 rpath で指定された場所も探すので、ほんの少しロードが遅くなるし、 たまたま同じ名前の共有ライブラリがあると事故る可能性もあります。

設定ファイルではなくて環境変数で rpath を指定することで、その時の pip install にだけ影響をあたえることができます。

$ PATH=/usr/local/mysql-5.6.33/bin:$PATH LDFLAGS=-Wl,-rpath,/usr/local/mysql-5.6.33/lib \
    pip install https://github.com/farcepest/MySQLdb1/archive/master.zip
このブログに乗せているコードは引用を除き CC0 1.0 で提供します。