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

第86回Plamo Linuxのビルドスクリプト再び

ここしばらく「Linuxカーネルの歴史を振り返る」という、読むのも書くのも大変な話題が続いたので、今回は少し気分を変えて、最近取り組んでいるPlamo Linuxのビルドスクリプトの改修について取りあげることにします。

Plamo Linuxのビルドスクリプトやパッケージ管理ツールについては、以前、この連載でもとりあげたことがあるものの、記事の日付を見ると4年前でした。

PlamoBuildスクリプトを使ってパッケージを作成し、installpkgかupdatepkgを使ってインストール、removepkgを使ってアンインストール、という枠組みは変っていないものの、この4年ほどの間にPlamoBuildスクリプトやPlamoBuildスクリプトを生成するメタ・ビルドスクリプトもだいぶ進化してきたので、今回はそのあたりの最新状況を紹介します。

ビルドスクリプトの改修

最初期のPlamoBuildスクリプトは、configure && make install を中心に、それぞれのソフトウェアをパッケージ化するための処理を手書きしたスクリプトでした。

そのうち、いちいち0から手書きするのも面倒なので、典型的な手順を整理してテンプレートを作り、パッケージ作成の際はそのテンプレートをコピーして使うようになりました。

さらには、ソースコードを指定するとパッケージ名やバージョン番号を設定したビルドスクリプトを生成するメタ・ビルドスクリプトを使うようになったのは過去の記事で紹介した通りです。

もともとPlamoBuildスクリプトを使い始めた当時は、GNU Autotoolsが生成するconfigureスクリプトを使うソフトウェアが主流だったので、ビルドスクリプトのテンプレートもconfigureを使うことを前提にしていました。

しかし過去の記事でも指摘したように、GNU AutotoolsはUNIXの仕様が分裂していた時代に開発されたこともあり、ずいぶん煩雑な設定を必要とします。そのため、新しく開発されたソフトウェアではGNU Autotoolsではなく、cmakeを使ってMakefileを生成する例が多くなってきました。加えて、最近ではPythonやPerlで書かれたアプリケーションも広まってきて、Python用のsetup.pyやPerl用のMakefile.PLを用いてビルドする例も目に付きます。

テンプレート化したビルドスクリプトを使い回す方法は簡単なものの、1つのテンプレートでこれら全てに対応しようとすると、それぞれの方法に応じた手順を用意して、configureやCMakeList.txt等の有無で動作を変えるような処理が必要になります。加えて、同梱するドキュメント類を圧縮する機能やファイルの所有者をチェックする機能など、便利な機能をあれこれテンプレートに組み込んでいった結果、シンプルさが売りものだったはずのPlamoBuildスクリプトがずいぶん複雑になってしまいました。

もともとPlamo Linuxは「作者(メンテナ)と利用者(ユーザ)の垣根を低くする」ことをひとつの目的としていました。パッケージがどのような設定や手順で作られているかを紹介するビルドスクリプトはユーザとメンテナをつなぐ重要なツールなので、複雑化して読みづらくなるのは問題です。

そこでPlamo Linuxの原点に回帰するためにも、ビルドスクリプトをよりシンプルな形に再構成することにしました。

ビルドスクリプトの再構成

PlamoBuildスクリプトはシェルスクリプトなので、シンプル化といってもそれほど凝ったことができるわけではありません。せいぜい汎用的な処理をサブルーチン化して別ファイルに括り出し、ビルドスクリプトの先頭付近でそのファイルを読み込む程度です。

