第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 を参照してください。

以下のようなアップストリームの Makefile にエラーを見つけて、install: gentoo の部分が 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

ファイルが /usr/local 以下にインストールされるようになっていることがわかります。 上記説明にあるように、そのディレクトリーヒエラルキーは Debian 上のローカルユーザー向けに予約されているので、これらのパスを以下のように変更してください:

# 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

debian/patches/fix-gentoo-target.patch のような、特に Debian パッケージだけに限定されない変更を行った場合、その内容をアップストリームのメンテナーに報告するようにしてください。そうすれば、プログラムの次版に反映してもらうことができ、他のすべての利用者にとっても有益な結果をもたらすことになります。また、あなたの修正を送る前に、Debian や Linux (あるいは Unix でさえも!) に特化した修正にせず、移植性をもたせることも忘れないでください。そうすれば、あなたの変更はずっと採用されやすくなります。

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

よくある問題がもう一つあります。ライブラリーはしばしばプラットフォームごとに異なります。例えば、Makefile は Debian システム上に存在しないライブラリーへの参照を含んでいるかもしれません。その場合には、Debian 上に存在する互換ライブラリーを指すように変更し、同じ目的を果たすようにしてやらなければなりません。

あなたのプログラムの 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 に合わせてソースコードへの必要な変更を加える必要があります。