第3章 ソースコードの変更

目次

3.1. quilt のセットアップ
3.2. アップストリームのバグを修正する
3.3. 指定場所へのファイルのインストール
3.4. ライブラリーの相違

アップストリームのソースを修正する具体的なやり方について、何から何まで説明するにはとても紙面が足りませんが、よくあるパターンとしては大体以下のようなものでしょう。

quilt プログラムはアップストリームソースに対する Debian パッケージ向け修正を記録する、基本的な方法を提供します。Debian パッケージで使うには、多少カスタマイズしたデフォルトを使うのが望ましいので、以下の行を ~/.bashrc に追加し Debian パッケージ作成用のエリアス dquilt を作りましょう。第 2 行目は quilt コマンドのシェル入力完了機能と同様の機能を dquilt コマンドに与えます:

alias dquilt="quilt --quiltrc=${HOME}/.quiltrc-dpkg"
complete -F _quilt_completion -o filenames dquilt

~/.quiltrc-dpkg ファイルを次のように作成しましょう:

d=. ; while [ ! -d $d/debian -a `readlink -e $d` != / ]; do d=$d/..; done
if [ -d $d/debian ] && [ -z $QUILT_PATCHES ]; then
    # if in Debian packaging tree with unset $QUILT_PATCHES
    QUILT_PATCHES="debian/patches"
    QUILT_PATCH_OPTS="--reject-format=unified"
    QUILT_DIFF_ARGS="-p ab --no-timestamps --no-index --color=auto"
    QUILT_REFRESH_ARGS="-p ab --no-timestamps --no-index"
    QUILT_COLORS="diff_hdr=1;32:diff_add=1;34:diff_rem=1;31:diff_hunk=1;33:diff_ctx=35:diff_cctx=33"
    if ! [ -d $d/debian/patches ]; then mkdir $d/debian/patches; fi
fi

quilt の使い方については、quilt(1)/usr/share/doc/quilt/quilt.pdf.gz を参照してください。

Let's assume you find an error in the upstream Makefile as follows, where install: gentoo should have been install: gentoo-target.