今回は、この別ファイルを/usr/share/plamobuild_functions.shという名前にして、テンプレートのうちすでにサブルーチン化できている部分と、作成したバイナリを作業用ディレクトリに仮インストールしてパッケージ用に調整する部分の処理を括り出すことにしました。

 1   prune_symlink() {
 2     echo "pruning symlink in $1"
 3     if [ -d $1 ] ; then (
 4       cd $P
 5       rm -f /tmp/iNsT-a.$$ ; touch /tmp/iNsT-a.$$
 6       for i in `find ${1#$P/} -type l` ; do
 7         target=`readlink $i`
...
45   strip_all() {
46     for chk in `find . ` ; do
47       chk_elf=`file $chk | grep ELF`
48       if [ "$chk_elf.x" != ".x" ]; then
49         chk_lib=`echo $chk | grep lib`
50         if [ "$chk_lib.x" != ".x" ]; then
51            echo "stripping $chk with -g "
...

コードの断片だけで恐縮ですが、例に示したprune_symlink()は指定したディレクトリ以下のシンボリックリンクを刈り取る処理、strip_all()は生成したバイナリファイルからデバッグ用のシンボルを取りのぞく処理です。

このような形で、prune_symlink()やstrip_all()の他、指定したディレクトリにある全てのファイルを圧縮するgzip_dir()指定したURLからソースコードをダウンロードするdownload_sources()等のコードをplamobuild_functions.shに切り出した結果、テンプレートを250行ほど削減することができました。

plamobuild_functions.shはメンテナの加藤さんがGitHubで管理してくれているので、GitHubのページで全体をご覧いただけます。

メタ・ビルドスクリプトの仕様変更

前節で紹介したplamobuild_functions.shに汎用的な処理を切り出すことでビルドスクリプトのテンプレートはずいぶん見通しがよくなりました。そこにconfigureやcmakeそれぞれの処理を盛り込むのも見苦しいので、ビルドスクリプトを作るスクリプト(メタ・ビルドスクリプト)がそのソフトウェアに応じた設定方法を判断し、ビルドスクリプトにはconfigureならconfigure用、cmakeならcmake用の処理のみを組み込むようにしました。

そのためにはメタ・ビルドスクリプト(make_PlamoBuild.py)がソースコード中にconfigureがあるか、あるいはCMakeList.txtがあるか、等を調べなければなりません。そこで以前のバージョンとは仕様が変わるものの、make_PlamoBuild.pyの必須引数にはソースコードのアーカイブファイルではなく、ソースコードを展開したディレクトリを指定するようにしました。

make_PlamoBuild.pyはソースコードを展開したディレクトリを引数に与えると,ディレクトリ名から作成するパッケージの名前とバージョンを取り出すと共に、configureやcmakeそれぞれに合わせたビルドスクリプトを生成します。また、手動で設定方法を指定するための-mオプションも用意しました。

$ make_PlamoBuild.py -h
usage: make_PlamoBuild.py [-h] [-p PREFIX] [-u URL] [-v] [-m METHOD] [-s] srcdir

PlamoBuild script maker

positional arguments:
  srcdir                source code directory

optional arguments:
  -h, --help            show this help message and exit
  -p PREFIX, --prefix PREFIX
                        install directory prefix(default=/usr)
  -u URL, --url URL     source code download url
  -v, --verbose         Verbose mode
  -m METHOD, --method METHOD
                        force config method(config, cmake, perl, python)
  -s, --source          copy source codes into build directory(use with configure)

make_PlamoBuild.pyもplamobuild_functions.sh同様、メンテナの加藤さんがGitHubで管理してくれているので、最新版のコードはGitHubから入手できます。

メタ・ビルドスクリプトの使用例

ビルドスクリプトに記載するソースコードのURLは-uオプションで指定できるので、ソースコードを入手してビルドスクリプトを生成する手順は以下のようになります。

まず、ブラウザでそのソフトウェアのダウンロード用ページを調べ、ダウンロード用のURLをコピーしておきます。その後、適切なディレクトリに移り、ソースコードをダウンロードして展開します。

$ wget --no-check-certificate https://gstreamer.freedesktop.org/src/orc/orc-0.4.26.tar.xz
...
長さ: 465768 (455K) [application/x-xz]
`orc-0.4.26.tar.xz' に保存中
orc-0.4.26.tar.xz   100%[===================>] 454.85K   686KB/s    in 0.7s    

$ tar xvf orc-0.4.26.tar.xz
orc-0.4.26/
orc-0.4.26/orc.pc.in
orc-0.4.26/tools/
orc-0.4.26/tools/Makefile.in
...

コピーしたURLを-uオプションに指定してmake_PlamoBuild.pyでビルドスクリプトを生成します。

$ make_PlamoBuild.py -u https://gstreamer.freedesktop.org/src/orc/orc-0.4.26.tar.xz orc-0.4.26

このコマンドで作成されたorc-0.4.26用ビルドスクリプトは以下のようになります。

  1    #!/bin/sh
  2    ##############################################################
  3    pkgbase='orc'
  4    vers='0.4.26'
  5    url="https://gstreamer.freedesktop.org/src/${pkgbase}/${pkgbase}-${vers}.tar.xz"
  6    arch=`uname -m`
  7    build=P1
  8    src="${pkgbase}-${vers}"
  9    OPT_CONFIG='--disable-static --enable-shared'
 10    DOCS='COPYING README RELEASE TODO'
 11    patchfiles=''
 12    compress=txz
 13    ##############################################################
 14    
 15    source /usr/share/plamobuild_functions.sh
 16    
 17    # このスクリプトで使う1文字変数の意味
 18    # 
 19    # $W : このスクリプトを動かすカレントディレクトリ
 20    # $S : ソースコードのあるディレクトリ(デフォルト: $W/${src})
 21    # $B : ビルド用ディレクトリ(デフォルト: /tmp/build{,32})
 22    # $P : ビルドしたファイルをインストールするディレクトリ(デフォルト: $W/work)
 23    
 24    
 25    if [ $# -eq 0 ] ; then
 26      opt_download=0 ; opt_config=1 ; opt_build=1 ; opt_package=1
 27    else
 28      opt_download=0 ; opt_config=0 ; opt_build=0 ; opt_package=0
 29     for i in $@ ; do
 30       case $i in
 31       download) opt_download=1 ;;
 32       config) opt_config=1 ;;
 33       build) opt_build=1 ;;
 34       package) opt_package=1 ;;
 35       esac
 36     done
 37   fi
 38   if [ $opt_download -eq 1 ] ; then
 39       download_sources
 40   fi
 41   
 42   if [ $opt_config -eq 1 ] ; then
 43       if [ -d $B ] ; then rm -rf $B ; fi ; mkdir -p $B 
 44   ######################################################################
 45   #  don't copy sources, so need patch in the src dir
 46   ######################################################################
 47       cd $S
 48       for patch in $patchfiles ; do
 49           if [ ! -f .${patch} ]; then
 50               patch -p1 < $W/$patch
 51               touch .${patch}
 52           fi
 53       done
 54       # if [ -f autogen.sh ] ; then
 55       #   sh ./autogen.sh
 56       # fi
 57   
 58       cd $B
 59       export PKG_CONFIG_PATH=/usr/${libdir}/pkgconfig:/usr/share/pkgconfig:/opt/kde/${libdir}/pkgconfig
 60       export LDFLAGS='-Wl,--as-needed' 
 61       $S/configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var --mandir='${prefix}'/share/man ${OPT_CONFIG[$i]}
 62       
 63       if [ $? != 0 ]; then
 64           echo "configure error. $0 script stop"
 65           exit 255
 66       fi
 67   fi
 68       
 69   if [ $opt_build -eq 1 ] ; then
 70       cd $B
 71       export LDFLAGS='-Wl,--as-needed'
 72       make -j3
 73       if [ $? != 0 ]; then
 74           echo "build error. $0 script stop"
 75           exit 255
 76       fi
 77   fi
 78   
 79   if [ $opt_package -eq 1 ] ; then
 80     check_root
 81     if [ -d $P ] ; then rm -rf $P ; fi ; mkdir -p $P
 82     cd $B
 83     export LDFLAGS='-Wl,--as-needed'
 84     make install DESTDIR=$P
 85   
 86   ################################
 87   #      install tweaks
 88   #  strip binaries, delete locale except ja, compress man, 
 89   #  install docs and patches, compress them and  chown root.root
 90   ################################
 91     install_tweak
 92   
 93   #############################
 94   #   convert symlink to null file and 
 95   #   add "ln -sf" command into install/doinst.sh
 96   ################################
 97     convert_links
 98   
 99     cd $P
100   /sbin/makepkg ../$pkg.$compress <<EOF
101   y
102   1
103   EOF
104   
105   fi

例に用いたorc-0.4.26の場合、自動生成したビルドスクリプトに手を加える必要はなく、そのままで新バージョンのパッケージが作成できました。

上記ビルドスクリプトをご覧いただければ分かるように、新しいスクリプトではbshレベルのシンプルな機能しか使っておらず、先に紹介したplamobuild_functions.shを15行目でsourceし、39行目のdownload_sources80行目のcheck_root91行目のinstall_tweak97行目のconvert_linksの4ヵ所でplamobuild_functions.shに隠蔽した処理を呼び出しています。

旧バージョンのorcをパッケージ化する際に利用したビルドスクリプトは292行だったので、行数は1/3ほどに削減できたようです。

「別ファイルに処理を分けるとスクリプトの独立性が低くなってわかりにくくなる」という意見もあるものの、この程度ならばシンプル化して読みやすくするメリットの方が大きいように思うので、手元ではこのスタイルのビルドスクリプトでパッケージを作ることにしました。


Plamo Linuxの場合、rpmやdebのような専用のパッケージシステムを利用していないため、今回紹介したようなシンプルなスクリプトでパッケージを作れるメリットがあります。その一方、統一された方法が無いため、もっと技巧を凝らしたビルドスクリプトを愛用するメンテナもいます。そのあたりの多様性もPlamo Linuxの特徴のひとつとしておきましょう(苦笑⁠⁠。

おすすめ記事

記事・ニュース一覧