limitusus’s diary

主に技術のことを書きます

libsqlite3.so を差し替える

ちょっと聞かれたので調べてみた。

目的

オリジナル libsqlite3.so.0 を実装したので、これを /module/libsqlite3.so.0 とし、 Python から使えるようにしたい。
Python

import sqlite3

とすると最終的に /usr/lib/python2.7/lib-dynload/_sqlite3.so が読まれるので、

ldd _sqlite3.so

としたときに libsqlite3.so.0 が /module/libsqlite3.so.0 を指すようにすればよい。

普通なら

動的ライブラリなんだから LD_LIBRARY_PATH を設定するのがまずは常識。

LD_LIBRARY_PATH=/module

しかし変わらない。

RPATH

実は _sqlite3.so には RPATH という情報が書かれていて、これが動的ライブラリの場所を示している。
manpage dlopen(3) を読んでもらうとわかるが、動的ライブラリはまずこの RPATH を検索し、ここにあればこれを使う。
LD_LIBRARY_PATH が読まれるのはその次の優先順位なのである。
したがって、この場合 LD_LIBRARY_PATH は機能しない。

RPATH を消す

以下の情報は多分に Frank's Geo-Geeking: RPATH, RUNPATH and LD_LIBRARY_PATH を参考にしている。
RPATH 情報は chrpath(8) により見ることができる。

chrpath /usr/lib/python2.7/lib-dynload/_sqlite3.so 
/usr/lib/python2.7/lib-dynload/_sqlite3.so: RPATH=/usr/lib/i386-linux-gnu

ここで気付いた。
_sqlite3.so の RPATH がないバージョンを作り、これを Python から読むようにすれば?」

cp /usr/lib/python2.7/lib-dynload/_sqlite3.so /module/_sqlite3.so
chrpath --delete /module/_sqlite3.so
export LD_LIBRARY_PATH=/module
ldd /module/_sqlite3.so

これで /module/_sqlite3.so が /module/libsqlite3.so.0 を読むようになってくれた。
もちろん Python から使うときには

export PYTHONPATH=/module

も忘れずに。

ちなみに

libpthread.so.0 ではこんな問題は起きない。というのも、libpthread.so.0 は RPATH で指定されたディレクトリではないところにあるからである。
この問題は SQLite3 モジュールが Python 組込みであることによっているのではないだろうか。