前回 までに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パッケージを開いたところ
こうしていくつかのパッケージを眺めていると、パッケージによっては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に追加します。
シンボリックリンクは、ファイルの実体とは関係ない、ファイル名に対する参照なため、ファイルの実体をまとめるように設計されているtarアーカイブとは相性がよくありません。そのため、昔のbusyboxのようにシンボリックリンクには対応していないtarの実装もありましたし、Linuxで標準のGNU tarでも、バージョンによってシンボリックリンクが既存ファイルを上書きする際の動作が異なっていたことがありました。これらの事情から、Plamo Linux(正確にはその元となったSlackaware Linux)では「パッケージにはシンボリックリンクを含めない」という方針を取っています。
シンボリックリンクをスクリプトに変換する処理は、先に見たzlibパッケージのような共有ライブラリを提供するパッケージでは必須です。というのも、共有ライブラリの場合、libz.so.1.2.8 という完全なバージョン番号を含んだライブラリ名から、メジャーバージョン番号のみを含んだlibz.so.1 、ライブラリ名のみを含んだlibz.so というシンボリックリンクを用意することになっており、共有ライブラリを含むパッケージでは、install/doinst.shスクリプトでそれらシンボリックリンクを再現する必要があるからです。
共有ライブラリは、動的リンクされる際にはメジャーバージョンまでを指定した"libz.so.1"という名前、コンパイル時にリンカから呼び出される際はバージョン番号を略した"libz.so"という名前で参照されます。
そのため、上記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"というコマンドを実行する必要があります。
gtk-query-immodulesコマンドは、GTK2/GTK3それぞれに用意されており、GTK2ではgtk-query-immodules-2.0、GTK3ではgtk-query-immodules-3.0という名前になっています。
そのため、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のメンテナにご参加ください。