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

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

最新の内容とより実用的な例でこの入門書を書き換えたものが Guide for Debian Maintainers として入手できます。この新しい入門書を第一次的な入門書として使ってください。

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

## 3.1. quilt のセットアップ

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

    alias dquilt="quilt --quiltrc=${HOME}/.quiltrc-dpkg"
    . /usr/share/bash-completion/completions/quilt
    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` を参照してください。

## 3.2. アップストリームのバグを修正する

以下のようなアップストリームの `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
    ... パッチの詳細

## 3.3. 指定場所へのファイルのインストール

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

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

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

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

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

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

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

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

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

`gentoo` の `Makefile` で該当する部分はこれです[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` へインストールする必要があります。ここで `gentoo` の `Makefile` には、マニュアルページに関する記述がまったく無いことに注意してください。Debian ポリシーでは、すべてのプログラムがそれぞれマニュアルを用意しなければならないと定めていますから、後で gentoo のマニュアルを作成して、それを `/usr/share/man/man1` 以下へインストールすることにします。

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

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

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

それらのファイルを編集し、該当行の `usr/local/lib` を `usr/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` の先頭で定義されているものを除いて、ディレクトリーへの参照をすべて変更してください。

修正前は、`gentoo` の `install` ターゲットはこうなっています:

    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/*` ファイルを送らなくてもよいことに注意してください。

## 3.4. ライブラリーの相違

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

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

    LIBS = -lfoo -lbar

`foo` ライブラリーが存在しないためにあなたのプログラムがコンパイルしないで、`foo2` ライブラリーがその等価を Debian システム上で提供する場合、`foo` を `foo2` に変更する `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`ディレクトリーはもう存在しているはずです。この操作例では、既存のパッケージを更新している場合に合わせて作成しています。

[23] GNU Coding Standards: 7.2.4 DESTDIR: Support for Staged Installs を参照下さい。

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

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

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

第2章 はじめの一歩 |  | 第4章 `debian/` ディレクトリー以下に無くてはならないファイル