続・玩式草子 ―戯れせんとや生まれけん―

第6回Plamoメンテナのすゝめ(余)

前回までにmake_PlamoBuild.pyで作成されるPlamoBuildスクリプトを使って、ソースコードからパッケージを作成する流れを紹介してきました。今回は少し視点を変えて、作成したパッケージをインストールする際の処理を紹介します。

パッケージに含まれる不思議なファイル

Plamo Linuxのパッケージは、rpmやdebといったパッケージ用に開発された独自形式ではなく、インストールしたいファイルをtarでまとめ、それを圧縮しただけの簡単な構造になっています。そのためパッケージの中身もtarやlessといった基本コマンドで確認できます。

$ less FD-3.01h-x86_64-B1.txz 
drwxr-xr-x root/root         0 2019-01-26 10:18:54 usr/
drwxr-xr-x root/root         0 2019-01-26 10:18:54 usr/bin/
-rw-r--r-- root/root     46382 2019-01-26 10:18:54 usr/bin/fd-unicd.tbl
-rw-r--r-- root/root     20429 2019-01-26 10:18:54 usr/bin/fd-dict.tbl
-rw-r--r-- root/root     12841 2019-01-26 10:18:54 usr/bin/fd-cat.ja
-rw-r--r-- root/root     12340 2019-01-26 10:18:54 usr/bin/fd-cat.C
-rwxr-xr-x root/root    719488 2019-01-26 10:18:54 usr/bin/fd
hrwxr-xr-x root/root         0 2019-01-26 10:18:54 usr/bin/fdsh usr/bin/fd へのリンク
...

さらにはemacsを使って内部のテキストファイルを直接確認することも可能です。

図1 emacsでzlib-1.2.8-x86_64-P2.txzパッケージを開いたところ
図1 emacsでzlib-1.2.8-x86_64-P2.txzパッケージを開いたところ

こうしていくつかのパッケージを眺めていると、パッケージによってはusr/lib以下にサイズ0のファイルが複数含まれていたり、作った覚えのないinstall/doinst.shというファイルが含まれていたりすることに気づくでしょう。

たとえばzlib-1.2.8パッケージには、"usr/lib/libz.so"と"usr/lib/libz.so.1"というサイズ0のファイルと、"install/doinst.sh"という作成した覚えのないファイルが存在しています。

$ less ~/Srcs/Plamo-7/Plamo-7.x/x86_64/plamo/00_base/zlib-1.2.8-x86_64-P2.txz 
drwxr-xr-x root/root         0 2016-06-15 19:26:04 usr/
drwxr-xr-x root/root         0 2016-06-15 19:26:04 usr/lib/
drwxr-xr-x root/root         0 2016-06-15 19:26:04 usr/lib/pkgconfig/
-rw-r--r-- root/root       252 2016-06-15 19:26:04 usr/lib/pkgconfig/zlib.pc
-rw-r--r-- root/root    144182 2016-06-15 19:26:04 usr/lib/libz.a
-rwxr-xr-x root/root    110976 2016-06-15 19:26:04 usr/lib/libz.so.1.2.8
-rw-r--r-- root/root         0 2016-06-15 09:00:00 usr/lib/libz.so
-rw-r--r-- root/root         0 2016-06-15 09:00:00 usr/lib/libz.so.1
...
drwxr-xr-x root/root         0 2016-06-15 19:26:04 install/
-rw-r--r-- root/root       160 2016-06-15 09:00:00 install/doinst.sh

さて、これらサイズ0のファイルと、作った覚えのないinstall/doinst.shというファイルは、一体どういう役割を果しているのだろうか、というのが今回の話題です。

install/doinst.shスクリプト

