玩式草子─ソフトウェアとたわむれる日々

第39回Plamo Linuxのビルドスクリプトとパッケージ管理ツールその2]

10月も下旬となるとめっきり日が短くなり、朝晩はずいぶん寒さを感じるようになってきました。残暑が長く続いた分、秋らしい季節の実感がないまま冬に突入している感じです。今年もあと2ヵ月、Plamo-5.0に向けた32ビット版と64ビット版の同期作業も最終段階に入ってきました。

さて、今回は前回に引き続いてパッケージ作りには欠かせないビルドスクリプトとその背景にあるビルドシステムについて取りあげてみます。

GNU Autotools

前回PlamoBuildスクリプトの例として紹介したXfce用のファイルマネジャーThunarは、configureを用いてビルド環境を構築するようになっており、configure ; make ; make install だけでビルド、インストールできます。

このconfigureスクリプトはGNUプロジェクトが開発したAutotoolsと呼ばれる開発システムの一部です。

GNUプロジェクトでは、開発したソフトウェアをさまざまなUNIX風OSの上で動作させるために、CPUやOSの種類、コンパイラ等のビルドツールの機能の違い等を吸収するAutotoolsというビルドシステムを開発しました。Autotoolsは、configureスクリプトを生成するautoconfconfigureで調べた結果を元に環境に応じたMakefileを生成するautomakeOSが共有(動的)ライブラリ機能を持っているかどうかに関わらずライブラリ操作を共通化するためのlibtoolsの3つのツールを使って、一つのソースコードをさまざまなUNIX風OS環境でビルドできるようにしています。

GNU Autotoolsは、設定ファイルの記述に独自のマクロ言語を使う必要があったりしてやや敷居は高いものの、最近のOSSプロジェクトの多くが採用しており、人気のあるソフトウェアでは、たいていconfigureを実行するだけでビルドが可能になっています。

Autotoolsを採用したソフトウェアは、ソフトウェアの種類によらず同じ手順でビルドできるので、名称やバージョン、入手先等を記述している10行ほどのヘッダ部を修正すれば、前回紹介した典型的なPlamoBuildスクリプトを流用することが可能です。

かってはImakeという独自のビルドシステムを利用していたX Window Systemも、Release7以降ではAutotoolsに移行して、それぞれの部品ごとにconfigureとmakeを繰替せばいいようになっているので、ヘッダ部分をそれぞれのソフトウェアに合わせたPlamoBuildスクリプトを生成しておけば、Xを構成する多数のソフトウェアを一気にパッケージ化することも可能です。このような仕組みのおかげで、前回紹介したようなペースでのパッケージ作りが可能になっていたわけです。

CMake

上述のようにGNU AutotoolsはOSS界の標準ビルドツールの地位を占めていますが、設計された当時とはUNIX風OSの世界も様変りしていて、最近の環境では不便な部分もあちこちにあります。そのような点を改善しようという新しいビルドシステムがいくつか提唱されており、それらの中で、最近、急速に勢力を伸ばしているのがCMakeと呼ばれるビルドシステムです。

CMakeはGNU Autotoolsを参考にしながら設計された新世代のビルドシステムで、OS Xも含めたUNIX風のOSのみならず、Windows環境にも対応するクロスプラットフォーム性を誇っています。

CMakeはGNU Autotools同様、自身が直接ビルドプロセスを管理するわけではなく、専用の設定ファイル(CMakeLists.txt)に従って、それぞれのプラットフォームに応じたビルド用設定ファイル(MakefileやEclipse等のIDE環境向けのプロジェクトファイル等)を生成してくれます。CMakeは比較的新しいビルドシステムなものの、C++用の高度なライブラリであるBoostMySQLKDE4といった高名なプロジェクトが採用しており、WindowsやMac環境もターゲットにするソフトウェアプロジェクトで積極的に採用されているようです。

CMakeはGNU Autotools同様、設定ファイルに従ってそれぞれの環境に応じたMakefileを生成するようになっていますが、変数やパス名の指定方法はconfigureスクリプトとは大きく異なります。たとえば、KDE-4.9.2に含まれているkdelibs-4.9.2の場合、ビルドスクリプトのヘッダ部は以下のような形になっています。

 1  #!/bin/sh
 2  ##############################################################
 3  url='ftp://ftp.kddlabs.co.jp/X/kde/stable/4.9.2/src/kdelibs-4.9.2.tar.xz'
 4  pkgbase=kdelibs
 5  vers=4.9.2
 6  arch=x86_64
 7  # arch=i586
 8  build=P1
 9  src=kdelibs-4.9.2