install: gentoo
        install ./gentoo $(BIN)
        install icons/* $(ICONS)
        install gentoorc-example $(HOME)/.gentoorc

これを修正して、dquilt コマンドを使って fix-gentoo-target.patch として登録しましょう: [22]

$ mkdir debian/patches
$ dquilt new fix-gentoo-target.patch
$ dquilt add Makefile

Makefile ファイルを次のように変更します:

install: gentoo-target
        install ./gentoo $(BIN)
        install icons/* $(ICONS)
        install gentoorc-example $(HOME)/.gentoorc

パッチを更新して debian/patches/fix-gentoo-target.patch を作成するように dquilt に要求し、それから説明を DEP-3: Patch Tagging Guidelines に準拠して追記します:

$ dquilt refresh
$ dquilt header -e
... パッチの詳細

通常、サードパーティーソフトウェアは自分自身を /usr/local サブディレクトリーにインストールします。Debian 上ではこれはシステム管理者 (もしくはユーザー) の個人用に予約されているため、パッケージャーは /usr/local のようなディレクトリーを使わず、Filesystem Hierarchy Standard (FHS) に従って /usr/bin サブディレクトリーのようなシステムディレクトリーを使わなくてはなりません。

プログラムのビルドを自動化するには、通常 make(1) が使われており、make install を実行すると、(Makefileinstall ターゲットに従い) 希望する場所へ直接インストールされます。Debian ではビルド済みのインストール可能なパッケージを提供するために、実際のインストール先のかわりに、一時ディレクトリーの下に作成されたファイルツリーのイメージへプログラムをインストールするようにビルドシステムを変更します。

普通のプログラムインストールとDebian パッケージ作成というこれら二つの違いには、debhelper パッケージの dh_auto_configuredh_auto_install のコマンドを使うことで特に意識せずに対応できます:

  • Makefile ファイルが GNU の慣例に準拠し、$(DESTDIR) 変数をサポートしていること。[23]

  • ソースは Filesystem Hierarchy Standard (FHS) に準拠している必要があります。

GNU autoconf を使っているプログラムは、自動的に GNU 規約に準拠するので、そのパッケージ作成はいとも簡単にできます。こういう事実や他から類推すると、debhelper パッケージはビルドシステムに立ち入った変更を加えることなく、約 90% のパッケージで使えると推定されます。そのため、パッケージ作成は見かけほど複雑ではありません。

もし Makefile ファイルを変更する必要があるなら、これら $(DESTDIR) 変数をサポートするように注意しましょう。デフォルトではアンセットされているとはいえ、プログラムのインストールに使われる各ファイルパスの前に$(DESTDIR) 変数は付与されます。パッケージ作成スクリプトは $(DESTDIR) を一時ディレクトリーにセットします。

単一バイナリーパッケージを生成するソースパッケージでは、debian/packagedh_auto_install コマンドが使う一時ディレクトリーとして指定されます。[24] 一時ディレクトリーに含まれているものはすべて、ユーザーがあなたのパッケージをインストールする時に、ユーザーのシステムにインストールされます。唯一の違いは、dpkg はファイルをあなたの作業ディレクトリーではなくルートディレクトリーからの相対パスにインストールするということです。

パッケージの作成時は、あなたのプログラムは debian/package にインストールされますが、.deb パッケージからルートディレクトリー下にインストールされた場合も正しく動作する必要があることを覚えておいてください。こうするためには、ビルドシステムがパッケージファイルの中のファイル中に /home/me/deb/package-version/usr/share/package といった文字列をハードコードしないようにしなければなりません。

gentooMakefile で該当する部分はこれです[25]:

# Where to put executable commands on 'make install'?
BIN     = /usr/local/bin
# Where to put icons on 'make install'?
ICONS   = /usr/local/share/gentoo

We see that the files are set to install under /usr/local. As explained above, that directory hierarchy is reserved for local use on Debian, so change those paths as follows:

# Where to put executable commands on 'make install'?
BIN     = $(DESTDIR)/usr/bin
# Where to put icons on 'make install'?
ICONS   = $(DESTDIR)/usr/share/gentoo

バイナリー、アイコン、文書など、それぞれのファイルを保存すべき正確な場所については、Filesystem Hierarchy Standard (FHS) 中に規定されています。全体に目を通して、あなたのパッケージに該当する箇所を読むことをお勧めします。

そういうわけで、実行可能バイナリーは /usr/local/bin ではなく /usr/bin へインストールしなければなりませんし、マニュアルページは /usr/local/man/man1 の代わりに /usr/share/man/man1 へインストールする必要があります。ここで gentooMakefile には、マニュアルページに関する記述がまったく無いことに注意してください。Debian ポリシーでは、すべてのプログラムがそれぞれマニュアルを用意しなければならないと定めていますから、後で gentoo のマニュアルを作成して、それを /usr/share/man/man1 以下へインストールすることにします。

プログラムの中には、このようなパスを定義するための Makefile 変数を使っていないものもあります。このような場合、C のソースそのものをいじって、指定された場所を使うように修正しなければなりません。でもどこを探し、何を確認すればよいのでしょうか? 以下のコマンドを実行すれば該当箇所を見つけることができます:

$ grep -nr --include='*.[c|h]' -e 'usr/local/lib' .

grep がソースツリーを再帰的に検索し、該当箇所を見つけたらそのファイルの名前と検索対象の文字列が含まれる行番号とを表示します。

それらのファイルを編集し、該当行の usr/local/libusr/lib に置き換えてください。これは以下の様にすると自動化出来ます:

$ sed -i -e 's#usr/local/lib#usr/lib#g' \
        $(find . -type f -name '*.[c|h]')

こうする代わりに、各置換を確認したい場合は、これは以下のようにインタラクティブにできます:

$ vim '+argdo %s#usr/local/lib#usr/lib#gce|update' +q \
        $(find . -type f -name '*.[c|h]')

修正が終ったら、 install ターゲットを探しましょう(install: で始まる行を探してください。この方法でたいていうまくいきます)。Makefile の先頭で定義されているものを除いて、ディレクトリーへの参照をすべて変更してください。

修正前は、gentooinstall ターゲットはこうなっています:

install: gentoo-target
        install ./gentoo $(BIN)
        install icons/* $(ICONS)
        install gentoorc-example $(HOME)/.gentoorc

dquilt コマンドを使って、debian/patches/install.patch としてアップストリームバグを修正して記録しましょう。

$ dquilt new install.patch
$ dquilt add Makefile

Debian パッケージ用に、これをエディタで次のように変更します:

install: gentoo-target
        install -d $(BIN) $(ICONS) $(DESTDIR)/etc
        install ./gentoo $(BIN)
        install -m644 icons/* $(ICONS)
        install -m644 gentoorc-example $(DESTDIR)/etc/gentoorc

お気づきになったでしょうが、変更後はこのルールの他のコマンドより前に install -d コマンドが追加されています。make install を実行するようなシステムなら /usr/local/bin やその他のディレクトリーはたいがい既に存在しているでしょうから、もともとの Makefile ではこのコマンドは使われていませんでした。しかし、私たちは独自に空っぽの(あるいはまだ存在さえしていない)ディレクトリーにインストールするわけですから、これらの各ディレクトリーを毎回作成する必要があります。

ルールの最後には、アップストリームの作者が省略することの多い付加的な資料のインストールなど、他の作業を追加することもできます:

        install -d $(DESTDIR)/usr/share/doc/gentoo/html
        cp -a docs/* $(DESTDIR)/usr/share/doc/gentoo/html

しっかりチェックをして、何も問題がないようであれば、dquilt でパッチを更新して debian/patches/install.patch を作成し、パッチの説明を追記してください:

$ dquilt refresh
$ dquilt header -e
... パッチの詳細

これで、一連のパッチができました。

  1. アップストリームのバグ修正: debian/patches/fix-gentoo-target.patch

  2. Debian 固有のパッケージ上の変更: debian/patches/install.patch

Whenever you make changes that are not specific to the Debian package such as debian/patches/fix-gentoo-target.patch, be sure to send them to the upstream maintainer so they can be included in the next version of the program and be useful to everyone else. Also remember to avoid making your fixes specific to Debian or Linux — or even Unix! Make them portable. This will make your fixes much easier to apply.

アップストリームの作者へ debian/* ファイルを送らなくてもよいことに注意してください。

There is one other common problem: libraries are often different from platform to platform. For example, a Makefile can contain a reference to a library that doesn't exist on the Debian system. In that case, we need to change it to a library that does exist in Debian, and serves the same purpose.

あなたのプログラムの Makefile (もしくは Makefile.in) が以下のようになっていると仮定しましょう。

LIBS = -lfoo -lbar

foo ライブラリーが存在しないためにあなたのプログラムがコンパイルしないで、foo2 ライブラリーがその等価を Debian システム上で提供する場合、foofoo2 に変更する debian/patches/foo2.patch としてこのビルド問題を解決できます:[26]

$ dquilt new foo2.patch
$ dquilt add Makefile
$ sed -i -e 's/-lfoo/-lfoo2/g' Makefile
$ dquilt refresh
$ dquilt header -e
... describe patch


[22] 前に説明したように dh_make を実行していれば、debian/patchesディレクトリーはもう存在しているはずです。この操作例では、既存のパッケージを更新している場合に合わせて作成しています。

[24] 複数バイナリーパッケージを生成するソースパッケージでは、debian/tmpdh_auto_install コマンドが使う一時ディレクトリーとしますが、debian/tmp の中身を debian/package-1debian/package-2 一時ディレクトリーへと、debian/package-1.installdebian/package-2.install ファイルによる指定に従い dh_install コマンドが分配することで複数バイナリー *.deb パッケージを作成されます。

[25] これは Makefile ファイルがこうなっているべきである、ということを示すための例にすぎません。Makefile ファイルが ./configure コマンドで作成されているなら、この手の Makefile を修正する正しい方法は、dh_auto_configure コマンドに --prefix=/usr を含むデフォルトのオプションを与えて、./configure コマンドを実行させることです。

[26] foo ライブラリーから foo2 ライブラリーへの API 変更があった場合、新しい API に合わせてソースコードへの必要な変更を加える必要があります。