となりのJohnの気まぐれ

気の向くままに

【SQLite】PythonでimportされるSQLiteのバージョンアップ

f:id:newbie29979:20201230195103p:plain

はじめに

SQLiteではバージョンによっては解析不可能な構文もある.今回のシステムの構築で扱ったUPSERT構文は,その汎用性の高さに関わらず,バージョン3.24.0以降でしか対応していない.
www.rect29.com
これはRaspberry piで開発を行うときなど,ビルトインでOSにSQLiteがインストール済みであった場合などで問題となりうる.インストール済みのそうしたソフトウェアは大概バージョンが古いのだ.このようなSQLiteのバージョンアップが必要な時には,開発者はSQLiteをソースからインストールする必要に迫られる.この記事はそうしたソースからバージョンアップする際の注意をまとめたものである.

pythonで有効になるSQLiteのバージョン

raspberry piではその名が示すように,開発で使われる言語はpythonである.raspberry piにOSのイメージを焼くと,既にpythonが入っている.しかしこのpythonはもちろん,SQLiteのバージョンは最新とは限らない
そこで,今回のUPSERT構文のようなバージョン依存の構文を使う際には,pythonが使用するSQLiteのバージョンを確認しなければならない.
pythonで使われるSQLiteのバージョンは以下のように確認できる.

>>> import sqlite3
>>> sqlite3.sqlite_version
'3.31.1'

3.31.1は記事執筆時のSQLiteの最新バージョンである.
UPSERT構文を使う場合,3.24.0以上でないとエラーを吐く.そこでpythonで使用されるSQLiteのバージョンを上げるためには,SQLiteを新しくビルドし,それを共有ライブラリとして扱うという方法をとる.

ソースからビルドしたSQLitepythonで扱う

SQLiteのビルド

ここを参考に進めた.
noknow.info

まずは適当なディレクトリで make installまで行う.

$ sudo wget https://www.sqlite.org/2020/sqlite-autoconf-3310100.tar.gz
$ sudo tar xvfz sqlite-autoconf-3310100.tar.gz
$ cd sqlite-autoconf-3310100.tar.gz
$ sudo ./configure
$ sudo make
$ sudo make install

./configureの実行時には--prefixオプションによってインストール先を指定することができる.

ここからが問題だ.
現在の状態はpythonが認識する古いSQLiteとたったいま導入した新しいSQLiteが共存している.そこで,新しいSQLiteが選ばれるようにする.

共有ライブラリ

sqlite3を/usr/local/sqlite3.31.1に配置したと仮定して記述する.
最初に,sqlite3のシンボリックリンクを作成する.

$ sudo ln -s /usr/local/sqlite3.31.1/bin/sqlite3 /usr/local/bin/

ライブラリとして使うには,次のライブラリのシンボリックリンクの作成も必要.

$ sudo ln -s /usr/local/sqlite3.31.1/include/sqlite3.h /usr/local/include/
$ sudo ln -s /usr/local/sqlite3.31.1/include/sqlite3ext.h /usr/local/include/

$ sudo ln -s /usr/local/sqlite3.31.1/lib/libsqlite3.a /usr/local/lib/
$ sudo ln -s /usr/local/sqlite3.31.1/lib/libsqlite3.la /usr/local/lib/
$ sudo ln -s /usr/local/sqlite3.31.1/lib/libsqlite3.so /usr/local/lib/
$ sudo ln -s /usr/local/sqlite3.31.1/lib/libsqlite3.so.0 /usr/local/lib/
$ sudo ln -s /usr/local/sqlite3.31.1/lib/libsqlite3.so.0.8.6 /usr/local/lib/

$ sudo ln -s /usr/local/sqlite3.31.1/lib/pkgconfig/sqlite3.pc /usr/local/lib/pkgconfig/

以上でやっとSQLiteをライブラリとして使用する準備が完了する.

次に,シンボリックリンクで配置したライブラリ(共有ライブラリ)へのパスを通す作業が必要になる.起動時にこれらライブラリを参照してほしいため,~/.bash_profileにパスを通す.

.bash_profile

...
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH
...

これでやっとpythonで使用されるSQLiteのバージョンが上がる…かと思いきやそうではない.罠である

実行者によって変わるSQLiteのバージョン

bash_profileはユーザがログインしたときに読まれるものである.ということは,systemdによって自動化する際など,root権限で実行されるときこの設定は読み込まれないのである.
Raspberry piは特徴上そうした自動化することは多い.従って,この対処が必要となる.
これに対処するためには,/etc/ld.so.confで以下のように記述する.

/usr/local/lib
include /etc/ld.so.conf.d/*.conf

本来であればシステム全体で共有ライブラリを通す場合,/etc/ld.so.conf.d内に/usr/local/libが記述されている設定ファイルを設置するのが望ましい.
例えば,/etc/ld.so.conf.d/local_lib.confというファイルを作成し,その中で

/usr/local/lib

と記述する.
ところが今回の場合だと古いSQLiteを共有ライブラリとして読み込む設定ファイルとの読み込み順の都合からか,うまくSQLiteのバージョンアップが確認できなかったため,強硬な手段として/etc/ld.so.confに記述した.

ld.so.confの更新が完了したら,キャッシュの更新を忘れずに行う.

$ sudo ldconfig

追加されたライブラリの確認は

$ sudo ldconfig -v

で可能.

まとめ

Raspberry piなどにOS次第では,使用されるライブラリのバージョンが古いことがある.特に,SQLiteではバージョン依存の構文がありバージョンアップが必要なこともある.ライブラリをソースからビルド,バージョンアップする際には,バイナリのシンボリックリンクだけでなく,そのライブラリのシンボリックリンクを通し,そのパスを通してやる必要がある.