10  OPT_CONFIG=' -DDOCBOOKXML_CURRENTDTD_DIR:PATH=/usr/share/xml/docbook/schema/4.2/dtd '
11  DOCS='AUTHORS COPYING COPYING.DOC COPYING.LIB INSTALL README README-WIN32.TXT TODO knewstuff licenses'
12  patchfiles=''
13  compress=txz
14  ##############################################################

前回紹介したThunar-1.4.0のビルドスクリプトと比べると、10行目のOPT_CONFIGの指定がずいぶん異なっていることに気づくでしょう。この例のように、CMakeでは、-Dで指定したい項目を指示し、その項目が変数かパス名かなども指定する必要があります。

一方、このビルドスクリプトのconfigを引数にした際の処理は以下のようになっています。

128  if [ $opt_config -eq 1 ] ; then
129    for i in `seq 0 $((${#B[@]} - 1))` ; do
130      if [ -d ${B[$i]} ] ; then rm -rf ${B[$i]} ; fi ; mkdir -p ${B[$i]}
131    done
132  ######################################################################
133  # * ./configure を行う前に適用したい設定やパッチなどがある場合はここに
134  #   記述します。
135  ######################################################################
136    for i in `seq 0 $((${#S[@]} - 1))` ; do
137      cd $S
138      for patch in $patchfiles ; do
139         if [ ! -f ".$patch" ]; then
140             patch -p1 141             touch ".$patch"
142         fi
143      done
144  
145     cd $B
146        if [ -f $S/CMakeLists.txt ]; then
147            export PKG_CONFIG_PATH=/opt/kde/${libdir}/pkgconfig:/usr/${libdir}/pkgconfig:/usr/share/pkgconfig
148            export LDFLAGS='-Wl,--as-needed' 
149            export CC="gcc -isystem /usr/include $target" 
150            export CXX="g++ -isystem /usr/include $target"
151            cmake -DCMAKE_INSTALL_PREFIX:PATH=/opt/kde -DLIB_INSTALL_DIR:PATH=/opt/kde/${libdir} -DLIB_SUFFIX=$suffix ${OPT_CONFIG} $S
152        fi