謎解き風に話題を展開する筆力もないので先に答を言ってしまうと(苦笑⁠⁠、このinstall/doinst.shというファイルは、パッケージを展開した直後に実行されるシェルスクリプトで、tarアーカイブを展開しただけでは対応できない処理をするために用意されています。

このスクリプトの主な使い道は、tarアーカイブに収めるべきではないシンボリックリンクを復元させることで、PlamoBuildスクリプトや/sbin/makepkgコマンドは、パッケージ化しようとしているディレクトリツリー中にシンボリックリンクを見つけた場合、そのリンクがtarアーカイブ中に含まれないように刈り取って、tarアーカイブを展開後に復元するような操作をinstall/doinst.shに追加します。

シンボリックリンクをスクリプトに変換する処理は、先に見たzlibパッケージのような共有ライブラリを提供するパッケージでは必須です。というのも、共有ライブラリの場合、libz.so.1.2.8という完全なバージョン番号を含んだライブラリ名から、メジャーバージョン番号のみを含んだlibz.so.1ライブラリ名のみを含んだlibz.soというシンボリックリンクを用意することになっており、共有ライブラリを含むパッケージでは、install/doinst.shスクリプトでそれらシンボリックリンクを再現する必要があるからです。

そのため、上記zlib-1.2.8パッケージのinstall/doinst.shには、以下のような「同名のファイルがあれば削除してシンボリックリンクを張る」という処理が設定されています。

  1  ( cd usr/lib ; rm -rf libz.so )
  2  ( cd usr/lib ; ln -sf libz.so.1.2.8 libz.so )
  3  ( cd usr/lib ; rm -rf libz.so.1 )
  4  ( cd usr/lib ; ln -sf libz.so.1.2.8 libz.so.1 )

一方、パッケージに含まれるファイルを調べると、"libz.so"と"libz.so.1"はそれぞれサイズが0のファイルになっています。

-rw-r--r-- root/root         0 2016-06-15 09:00:00 usr/lib/libz.so
-rw-r--r-- root/root         0 2016-06-15 09:00:00 usr/lib/libz.so.1

これらサイズが0の、展開はされるもののinstall/doinst.shスクリプトで即座に削除、置き換えられるファイルは、⁠このパッケージにはこういう名前のシンボリックリンクが作成される」ことを示す目印、いわゆる「プレースホルダー」として置かれているわけです。

このシンボリックリンクをスクリプトに変換する処理は、PlamoBuildスクリプトが自動的に行うので、通常は気にする必要ありません。具体的には、makepkgを実行する直前の"convert_links"がそのための処理になっています。

 91  #############################
 92  #   convert symlink to null file and 
 93  #   add "ln -sf" command into install/doinst.sh
 94  ################################
 95    convert_links
 96  
 97    cd $P
 98    /sbin/makepkg ../$pkg.$compress <<EOF

このconvert_linksの実体は、ビルド用の処理をまとめた"/usr/share/plamobuild_functions.sh"に定義されているので、興味ある方は調べてみてください。

なお、convert_linksの処理は、共有ライブラリに限らず、パッケージ化しようとしているディレクトリツリーにある全てのシンボリックリンクに適用されるので、"make install"が作成する以外のリンクも事前に用意しておけばinstall/doinst.shに変換できます。

install/initpkgスクリプト

ソフトウェアの中には、インストール時に「初期化」作業が必要なものがあります。たとえば、新しくフォントをインストールする際には、"fc-cache"コマンドを実行してfontconfigのキャッシュデータを更新する必要がありますし、独自のデータ形式を利用するアプリケーションを追加した場合は、"update-mime-database"や"update-desktop-database"コマンドを実行し、拡張子やファイルの種類とアプリケーションの関連づけデータを更新しなければなりません。

このような「初期化」処理は、手動でソフトウェアをビルド、インストールする際は、ドキュメント等に記載されている手順をそのまま用いて問題ないものの、パッケージに組み込む際には少し考えないといけません。

というのも、パッケージ化したソフトウェアの場合、動作中の環境にインストールする場合(追加インストール)とインストーラから全く新しい環境にインストールする場合(新規インストール)では適用すべき対象が異なり、単純に「インストール後に初期化処理を行う」だけでは通用しなくなるからです。

Plamo Linuxを例にとると、インストーラとして公開しているDVDイメージから起動すると、ramdiskをルートパーティションとするインストール用の最小規模なLinuxシステムが起動します。このインストール用Linuxシステムは、インストール先として指定したHDDパーティションを/mntにマウントし、選択されたパッケージを/mnt以下にインストールしていきます。

このような状況で、⁠インストール後の初期化処理」を単純に実行すると、その処理は、本来適用されるべき/mnt以下の新環境ではなく、電源を落したら消えてしまうramdisk上の環境に適用されてしまいます。

このような問題に対応するため、Plamo Linuxではinitpkgという仕組みを導入して、新規インストールの場合、⁠インストール後の初期化処理」はインストール時ではなく、再起動して新システムを立ちあげた際に実行するようにしています。

initpkgの例としてuimのビルドスクリプトを取りあげてみましょう。uim(Universal Input Method)はさまざまな言語やかな漢字変換エンジンに対応したインプットメソッドで、XfceやMateといったデスクトップ環境の基盤であるGTK2/GTK3にも対応しています。

一方、GTK2/GTK3では、さまざまな言語に柔軟に対応するため、任意の入力メソッドをモジュールとして追加できるようになっているものの、追加した入力メソッドを有効にするには、"gtk-query-immodules"というコマンドを実行する必要があります。

そのため、uimのビルドスクリプト(PlamoBuild.uim-1.8.6)では、"make install"した後、install/initpkgというファイルへGTK2、GTK3それぞれの環境用に"gtk-query-immodules"を呼び出す処理を書き込んでいます。

 82    make install DESTDIR=$P
 83    mkdir -p $P/install
 84    cat <<"EOF" > $P/install/initpkg
 85  if [ -x /usr/bin/gtk-query-immodules-2.0 ]; then
 86      /usr/bin/gtk-query-immodules-2.0 --update-cache
 87  fi
 88  
 89  if [ -x /usr/bin/gtk-query-immodules-3.0 ]; then
 90      /usr/bin/gtk-query-immodules-3.0 --update-cache
 91  fi
 92  
 93  EOF
 94  

このinstall/initpkgに書き込まれたコードは、makepkgコマンドによってinstall/doinst.shファイルにマージされ、パッケージに取り込まれます。その際、元々のinstall/doinst.shの処理(シンボリックリンクの復元)とは区別できるように、前後に"#%% begin initialize"と"#%% end"の行が挿入されます。

$ cat -n install/doinst.sh
   1  ( cd usr/lib ; rm -rf libgcroots.so.0 )
   2  ( cd usr/lib ; ln -sf libgcroots.so.0.1.0 libgcroots.so.0 )
 ...
 263  ( cd usr/share/uim/pixmaps ; rm -rf m17n-zh-zhuyin.png )
 264  ( cd usr/share/uim/pixmaps ; ln -sf /usr/share/m17n/icons/zh-zhuyin.png m17n-zh-zhuyin.png )
 265  #%% begin initialize 
 266  if [ -x /usr/bin/gtk-query-immodules-2.0 ]; then
 267      /usr/bin/gtk-query-immodules-2.0 --update-cache
 268  fi
 269  
 270  if [ -x /usr/bin/gtk-query-immodules-3.0 ]; then
 271      /usr/bin/gtk-query-immodules-3.0 --update-cache
 272  fi
 273  
 274  #%% end

このパッケージをインストールする際、/sbin/installpkgコマンドは、tarアーカイブを展開後、マージされたinitpkgのコードをinstall/doinst.shから/var/log/initpkg/に移した上で、残りの部分(シンボリックリンクの復元)処理を実行します。

一方、/var/log/initpkg/に切り出された初期化処理は、追加インストールの場合は即座に、新規インストールの場合は再起動して新しい環境が立ち上がった際に、/etc/rc.d/rc.initpkgから実行され、環境に応じた初期化処理を実現します。

実行されたinstall/doinst.shのコードは、/var/log/scripts/に、パッケージ名をファイル名にして保存され(この例では/var/log/scripts/uim⁠⁠、切り出して別途実行された初期化用のコードは/var/log/initpkg.log/に同じくパッケージ名のファイル(/var/log/initpkg.log/uim)として保存されるので、それぞれのパッケージがどのような初期化処理を行ったのかを後から確認することもできます。

/var/log/initpkg/に切り出したパッケージの初期化処理は、正常に実行できるまで/var/log/initpkg/に留まり、システムを起動するたびに再実行が試みられます。あるパッケージをインストールした後、起動時にエラーメッセージが表示され続けるようになった場合は、このディレクトリに何かファイルが残っていないかをチェックしてください。


今回は作成したパッケージをインストールする際に必要となるinstall/doinst.shスクリプトを紹介しました。

もっとも、前半で紹介したシンボリックリンクをスクリプトに変換する処理はPlamoBuildスクリプトが自動的にやってくれますし、後半で紹介したinitpkgの仕組みも「インストール後に必要な初期化処理はinstall/initpkgファイルに記述する」ことだけ覚えておけば、後の処理はmakepkgやinstallpkgといったパッケージ管理ツールがよろしくやってくれるので、通常のパッケージ作りの際にはそれほど気にする必要はありません。

しかしながら、パッケージ作りに慣れてくると、より便利に、より使いやすくなるように、インストール後のシステム環境をあれこれ調整したくなるはずで、その際には、今回紹介したような知識も役に立つことでしょう。ぜひこれらの機能を使いこなして、Plamo Linuxのメンテナにご参加ください。

おすすめ記事

記事・ニュース一覧