CMakeの場合、ソースコードのあるディレクトリとビルド作業を行うディレクトリを分けることが推奨されているので、ソースコードを作業用ディレクトリにコピーする作業は省き(129-131行⁠⁠、パッチはソースコードのあるディレクトリ($S)で当てた上で(137-143行⁠⁠、作業用ディレクトリ($B)に移って、cmakeコマンドを実行します(151行⁠⁠。

cmakeコマンドには、configureの場合同様、ビルドしたコマンドやライブラリのインストール先(-DCMAKE_INSTALL_PREFIX:PATH=..)を設定した上で、ソースコードのあるディレクトリ($S)を引数に指定します。この指定で、$Sディレクトリ以下にあるCMake用の設定ファイル(CMakeLists.txt)を元に、環境に応じたMakefileが生成されます。

config時の処理は大きく異なるものの、cmakeコマンドはそれぞれの環境に応じたMakefileを生成するので、buildやinstall時の処理はGNU Autotoolsを採用しているソフトウェアと同様、makemake installで済みます。

このように、CMakeを採用しているソフトウェアでも、GNU Autotoolsを採用しているソフトウェア同様、ビルドスクリプトのひな形を用意しておけば、後はヘッダ部分のファイル名やバージョン番号の修正だけで対応でき、パッケージの大量ビルドが可能になるわけです。

その他のビルドシステムを持つソフトウェア

最近では多くのソフトウェアがGNU AutotoolsやCMakeといったビルドシステムを採用していますが、それらとは異なるシステムを採用しているソフトウェアもあります。

それらの代表例がPerlやPythonで開発されたソフトウェアです。PerlやPythonで書かれたソフトウェアの場合、CPUやOS環境の違いなどはPerlやPythonのレベルで吸収してくれるので、GNU Autotoolsのような細かな環境チェックを行う必要がなく、PerlやPythonのバージョン、必要なモジュールの有無程度のチェックで済みます。そのためPerlもPythonもそれぞれ独自のビルドシステムを用意しています。

Perlの場合、Makefile.PLというPerlスクリプトが用意され、このスクリプトから、そのソフトウェアをビルド、インストールするためのMakefileを生成するようになっています。生成されたMakefileは、他のビルドシステムの場合と同様の手順でビルドできますので、ビルドスクリプトではconfigureの代わりにperl Makefile.PLしておけば、build(make)とpackage(make install)の処理は標準のビルドスクリプトを利用できます。

たとえば、PerlにURI処理機能を追加するモジュールをビルドするためのスクリプト(PlamoBuild.URI-1.60)ではconfig時の処理を以下のようにしています。

197    for i in `seq 0 $((${#B[@]} - 1))` ; do
198      cd ${B[$i]}
199      for patch in $patchfiles ; do
200         patch -p1 201      done
202      perl Makefile.PL
203  
204    done

Pythonの場合はより徹底して、setup.pyというPythonスクリプトのみでビルドもインストールもできるようになっています。このスクリプトではconfigureに該当する処理は不要で、makeの代わりにpython ./setup.py buildを、make installの代わりにpython ./setup.py installを実行すればいいようになっています。

そのため、たとえばPythonにnotify機能を追加するモジュールをビルドするためのPlamoBuild.py-notify-0.3.1では、buildとpackageの処理は以下のようにしています。

211      cd ${B[$i]}
212      if [ -f setup.py ] ; then
213        python ./setup.py build
214      fi
...  
232      if [ -f setup.py ] ; then
233        python ./setup.py install --root $P
234      fi

一方、GNU Autotoolsが普及する以前に開発されたソフトウェアでは、設定ファイル等の調整がかなり面倒なことになります。Plamoの場合、KDEやXfceといった統合デスクトップ環境が普及する以前の「ウィンドウマネージャ」を支持する人が結構いるので、当時のソフトウェアもいくつか収録しています。それらのうち、当時広く使われていたAfterStepClassicのビルドスクリプトでは、config時の処理は以下のようになっています。

240   cp -p configure.h configure.h.orig
241   sed -i -e '/^#define/s@bin/X11@bin@g' configure.h
242   if [ "$arch" = "x86_64" ]; then
243       sed -i -e '/^#define/s@lib@lib64@g' configure.h
244   fi
245 
246   cp -p sample.steprc sample.steprc.orig
247   sed -i -e '/^ModulePath/s@:.*@@g' -e '/^PixmapPath/s@$@:/usr/share/afterstep/icons@g' -e '/^ModulePath/!s@lib/X11@share@g' sample.steprc
248   if [ "$arch" = "x86_64" ]; then
249        sed -i -e '/^ModulePath/s@lib@lib64@g' sample.steprc
250   fi
... 
272   cd ${B[0]}
273   xmkmf -a
274   for i in afterstep modules/{Audio,Auto,Wharf,Banner,Pager,asclock,Animate} ; do
275     cp -p $i/Makefile $i/Makefile.orig
276     sed '/MANPATH =/s@man@share/man@g' $i/Makefile.orig > $i/Makefile
277   done

AfterStepClassicでは、当時のX Window Systemが採用していたImakeビルドシステムを利用しており、273行目に実行しているxmkmfコマンドが、あらかじめ用意されたImakefileから環境に応じたMakefileを生成します。しかしながら、Imakeでは対応できないconfigure.hやsample.steprcは個別にsedで修正したり、xmkmfで生成したMakefileもMANPATHの部分が現在の標準とはずれているので別途修正したりしています。

このビルドスクリプトには、同様の修正作業があちこちにあり、このあたりの処理を自動的にやってくれる最近のビルドシステムに慣れた身には、それらを確認するだけでも大変です。

開発元のX自体がGNU Autotoolsに移行してImakeシステムを放棄してしまったので、この世代のソフトウェアはそろそろ退役させる時期かな、という気もしていますが、根強いニーズもあるし、ビルドが今のように簡単ではなかった時の記憶のためだけでも残しておく価値があるように思っています。

ビルドスクリプト自動生成ツール

以上紹介してきたように、最近のソフトウェアの多くはGNU AutotoolsやCMakeといった汎用的なビルドシステムを採用しており、それらのソフトウェアはほぼ定型的な処理でビルド、インストールできるようになっているので、ビルドスクリプトも定型化できます。

そのような定型化したビルドスクリプトを作るためのメタ・ビルドスクリプトmake_PlamoBuild.pyこの連載でも以前紹介したことがありますが、最近のバージョンはメンテナの加藤さんがgithubで公開してくれています。

最近のmake_PlamoBuild.pyは、GNU AutoconfとKDE用のCMakeの双方に対応しており、デフォルトではconfigureを使うGNU Autoconf用、-t KDEオプションを指定すると、インストール先を/opt/kde/に指定したCMake用のビルドスクリプトを生成します。また、引数としてソースコードの入手先のURLを指定すれば、ヘッダのURL部に自動的に埋めこむような機能も加えています。

このメタビルドスクリプトを使えば、典型的なパッケージ作成作業は以下のような流れになります。例としてxz圧縮ユーティリティの最新版5.0.4をビルドしてみます。

Google等でソースコードの入手先を確認し、wget等を使ってダウンロード
$ wget http://tukaani.org/xz/xz-5.0.4.tar.bz2
--2012-10-30 13:59:17--  http://tukaani.org/xz/xz-5.0.4.tar.bz2
tukaani.org (tukaani.org) をDNSに問いあわせています... 84.34.147.45
..
2012-10-30 13:59:22 (253 KB/s) - `xz-5.0.4.tar.bz2' へ保存完了 [1048328/1048328]
メタビルドスクリプトでGNU Autoconf(configure)用ビルドスクリプトを生成
$ /mnt/Srcs/make_PlamoBuild.py -u http://tukaani.org/xz/xz-5.0.4.tar.bz2 xz-5.0.4.tar.bz2 
dirname =  xz-5.0.4
making PlamoBuild.xz-5.0.4 ...
ビルドスクリプトを実行し、一般ユーザ権限でパッケージを試作
$ ./PlamoBuild.xz-5.0.4 

XZ Utils 5.0.4

System type:
checking build system type... x86_64-unknown-linux-gnu
checking host system type... x86_64-unknown-linux-gnu
...
config.status: creating po/Makefile
make  all-recursive
make[1]: ディレクトリ `/mnt2/Srcs/X/Xz/build' に入ります
Making all in src
...
make[1]: ディレクトリ `/mnt2/Srcs/X/Xz/build' から出ます
Do you want to package as root? [y/N] 
Making install in src
...
./usr/share/man/man1/lzfgrep.1.gz
./usr/share/man/man1/lzmore.1.gz
./usr/share/man/man1/lzless.1.gz
試作したパッケージの確認
$ tar tvf xz-5.0.4-x86_64-P1.txz
drwxr-xr-x kojima/users      0 2012-10-30 14:00:17 usr/
drwxr-xr-x kojima/users      0 2012-10-30 14:00:16 usr/include/
drwxr-xr-x kojima/users      0 2012-10-30 14:00:16 usr/include/lzma/
...
問題ないようなのでroot権限でパッケージ作成
$ ./PlamoBuild.xz-5.0.4 package
Do you want to package as root? [y/N] y
パスワード:
Making install in src
...
./usr/share/man/man1/lzmore.1.gz
./usr/share/man/man1/lzless.1.gz

$ ls -l xz-5.0.4-x86_64-P1.txz
-rw-r--r-- 1 kojima users 529,520 10月 30日  14:01 xz-5.0.4-x86_64-P1.txz
パッケージを更新
$ sudo updatepkg xz-5.0.4-x86_64-P1.txz
パスワード:
removing xz-5.0.3

Removing package xz...
Removing files:
  --> Deleting symlink bin/lzma
  --> Deleting symlink bin/unlzma
...
xz-5.0.4-x86_64-P1 のインストール中 
PACKAGE DESCRIPTION:
xz-5.0.4-x86_64-P1 のインストールスクリプトを実行中
インストールしたコマンドのバージョン確認
$ xz --version
xz (XZ Utils) 5.0.4
liblzma 5.0.4

これは余分な作業を省いた極端な例で、実際にパッケージを作成する場合には、ソースコードに付属のREADMEファイルを眺めたり、過去のビルドスクリプトを調べたり、configure --helpで表示される指定可能なオプション類を調べたりします。しかし処理の基本的な流れはここに示した通りで、特に調整が不要なソフトウェアならば、それほど時間をかけずにパッケージ化することが可能です。

おすすめ記事

記事・ニュース一覧