Ubuntuユーザーに送る軽率なdebパッケージング

# はじめに
debパッケージは利用するには便利だが作るとなると途端に面倒くさくなる。Debianの長い歴史の中で数々のユーティリティが作られ、新しいツールも置換することを目的とせず多くの歴史的スクリプトに依存しつつ補完しているからだ。またDebianコミュニティはdebパッケージをDebianのみ使うことを想定しており、ユーティリティにはDebianポリシーに適合するかといったDebian固有の要求事項が一緒くたになっている。信頼出来る唯一の情報源であるDebian文書も同様であり、debパッケージのビルドシステムは広範なLinuxディストリビューションにパッケージを提供するために設計されていない。

※もっともこれはDebianに後乗りした派生ディストロが解決すべき課題なのだが。

とはいってもdebパッケージはDebian系ディストロでのソフトウェア/データ運搬手段として優れている。SnapとかAppImageといったサンドボックス系パッケージシステムはまだ版図が決まりきっていない印象があり、現実的にはdebパッケージを使わざるを得ない。

本文では飽くまでリポジトリへのアップロードを目的とせず、個人もしくは組織内部で使うためのdebパッケージの作成方法について取り扱う。

Debian/Ubuntuリポジトリでリリースする為の正当な方法についてはそれらの公式ドキュメントを参照してほしい。

## 簡易版バイナリパッケージ作成方法
バージョン管理もコンパイルもせず、本当にデータの集合をまとめて*.debファイルだけ作りたい場合は`dpkg-dev --build`を実行する方法が簡便だ。以下が分かりやすい。

[社内利用のための deb パッケージング入門 - Cybozu Inside Out](https://blog.cybozu.io/entry/2016/05/16/111500)

この方法はdebのビルド過程の上では最終出力物の梱包だけを行っている状態だ。通常含まれているchangelogやcopyright等のファイルは手動で管理する必要があるし、アーキテクチャ毎にディレクトリを用意しなければならない。1回のリリースだけで終わらず変更を管理する必要があるならソースパッケージを作成してツールによる補助を利用したい。

# ソースパッケージの概要
最近のdebビルドシステムでは次の2つのモデルケースがある。

## 上流ソースが存在するケース
独自にバージョン管理する上流ソースが存在し、それをDebian(系)にポーティングするケース。これらはポーティング後の独自変更を区別するために、`quilt`というパッチ管理ツールを介してソースへの変更を記録する。またこのケースにによるフォーマット自体もquiltと呼ばれ、基本的にこのquiltフォーマットがデフォルトである。

debビルドシステムはソースを保全するために、パッチファイルやパッケージングのために必要な情報の全てをソースツリー直下のdebian/ディレクトリに配置する。同様にバージョン番号も区別し、例えば上流ソースのバージョンが1.2.1であれば、Debianへのポーティングの際にはそこにDebianでのパッチバージョンを追加して1.2.1-1の様になる。

このフォーマットにおけるソースパッケージの実体は以下の様になる。ここでPACKAGEはパッケージ名、VERSIONは上流ソースのバージョン、そしてDEBVERはDebianでのパッチバージョンとする。

- PACKAGE_VERSION.orig.tar.gz
  オリジナルソースのアーカイブ
- PACKAGE_VERSION-DEBVER.tar.xz
  Debian変更部分。上述のdebian/ディレクトリが格納される
- PACKAGE_VERSION-DEBVER.dsc
  ソースパッケージのメタデータファイル・概要やチェックサムが記述される

## (Debian)オリジナルのケース
最初からDebian(または他のディストロ)に向けて開発されており、上流とDebianで変更を区別する必要がないケース。この場合は`quilt`は使われず、このフォーマットはnativeと呼ばれる。

このフォーマットにおけるソースパッケージの実体は以下の様になる。

- PACKAGE_VERSION.tar.xz
- PACKAGE_VERSION.dsc

Debianコミュニティからしてみればdebパッケージの作成動機はほとんどの場合OSSのポーティングであり、従って各種ツールのデフォルトやDebian文書もquiltフォーマットに合わせられている。しかし本文のターゲットである内部使用の場合、恐らく上流ソースと独自変更の区別は無いだろう。従って以降はnativeフォーマットを中心に話を進めていく。`quilt`の使い方まで含めると話が複雑になるし、quiltフォーマットはDebian文書のカバー範囲だ。

# ツール類
ツールが多く、また機能の置換やラッパーの関係が複雑だったので一端整理。本文で使うツールは太字で示す。

## セットアップ
- dh_make
  dhと付くがdebhelperではないらしい、紛らわしい。以前のデファクトスタンダード。
- **debmake**
  dh_makeの後継らしくDebian文書でプッシュされている

## 変更管理

- dquilt
  所定の操作によりソースの変更をパッチファイル(debian/patches/*)に反映してくれる
- **debchange(dch)**
  変更ログ(debian/changelog)の編集

## ビルド
- dpkg-buildpackage
  ソースパッケージからのビルド
- **debuild**
  dpkg-buildpackage + lintian + α

## パッケージングヘルパー
- **debhelper**
  基本的にはdebian/rulesで使うスクリプト群
- CDBS
  debhelperの後継を目指したが置き換わらなかった?
- **dh**
  複数のdebhelperを現在のターゲットを認識してまとめて呼び出すラッパー

※dh_make以前に更に別のdebmake(deb-make?)があったらしく、英語ですら外部サイトだと「dh_makeがあるのでdebmakeは非推奨だよ」と書かれていたりする。

## その他
- devscripts
  debパッケージングのための小規模なスクリプト群・debchangeやdebuildを含む
- **lintian**
  debパッケージがDebianのポリシー沿っているかをチェックする
  内部用なら必ずしも全て従う必要は無いが「らしさ」を確認するのに有用

# インストール
本文で使うツール類は基本的に以下でインストール出来る。

```
$ sudo apt update
$ sudo apt install build-essential devscripts debmake
```

また、ツールの幾つかは共通して環境変数DEBEMAIL及びDEBFULLNAMEを参照する。従って次に様に`~/.bashrc`に記述しておくといい。

```
DEBEMAIL=`liqsuq@example.com`
DEBFULLNAME="liqsuq"
export DEBEMAIL DEBFULLNAME
```

# 手順
## 概要
基本的なフローは時期やプロジェクトによって大きく異なるが現時点で1からパッケージングするなら次の様に行う模様。

- debmakeでセットアップ
- debianディレクトリを編集
- (dquiltで編集)
- debchangeでバージョンを切る
- debuildでビルド
- パッケージの確認(内容/インストール)

ビルドの際には裏でパッケージングヘルパーが動いてパッケージングに関する雑多な処理をある程度は自動で行ってくれる。

## ワークスペースの構築

debパッケージングではソースツリーの親ディレクトリに成果物を出力するのでまずワークスペース(用語がなかったので独自定義)を作成する。

```
$ mkdir ws-deb
$ cd ws-deb
```

そしてソースのtarballを展開するなりコピーするなりしてソースツリーとなるディレクトリを作成する。この時ディレクトリ名はPACKAGE-VERSION/とする。

## セットアップ
PACKAGE-VERSION/に移動し`debmake -n`を実行。するとdebian/ディレクトリが生成されるためこれを調整していく。

## debianディレクトリを編集
debmakeをデフォルト(-x1)で実行すると以下の様なファイル構成になる。

```
$ tree debian/
debian/
├── README.Debian
├── changelog
├── compat
├── control
├── copyright
├── rules
├── source
│     ├── format
│     └── local-options
└── watch
```

各ファイルの詳細は以下を参考にして欲しいが軽く触れておく。
- [第4章 debian/ ディレクトリー以下に無くてはならないファイル - Debian 新メンテナーガイド](https://www.debian.org/doc/manuals/maint-guide/dreq.ja.html)
- [第5章 debianディレクトリーにあるその他のファイル - Debian 新メンテナーガイド](https://www.debian.org/doc/manuals/maint-guide/dother.ja.html)

### 必須ファイル
- **debian/chagelog**
  更新履歴を記録・パッケージのバージョンはここから参照される
- **debian/control**
  ソース/バイナリパッケージのメタデータを記述
- **debian/rules**
  ビルドレシピ・中身はMakefile形式だがdhを介してdebhelperを呼ぶ
- **debian/copyright**
  著作権表記ないしライセンスを統合して記述

### 準必須ファイル
本来はdebパッケージング必須ではなかったが、現在ではパッケージングヘルパーが参照しているためほぼ必須なファイル。とりあえず`debmake`の出力のまま置いておく。

- debian/source/format
  ソースパッケージのフォーマットを定義・3.0 (native/quilt)

### 無くても良いファイル
- debian/compat
  `debhelper`の互換性を定義…なのだが現在はdebian/controlのBuild-Depandsに書くのが推奨らしい  ~~じゃあそっちをテンプレにしてくれよ~~
- debian/README.Debian
  パッケージングの際の通知事項を記述・無ければ削除
- debian/watch
  Debianの上流ソース監視サービス等が使う・nativeの場合不要(lintianが警告する)
- debian/source/local-options
  DebianのVCSで管理する時に使うらしい

### 生成されないけど重要なファイル
- debian/conffiles
  上書き確認する必要がある設定ファイル(/etc/以下除く)を記述
- debian/install
  画像や設定ファイル等ビルドシステムによってインストールされないファイルを記述
- debian/PACKAGE.manpages
  インストールするmanページを記述・「PACKAGE.」は省略可
- debian/{pre,post}{inst,rm}
  {インストール,削除}{前,後}に実行されるスクリプト
- debian/PACKAGE.symbols
  symlinkを貼る必要のあるライブラリで記述・「PACKAGE.」は省略可

既に何らかの仕組みがあるのに{pre,post}{inst|,rm}ファイルにスクリプトを書くべきでは無いだろう。まずはdebian/以下のファイルで出来ることはないか調べてみよう。

## バージョンを切る
debian/changelogは任意のエディタでも書けるが`debchange`というコマンドが用意されている。

## ビルド
`debuild`を実行してみる。`dpkg-buildpackage`と`lintian`が実行される。`dpkg-buildpackage`がうまくいかなければdebian/rulesを中心に確認していく。`lintian`がうまくいかなければまず`lintian -i ../*.changes`を実行してポリシー違反の詳細を確認していく。

## パッケージの確認

コンパイルを必要としないファイルを含む場合、debian/installに書かないと出力されたdebパッケージからファイルが漏れる。そうしたことが無い様に一度debパッケージを展開してみて漏れがないか確認した方が良い。`dokg-deb -R debファイル 出力ディレクトリ`でdebパッケージを展開出来る。前述の`dpkg-dev --build`で簡易的にパッケージを作成する場合と同じ構成をしている。

# 例
## シェルスクリプト
「Hello!!」と出力するだけのシンプルなシェルスクリプトexampleをdebパッケージ化してみよう。

先述の通りワークスペースとソースツリーを作り、scripts/ディレクトリにexampleスクリプトを格納する。

```bash
~$ mkdir -p ws-sh/example-0.1/scripts
~$ cd ws-deb/example-0.1
~/ws-sh/example-0.1$ cat >example <<EOF
> #!/bin/bash
> echo "Hello
> EOF
~/ws-sh/example-0.1$ tree ..
..
└── example-0.1
    └── scripts
        └── example

2 directories, 1 file
```

そして`debmake`を実行。シェルスクリプトである旨を`-b`オプションで伝える。

```bash
~/ws-sh/example-0.1$ debmake -n -b "example:sh"
~/ws-sh/example-0.1$ tree ..
..
└── example-0.1
       ├── debian
       │     ├── README.Debian
       │     ├── changelog
       │     ├── compat
       │     ├── control
       │     ├── copyright
       │     ├── rules
       │     ├── source
       │     │     ├── format
       │     │     └── local-options
       │     └── watch
       └── scripts
              └── example

4 directories, 10 files
```

先述の通りdebian/compat、debian/README.Debian、debian/watch及びdebian/source/local-optionsは必要ないので削除する。

```bash
~/ws-sh/example-0.1$ rm debuan/compat debian/README.Debian debian/watch debian/source/local-options
```

まずはdebian/controlから。Sectionをとりあえずmiscとし、Homepage行を(無いので)削除し、Descriptionを適当に編集する。debian/compatを削除したのでBuild-Dependsも書き換える。

```bash
~/ws-sh/example-0.1$ vim debian/control
:
~/ws-sh/example-0.1$ cat debian/control
Source: example
Section: misc
Priority: optional
Maintainer: liqsuq <liqsuq@example.com>
Build-Depends: debhelper-compat (=11)
Standards-Version: 4.1.4

Package: example
Architecture: all
Multi-Arch: foreign
Depends: ${misc:Depends}
Description: completely example command
 example command is completely example command.
 This outputs "Hello" message.
 This is not intended for anything other than use in the example.
```

今回の場合Make等のインストールを行う機構が無いのでdebian/installを作成する。exampleスクリプトは/usr/bin/以下にインストールする。

```bash
~/ws-sh/example-0.1$ cat >debian/install <<EOF
> scripts/example usr/bin
> EOF
```

debian/copyrightも編集する。今回はライセンス条文が短いという理由で軽率にMITライセンス(Expatライセンス)を使用する。

```bash
~/ws-sh/example-0.1$ vim debian/copyright
:
~/ws-sh/example-0.1$ cat debian/copyright
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: example

Files: *
Copyright: 2022 liqsuq <liqsuq@example.com>
License: Expat
 Permission is hereby granted, free of charge, to any person obtaining a
 copy of this software and associated documentation files (the "Software"),
 to deal in the Software without restriction, including without limitation
 the rights to use, copy, modify, merge, publish, distribute, sublicense,
 and/or sell copies of the Software, and to permit persons to whom the
 Software is furnished to do so, subject to the following conditions:
 .
 The above copyright notice and this permission notice shall be included
 in all copies or substantial portions of the Software.
 .
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 
 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
```

概ね必要な編集は済んだので`debchange`を使ってバージョンを切る。`debmake`が生成したテンプレートを削る。

```bash
~/ws-sh/example-0.1$ debchange
:
~/ws-sh/example-0.1$ cat debian/changelog
example (0.1) UNRELEASED; urgency=low

  * Initial release.

 -- liqsuq <liqsuq@example.com>  Fri, 29 Jul 2022 09:40:29 +0900
```

ここで一旦`debuild`してみる。

```bash
~/ws-deb/example-0.1$ debuild
 dpkg-buildpackage -us -uc -ui
dpkg-buildpackage: info: source package example
dpkg-buildpackage: info: source version 0.1
dpkg-buildpackage: info: source distribution UNRELEASED
dpkg-buildpackage: info: source changed by liqsuq <liqsuq@example.com>
:
Now running lintian example_0.1_amd64.changes ...
W: example: binary-without-manpage usr/bin/example
Finished running lintian.
```

`lintian`の警告が1件出てきた。詳細メッセージを確認する。

```bash
~/ws-sh/example-0.1$ lintian -i ../example_0.1_amd64.changes 
W: example: binary-without-manpage usr/bin/example
N: 
N:    Each binary in /usr/bin, /usr/sbin, /bin, /sbin or /usr/games should
N:    have a manual page
N:    
N:    Note that though the man program has the capability to check for several
N:    program names in the NAMES section, each of these programs should have
N:    its own manual page (a symbolic link to the appropriate manual page is
N:    sufficient) because other manual page viewers such as xman or tkman
N:    don't support this.
N:    
N:    If the name of the man page differs from the binary by case, man may be
N:    able to find it anyway; however, it is still best practice to make the
N:    case of the man page match the case of the binary.
N:    
N:    If the man pages are provided by another package on which this package
N:    depends, Lintian may not be able to determine that man pages are
N:    available. In this case, after confirming that all binaries do have man
N:    pages after this package and its dependencies are installed, please add
N:    a Lintian override.
N:    
N:    Refer to Debian Policy Manual section 12.1 (Manual pages) for details.
N:    
N:    Severity: warning
N:    
N:    Check: documentation/man
N: 
```

「実行ファイルなのにmanページないじゃん」とのお叱り。Debianポリシーでは実行ファイルにはmanページが存在することを義務付けている。無視しても良いがdebパッケージ「っぽく」なるので追加してみる。

man/example.1にroff形式で簡単なmanページファイルを作成する。※今回はnativeフォーマットなので直接ソースツリーにmanページファイルを書きますが、上流ソースにmanページが無いのでDebian修正としてmanページを作成するためにdebian/以下でmanページを作成する仕組みもある。

```bash
~/ws-sh/example-0.1$ mkdir man
~/ws-sh/example-0.1$ cat >man/example.1 <<EOF
> .TH EXAMPLE 1 "2022-07-28" rkgknet.org "Example Manual"
> 
> .SH NAME
> example \- copletely example command
> 
> .SH SYMPOSIS
> \fBexample\fR
> 
> .SH DESCRIPTION
> \fBexample\fR is a completely example command.
> This outputs "Hello" message.
> This is not intended for anything other than use in the example.
> 
> .SH AUTOR
> Written by liqsuq <liqsuq@example.com>
> EOF
```

debian/manpagesを作成し、man/example.1の存在を指示する。

```bash
~/ws-sh/example-0.1$ cat >debian/manpages <<EOF
> man/example.1
> EOF
```

`debuild`して`lintian`が警告しないことを確認する。

```bash
~/ws-sh/example-0.1$ debuild
 dpkg-buildpackage -us -uc -ui
dpkg-buildpackage: info: source package example
dpkg-buildpackage: info: source version 0.1
dpkg-buildpackage: info: source distribution UNRELEASED
dpkg-buildpackage: info: source changed by liqsuq <liqsuq@example.com>
:
Now running lintian example_0.1_amd64.changes ...
Finished running lintian.
```

debパッケージを展開して意図したファイルが含まれている事を確認する。debian/changelogやdebian/copyright、manページはDebianが想定するディレクトリに格納される。

```bash
~/ws-sh/example-0.1$ cd ..
~/ws-sh$ dpkg-deb -R example_0.1_all.deb example-extracted
~/ws-sh$ tree example-extracted/
example-extracted/
├── DEBIAN
│     ├── control
│     └── md5sums
└── usr
       ├── bin
       │     └── example
       └── share
              ├── doc
              │     └── example
              │            ├── changelog.gz
              │            └── copyright
              └── man
                     └── man1
                            └── example.1.gz

8 directories, 6 files
```

システムにインストールしてみて動作を確認する。

```bash
~/ws-sh$ sudo apt install -y ./example_0.1_all.deb
:
~/ws-sh$ which example
/usr/bin/example
~/ws-sh$ example
Hello!!
```

最後に中間ファイルの削除を行ってからワークスペース全体を見てみよう。

```bash
~/ws-sh$ cd example-0.1/
~/ws-sh/example-0.1$ debuild -- clean
~/ws-sh/example-0.1$ cd ../
~/ws-sh$ rm -rf ../example-extracted/
~/ws-sh$ tree
.
├── example-0.1
│     ├── debian
│     │     ├── changelog
│     │     ├── control
│     │     ├── copyright
│     │     ├── install
│     │     ├── manpages
│     │     ├── rules
│     │     └── source
│     │            └── format
│     ├── man
│     │     └── example.1
│     └── scripts
│            └── example
├── example_0.1.dsc
├── example_0.1.tar.xz
├── example_0.1_all.deb
├── example_0.1_amd64.build
├── example_0.1_amd64.buildinfo
└── example_0.1_amd64.changes

5 directories, 16 files
```

ワークスペース直下にソースパッケージでもバイナリパッケージでも無いファイルが残っているので触れておく。

- example_0.1_amd64.build
  ビルドログ
- example_0.1_amd64.buildinfo
  ビルド時の情報が記述される
- example_0.1_amd64.changes
  バイナリパッケージのメタデータファイル

## シングルバイナリ(Makefile)
今度は「Hello!!」と出力するだけのC++コードexample.cppをdebパッケージ化してみよう。

まずワークスペースとソースツリーを作り、src/ディレクトリにexample.cppを格納する。

```bash
~$ mkdir -p ws-single/example-0.1/src
~$ cd ws-single/example-0.1
~/ws-single/example-0.1$ cat >example.cpp <<EOF
> #include <iostream>
> using namespace std;
> int main(int argc, char **argv) {
>     cout << "Hello!!" << endl;
> }
> EOF
```

このコードをビルドするためにMakefileを作成する。ここでMakefileはGNUコーディング標準に準拠している必要があるらしい。とは言ってもパッケージングで重要なのは以下の1つだけの模様。

- インストール/アンインストールパスにDESTDIR変数を付加すること

distcleanやuninstallといったターゲットは無いとGNUコーディング標準に合わないが、debhelperは無いなら無いでよしなにやってくれる様だ。ただし`make`でビルド、`make install`でインストールといった最低限の作法は必要。

```bash
~/ws-single/example-0.1$ vim Makefile
:
~/ws-single/example-0.1$ cat Makefile
.PHONY: all clean install
all: src/example
install: src/example
    install -D src/example $(DESTDIR)/usr/bin/example
clean:
    -rm -f src/example
```

`debmake`を実行。`-b`オプションでコンパイル言語によるバイナリコードパッケージであることを指示する(デフォルトなので省略可)。

```bash
~/ws-single/example-0.1$ debmake -n -b "example:bin"
~/ws-single/example-0.1$ tree ..
..
└── example-0.1
       ├── debian
       │     ├── README.Debian
       │     ├── changelog
       │     ├── compat
       │     ├── control
       │     ├── copyright
       │     ├── rules
       │     ├── source
       │     │     ├── format
       │     │     └── local-options
       │     └── watch
       └── src
              └── example.cpp

4 directories, 10 files
```

テンプレートファイルの編集はシェルスクリプト版と同様なのでdebian/conpat、debian/README.Debian、debian/watch及びdebian/source/local-optionsを削除してdebian/control、debian/copyright及びdebian/changelogを編集する。man/example.1とdebian/manpagesも作成する。ただし今回はmakeによってexampleバイナリが自動でインストールされるはずなのでdebian/installは不要。

```bash
~/ws-single/example-0.1$ rm debian/compat debian/README.Debian debian/watch debian/source/local-options
~/ws-single/example-0.1$ vim debian/control
:
~/ws-single/example-0.1$ cat debian/control
Source: example
Section: misc
Priority: optional
Maintainer: liqsuq <liqsuq@example.com>
Build-Depends: debhelper-compat (=11)
Standards-Version: 4.1.4

Package: example
Architecture: any
Multi-Arch: foreign
Depends: ${misc:Depends}, ${shlibs:Depends}
Description: completely example command
 example command is completely example command.
 This outputs "Hello" message.
 This is not intended for anything other than use in the example.
~/ws-single/example-0.1$ vim debian/copyright
:
~/ws-single/example-0.1$ debchange
~/ws-single/example-0.1$ cat >man/example.1 <<EOF
:    # 省略
~/ws-single/example-0.1$ echo "man/example.1" >debian/manpages
```

`debmake`で`-b "example:bin"`としてコンパイルが必要なことを通知したため、debian/controlのArchitectureセクションがallからanyに変わったことは認識しておく。ソースパッケージからビルドすることで"どれか"のアーキテクチャに対応するバイナリパッケージが作成されることを示唆している。Debianのリポジトリでは各アーキテクチャで自動でバイナリパッケージをビルドするそうだ。

次に`debuild`してみる。ここで一応debian/controlの`#export DH_VERBOSE = 1`のコメントアウトを外し、`dh`が詳細ログを出力する様にしておく。

```bash
$ debuild
 dpkg-buildpackage -us -uc -ui
dpkg-buildpackage: info: source package example
dpkg-buildpackage: info: source version 0.1
dpkg-buildpackage: info: source distribution UNRELEASED
dpkg-buildpackage: info: source changed by liqsuq <liqsuq@example.com>
 dpkg-source --before-build .
dpkg-buildpackage: info: host architecture amd64
 fakeroot debian/rules clean
dh clean
   dh_auto_clean
        make -j8 clean
make[1]: ディレクトリ '/home/liqsuq/ws-single/example-0.1' に入ります
rm -f src/example
make[1]: ディレクトリ '/home/liqsuq/ws-single/example-0.1' から出ます
   dh_clean
        rm -f debian/debhelper-build-stamp
        rm -rf debian/.debhelper/
        rm -f -- debian/example.substvars debian/files
        rm -fr -- debian/example/ debian/tmp/
        find .  \( \( \
                \( -path .\*/.git -o -path .\*/.svn -o -path .\*/.bzr -o -path .\*/.hg -o -path .\*/CVS -o -path .\*/.pc -o -path .\*/_darcs \) -prune -o -type f -a \
                \( -name '#*#' -o -name '.*~' -o -name '*~' -o -name DEADJOE \
                 -o -name '*.orig' -o -name '*.rej' -o -name '*.bak' \
                 -o -name '.*.orig' -o -name .*.rej -o -name '.SUMS' \
                 -o -name TAGS -o \( -path '*/.deps/*' -a -name '*.P' \) \
                \) -exec rm -f {} + \) -o \
                \( -type d -a -name autom4te.cache -prune -exec rm -rf {} + \) \)
 dpkg-source -b .
dpkg-source: info: using source format '3.0 (native)'
dpkg-source: info: building example in example_0.1.tar.xz
dpkg-source: info: building example in example_0.1.dsc
 debian/rules build
dh build
   dh_update_autotools_config
   dh_autoreconf
   dh_auto_configure
   dh_auto_build
        make -j8 "INSTALL=install --strip-program=true"
make[1]: ディレクトリ '/home/liqsuq/ws-single/example-0.1' に入ります
g++ -g -O2 -fdebug-prefix-map=/home/liqsuq/ws-single/example-0.1=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -Wl,-Bsymbolic-functions -Wl,-z,relro  src/example.cpp   -o src/example
make[1]: ディレクトリ '/home/liqsuq/ws-single/example-0.1' から出ます
   dh_auto_test
   create-stamp debian/debhelper-build-stamp
 fakeroot debian/rules binary
dh binary
   dh_testroot
   dh_prep
        rm -f -- debian/example.substvars
        rm -fr -- debian/.debhelper/generated/example/ debian/example/ debian/tmp/
   dh_auto_install
        install -d /home/liqsuq/ws-single/example-0.1/debian/example
        make -j8 install DESTDIR=/home/liqsuq/ws-single/example-0.1/debian/example AM_UPDATE_INFO_DIR=no "INSTALL=install --strip-program=true"
make[1]: ディレクトリ '/home/liqsuq/ws-single/example-0.1' に入ります
install -D src/example /home/liqsuq/ws-single/example-0.1/debian/example/usr/bin/example
make[1]: ディレクトリ '/home/liqsuq/ws-single/example-0.1' から出ます
   dh_installdocs
        install -d debian/example/usr/share/doc/example
        install -d debian/.debhelper/generated/example
        install -p -m0644 debian/copyright debian/example/usr/share/doc/example/copyright
   dh_installchangelogs
        install -p -m0644 debian/changelog debian/example/usr/share/doc/example/changelog
   dh_installman
        install -d debian/example/usr/share/man/man1/
        install -p -m0644 ./man/example.1 debian/example/usr/share/man/man1/example.1
        man-recode --to-code UTF-8 --suffix .dh-new debian/example/usr/share/man/man1/example.1
        mv debian/example/usr/share/man/man1/example.1.dh-new debian/example/usr/share/man/man1/example.1
        chmod 0644 -- debian/example/usr/share/man/man1/example.1
   dh_perl
   dh_link
   dh_strip_nondeterminism
   dh_compress
        cd debian/example
        chmod a-x usr/share/doc/example/changelog usr/share/man/man1/example.1
        gzip -9nf usr/share/doc/example/changelog usr/share/man/man1/example.1
        cd '/home/liqsuq/ws-single/example-0.1'
   dh_fixperms
        find debian/example -true -print0 2>/dev/null | xargs -0r chown --no-dereference 0:0
        find debian/example ! -type l -a -true -a -true -print0 2>/dev/null | xargs -0r chmod go=rX,u+rw,a-s
        find debian/example/usr/share/doc -type f -a -true -a ! -regex 'debian/example/usr/share/doc/[^/]*/examples/.*' -print0 2>/dev/null | xargs -0r chmod 0644
        find debian/example/usr/share/doc -type d -a -true -a -true -print0 2>/dev/null | xargs -0r chmod 0755
        find debian/example/usr/share/man -type f -a -true -a -true -print0 2>/dev/null | xargs -0r chmod 0644
        find debian/example -type f \( -name '*.so.*' -o -name '*.so' -o -name '*.la' -o -name '*.a' -o -name '*.js' -o -name '*.css' -o -name '*.scss' -o -name '*.sass' -o -name '*.jpeg' -o -name '*.jpg' -o -name '*.png' -o -name '*.gif' -o -name '*.cmxs' -o -name '*.node' \) -a -true -a -true -print0 2>/dev/null | xargs -0r chmod 0644
        find debian/example/usr/bin -type f -a -true -a -true -print0 2>/dev/null | xargs -0r chmod a+x
   dh_missing
   dh_strip
        install -d debian/.debhelper/example/dbgsym-root/usr/lib/debug/.build-id/32
        objcopy --only-keep-debug --compress-debug-sections debian/example/usr/bin/example debian/.debhelper/example/dbgsym-root/usr/lib/debug/.build-id/32/9c6502e560058ad8453db9b3da47e97ee0dbb0.debug
        chmod 0644 -- debian/.debhelper/example/dbgsym-root/usr/lib/debug/.build-id/32/9c6502e560058ad8453db9b3da47e97ee0dbb0.debug
        chown 0:0 -- debian/.debhelper/example/dbgsym-root/usr/lib/debug/.build-id/32/9c6502e560058ad8453db9b3da47e97ee0dbb0.debug
        strip --remove-section=.comment --remove-section=.note debian/example/usr/bin/example
        objcopy --add-gnu-debuglink debian/.debhelper/example/dbgsym-root/usr/lib/debug/.build-id/32/9c6502e560058ad8453db9b3da47e97ee0dbb0.debug debian/example/usr/bin/example
        install -d debian/.debhelper/example/dbgsym-root/usr/share/doc
        ln -s example debian/.debhelper/example/dbgsym-root/usr/share/doc/example-dbgsym
   dh_makeshlibs
        rm -f debian/example/DEBIAN/shlibs
   dh_shlibdeps
        install -d debian/example/DEBIAN
        dpkg-shlibdeps -Tdebian/example.substvars debian/example/usr/bin/example
   dh_installdeb
   dh_gencontrol
        echo misc:Depends= >> debian/example.substvars
        echo misc:Pre-Depends= >> debian/example.substvars
        install -d debian/.debhelper/example/dbgsym-root/DEBIAN
        dpkg-gencontrol -pexample -ldebian/changelog -Tdebian/example.substvars -Pdebian/.debhelper/example/dbgsym-root -UPre-Depends -URecommends -USuggests -UEnhances -UProvides -UEssential -UConflicts -DPriority=optional -UHomepage -UImportant -UBuilt-Using -DAuto-Built-Package=debug-symbols -DPackage=example-dbgsym "-DDepends=example (= \${binary:Version})" "-DDescription=debug symbols for example" -DBuild-Ids=329c6502e560058ad8453db9b3da47e97ee0dbb0 -DSection=debug -DPackage-Type=ddeb -UMulti-Arch -UReplaces -UBreaks
        chmod 0644 -- debian/.debhelper/example/dbgsym-root/DEBIAN/control
        chown 0:0 -- debian/.debhelper/example/dbgsym-root/DEBIAN/control
        dpkg-gencontrol -pexample -ldebian/changelog -Tdebian/example.substvars -Pdebian/example
        chmod 0644 -- debian/example/DEBIAN/control
        chown 0:0 -- debian/example/DEBIAN/control
   dh_md5sums
        cd debian/example >/dev/null && xargs -r0 md5sum | perl -pe 'if (s@^\\@@) { s/\\\\/\\/g; }' > DEBIAN/md5sums
        chmod 0644 -- debian/example/DEBIAN/md5sums
        chown 0:0 -- debian/example/DEBIAN/md5sums
        cd debian/.debhelper/example/dbgsym-root >/dev/null && xargs -r0 md5sum | perl -pe 'if (s@^\\@@) { s/\\\\/\\/g; }' > DEBIAN/md5sums
        chmod 0644 -- debian/.debhelper/example/dbgsym-root/DEBIAN/md5sums
        chown 0:0 -- debian/.debhelper/example/dbgsym-root/DEBIAN/md5sums
   dh_builddeb
        dpkg-deb --build debian/example ..
dpkg-deb: building package 'example' in '../example_0.1_amd64.deb'.
        install -d debian/.debhelper/scratch-space/build-example
        dpkg-deb --build debian/.debhelper/example/dbgsym-root debian/.debhelper/scratch-space/build-example
dpkg-deb: building package 'example-dbgsym' in 'debian/.debhelper/scratch-space/build-example/example-dbgsym_0.1_amd64.deb'.
        Renaming example-dbgsym_0.1_amd64.deb to example-dbgsym_0.1_amd64.ddeb
        mv debian/.debhelper/scratch-space/build-example/example-dbgsym_0.1_amd64.deb ../example-dbgsym_0.1_amd64.ddeb
 dpkg-genbuildinfo
 dpkg-genchanges  >../example_0.1_amd64.changes
dpkg-genchanges: info: including full source code in upload
 dpkg-source --after-build .
dpkg-buildpackage: info: full upload; Debian-native package (full source is included)
Now running lintian example_0.1_amd64.changes ...
Finished running lintian.
```

ビルドもlintianも問題なく終了しているが、実に多くのことをやっている。

先述した様に`debuild`を実行すると`dpkg-buildpackage`が実行され、`dh clean`・`dh build`・`dh binary`等の各ターゲットがdebhelperスクリプト群(dh_*)を呼び出している。例えばdh_auto_cleanはソースのMakefileにdistcleanターゲットがあればdistclean、無ければcleanを実行する様だ。この様にソースのビルドシステムや設定に合わせてある程度はデフォルトで柔軟にビルド出来る様になっている。

今回の単純なソースではビルドが失敗しなかったがもし失敗する場合は、override_dh_*ターゲットを追加してdebhelperの挙動を変更する等、debian/rulesに対して変更を行っていく。

さて、ここでワークスペースを見てみる。

```bash
~/ws-single/example-0.1$ debuild -- clean
~/ws-single/example-0.1$ tree ..
..
├── example-0.1
│     ├── Makefile
│     ├── debian
│     │     ├── changelog
│     │     ├── control
│     │     ├── copyright
│     │     ├── manpages
│     │     ├── rules
│     │     └── source
│     │            └── format
│     ├── man
│     │     └── example.1
│     └── src
│            └── example.cpp
├── example-dbgsym_0.1_amd64.ddeb
├── example_0.1.dsc
├── example_0.1.tar.xz
├── example_0.1_amd64.build
├── example_0.1_amd64.buildinfo
├── example_0.1_amd64.changes
└── example_0.1_amd64.deb

5 directories, 17 files
```

example-dbgsym_0.1_amd64.ddebというファイルが生成されている。これは自動ビルドに組み込まれたデバッグシンボルパッケージだそうで、以前は*-dbgというパッケージ命名方針は共通なもののメンテナによってやったりやらなかったりした物と同じ立ち位置だ。Ubuntuでも存在するが滅多に使われないということで別リポジトリに隔離され、利用するにはソースパッケージよりもやや手間な手順が必要になる。

[Debug Symbol Packages - Ubuntu Wiki](https://wiki.ubuntu.com/Debug%20Symbol%20Packages)

## マルチバイナリ(CMake)
ここではバイナリ、共有ライブラリ、ヘッダファイルを擁するソースパッケージをexample、libexample、libexample-devという3つのバイナリパッケージに分けて作成する方法を例示する。

本題に入っていく前にシングルバイナリと異なる幾つかの注意点を列挙する。

- 一時インストール結果はdebian/PACKAGE/でなくdebian/tmp/に格納される
- どのパッケージに格納するかはdebian/PACKAGE.installで制御する必要がある
- 互換性のためにライブラリはlib*.so->lib*.so.0->lib*.so.0.1の様なsymlinkにする
- MultiArchサポートに伴いライブラリは/usr/lib/x86_64-linux-gnu/といったアーキテクチャ毎のパスに格納する

[5.22. マルチアーキ - Debian メンテナー用ガイド](https://www.debian.org/doc/manuals/debmake-doc/ch05.ja.html#multiarch)

特に4項のMultiArchサポートが曲者で、ビルドシステムでアーキテクチャを検知してインストールパスを切り替える様な仕組みが必要。本来単独ではマルチアーキ/マルチOSの機構を持たないMakefileでこれに対応するには厄介なのでCMakeを使用していく。適切にCMakeを設定すれば3項も自動的にやってくれる。

[Multiarch/Implementation - Debian Wiki](https://wiki.debian.org/Multiarch/Implementation)

いつも通りワークスペースとソースツリーを作り、include/、lib/、man/及びsrc/ディレクトリを作成してソースファイルを配置していく。

```bash
~$ mkdir -p ws-multi/example-0.1/
~$ cd ws-multi/example-0.1
~/ws-multi/example-0.1$ mkdir include lib man src
~/ws-multi/example-0.1$ cat >include/example.h <<EOF
> #pragma once
> void example();
> EOF
~/ws-multi/example-0.1$ cat >lib/libexample.cpp <<EOF
> #include <iostream>
> #include <example.h>
> using namespace std;
> void example() {
>     cout << "example() was called!!" << endl;
> }
> EOF
~/ws-multi/example-0.1$ cat >man/example.1 <<EOF
:    # これまでと同じなので省略
> EOF
~/ws-multi/example-0.1$ cat >src/example.cpp <<EOF
> #include <iostream>
> #include <example.h>
> using namespace std;
> int main(int argc, char **argv) {
>     cout << "Hello!!" << endl;
>     example();
> }
> EOF
```

各ディレクトリにCMakeLists.txtを配置していく。ポイントは`include(GNUInstallDirs)`をインクルードして事前定義された変数`CMAKE_INSTALL_*`を使用することと、ライブラリに対して`VERSION`及び`SOVERSION`プロパティを与えること。`SOVERSION`は通常はライブラリバージョンのメジャーバージョン。

[install — CMake 3.24.0-rc5 Documentation](https://cmake.org/cmake/help/latest/command/install.html)
[GNUInstallDirs — CMake 3.24.0-rc5 Documentation](https://cmake.org/cmake/help/latest/module/GNUInstallDirs.html)

それとlibexample.so.0.1ならライブラリターゲット名はexampleにすること。バイナリターゲット名と被るので以下を参考にした。

[cmakeでライブラリ名と実行ファイル名を同じにする - Qiita](https://qiita.com/m_mizutani/items/d0e77a45931ac5348dc0)

```bash
~/ws-multi/example-0.1$ cat >CMakeLists.txt <<EOF
> cmake_minimum_required(VERSION 3.16)
> project(example VERSION 0.1)
> include(GNUInstallDirs)
> add_subdirectory(lib)
> add_subdirectory(src)
> add_subdirectory(include)
> add_subdirectory(man)
> EOF
~/ws-multi/example-0.1$ cat >lib/CMakeLists.txt <<EOF
> add_library(example SHARED libexample.cpp)
> set_target_properties(example PROPERTIES VERSION ${PROJECT_VERSION})
> set_target_properties(example PROPERTIES SOVERSION ${PROJECT_VERSION_MAJOR})
> target_include_directories(example PUBLIC "${PROJECT_SOURCE_DIR}/include")
> install(TARGETS example)
> EOF
~/ws-multi/example-0.1$ cat >src/CMakeLists.txt <<EOF
> add_executable(example-bin example.cpp)
> set_target_properties(example-bin PROPERTIES OUTPUT_NAME example)
> target_link_libraries(example-bin example)
> install(TARGETS example-bin)
> EOF
~/ws-multi/example-0.1$ cat >include/CMakeLists.txt <<EOF
> install(FILES example.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
> EOF
~/ws-multi/example-0.1$ cat >man/CMakeLists.txt <<EOF
> install(FILES example.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
> EOF
~/ws-multi/example-0.1$ tree ..
..
└── example-0.1
       ├── CMakeLists.txt
       ├── include
       │     ├── CMakeLists.txt
       │     └── example.h
       ├── lib
       │     ├── CMakeLists.txt
       │     └── libexample.cpp
       ├── man
       │     ├── CMakeLists.txt
       │     └── example.1
       └── src
              ├── CMakeLists.txt
              └── example.cpp

5 directories, 10 files
```

`debmake`する。ライブラリパッケージのパッケージ名の末尾にはメジャーバージョンを付けるのが慣習らしく、無いと上手くビルド出来なかったりした。

```bash
~/ws-multi/example-0.1$ debmake -n -b "example:bin,libexample0:lib,libexample-dev:dev"
:
~/ws-multi/example-0.1$ tree ..
..
├── CMakeLists.txt
├── debian
│     ├── README.Debian
│     ├── changelog
│     ├── clean
│     ├── compat
│     ├── control
│     ├── copyright
│     ├── example.doc-base
│     ├── example.docs
│     ├── example.examples
│     ├── example.info
│     ├── example.install
│     ├── example.links
│     ├── example.manpages
│     ├── example.postinst
│     ├── example.postrm
│     ├── example.preinst
│     ├── example.prerm
│     ├── libexample-dev.install
│     ├── libexample0.install
│     ├── libexample0.symbols
│     ├── rules
│     ├── source
│     │     ├── format
│     │     └── local-options
│     └── watch
├── include
│     ├── CMakeLists.txt
│     └── example.h
├── lib
│     ├── CMakeLists.txt
│     └── libexample.cpp
├── man
│     ├── CMakeLists.txt
│     └── example.1
└── src
       ├── CMakeLists.txt
       └── example.cpp

6 directories, 33 files
```

どうもマルチバイナリだとより多くのテンプレートファイルが生成されるらしい(`-x2`)。後で使うファイル以外は削除していく。今回はCMakeでmanページ含めてdebian/tmp/にインストールしているためdebian/manpages等は不要。その代わりにdebian/PACKAGE.installを使用していく。

```bash
~/ws-multi/example-0.1$ rm debian/README.Debian debian/clean debian/compat debian/example.doc-base debian/example.docs debian/example.examples debian/example.info debian/example.links debian/example.manpages debian/example.postinst debian/example.postrm debian/example.preinst debian/example.prerm debian/source/local-options debian/watch
~/ws-multi/example-0.1$ tree ..
..
└── example-0.1
    ├── CMakeLists.txt
    ├── debian
    │     ├── changelog
    │     ├── control
    │     ├── copyright
    │     ├── example.install
    │     ├── libexample-dev.install
    │     ├── libexample0.install
    │     ├── libexample0.symbols
    │     ├── rules
    │     └── source
    │            └── format
    ├── include
    │     ├── CMakeLists.txt
    │     └── example.h
    ├── lib
    │     ├── CMakeLists.txt
    │     └── libexample.cpp
    ├── man
    │     ├── CMakeLists.txt
    │     └── example.1
    └── src
           ├── CMakeLists.txt
           └── example.cpp

7 directories, 18 files
```

これまでと同様に基本的なdebianファイルを書き換える。

```
~/ws_multi/example-0.1$ vim debian/control
:
~/ws_multi/example-0.1$ cat debian/control
Source: example
Section: misc
Priority: optional
Maintainer: liqsuq <liqsuq@example.com>
Build-Depends: cmake, debhelper-compat (=11)
Standards-Version: 4.1.4

Package: example
Architecture: any
Multi-Arch: foreign
Depends: libexample0 (= ${binary:Version}), ${misc:Depends}, ${shlibs:Depends}
Description: completely example command
 example command is completely example command.
 This outputs "Hello" message.
 This is not intended for anything other than use in the example.

Package: libexample0
Section: libs
Architecture: any
Multi-Arch: same
Pre-Depends: ${misc:Pre-Depends}
Depends: ${misc:Depends}, ${shlibs:Depends}
Description: library package of example command
 This package contains the shared library.

Package: libexample-dev
Section: libdevel
Architecture: any
Multi-Arch: same
Depends: libexample0 (= ${binary:Version}), ${misc:Depends}
Description: developmant package of example command
 This package contains the development files.
~/ws_multi/example-0.1$ vim debian/copyright
:
~/ws_multi/example-0.1$ debchange
:
```

PACKAGE.installを記述していく。何を記述すればいいか分からなければ一度`debuild`してみて(多分失敗するが)、debian/tmp/の中身を選り分けていけばいいだろう。注意したいのはlibexample.so.0とlibexample.so.0.1はlibexample0パッケージの物だがlibexample.soはlibexample-devパッケージの物だということ。

debian/libexample0.symbolsはひとまずそのまま置いておく。

```bash
~/ws_multi/example-0.1$ cat >debian/example.install <<EOF
> usr/bin/*
> usr/share/man/*
> EOF
~/ws_multi/example-0.1$ cat >debian/libexample0.install <<EOF
> usr/lib/*/*.so.*
> EOF
~/ws_multi/example-0.1$ cat
> usr/include/*
> usr/lib/*/*.so
> EOF
```

`debuild`を実行する。分かりづらいがlintian以外の部分で警告を吐いている。

```
~/ws_multi/example-0.1$ debuild
:
dpkg-gensymbols: warning: new libraries appeared in the symbols file: libexample.so.0
dpkg-gensymbols: warning: debian/libexample0/DEBIAN/symbols doesn't match completely debian/libexample0.symbols
--- debian/libexample0.symbols (libexample0_0.1_amd64)
+++ dpkg-gensymbols5H1eKZ       2022-08-03 17:34:06.747563164 +0900
@@ -0,0 +1,3 @@
+libexample.so.0 libexample0 #MINVER#
+ _Z7examplev@Base 0.1
+ _ZNKSt5ctypeIcE8do_widenEc@Base 0.1
   dh_shlibdeps
   dh_installdeb
   dh_gencontrol
   dh_md5sums
   dh_builddeb
:
```

この生成されたsymbolsファイルをdebian/libexample0.symbolsに使うそうだ。コピーしてもう一度`debuild`。

[A.2. debian/package.symbolsの管理 - Debian メンテナー用ガイド](https://www.debian.org/doc/manuals/maint-guide/advanced.ja.html#librarysymbols)

```bash
~/ws_multi/example-0.1$ cp debian/libexample0/DEBIAN/symbols debian/libexample0.symbols
~/ws_multi/example-0.1$ debuild
:
```

警告を吐かなくなった。`debuild -- clean`して全体を見ておこう。

```bash
~/ws_multi/example-0.1$ tree ..
..
├── example-0.1
│     ├── CMakeLists.txt
│     ├── debian
│     │     ├── changelog
│     │     ├── control
│     │     ├── copyright
│     │     ├── example.install
│     │     ├── libexample-dev.install
│     │     ├── libexample0.install
│     │     ├── libexample0.symbols
│     │     ├── rules
│     │     └── source
│     │            └── format
│     ├── include
│     │     ├── CMakeLists.txt
│     │     └── example.h
│     ├── lib
│     │     ├── CMakeLists.txt
│     │     └── libexample.cpp
│     ├── man
│     │     ├── CMakeLists.txt
│     │     └── example.1
│     └── src
│            ├── CMakeLists.txt
│            └── example.cpp
├── example-dbgsym_0.1_amd64.ddeb
├── example_0.1.dsc
├── example_0.1.tar.xz
├── example_0.1_amd64.build
├── example_0.1_amd64.buildinfo
├── example_0.1_amd64.changes
├── example_0.1_amd64.deb
├── libexample-dev_0.1_amd64.deb
├── libexample0-dbgsym_0.1_amd64.ddeb
└── libexample0_0.1_amd64.deb
```

# その他の例
以下にはより多くのユースケースをカバーした例がある(quiltフォーマットだが)。
[第8章その他の例 - Debian メンテナー用ガイド](https://www.debian.org/doc/manuals/debmake-doc/ch08.ja.html)

# Tips
## debmakeの-bオプションタイプ一覧
書式は`-b "package[:type],..."`でそもそもlib*なりlib*-devなり*-docなりのpackage引数からtypeは決定出来るのですが一応。

| Type    | Arch  | Multi-Arch | Description                                |
| ------- | ----- | ---------- | ------------------------------------------ |
| bin     | any   | foreign    | (C/C++による)ELFバイナリコード             |
| lib     | any   | same       | ライブラリ                                 |
| dev     | any   | same       | 開発用ライブラリ(ヘッダや静的ライブラリ等) |
| doc     | all   | foreign    | ドキュメント                               |
| data    | all   | foreign    | データ(フォントや画像等)                   |
| sh      | all   | foreign    | シェルスクリプト                           |
| perl    | all   | foreign    | Perlスクリプト                             |
| python3 | all   | foreign    | Python3スクリプト                          |
| ruby    | all   | foreign    | Rubyスクリプト                             |
| nodejs  | all   | foreign    | Node.jsスクリプト                          |

## ライブラリファイル名の種類
ライブラリファイルは更新時の都合もあってか概ねこの形態になっている。

| Name       | Example     | Package  | Description                           |
| ---------- | ----------- | -------- | ------------------------------------- |
| realname   | lib*.so.0.1 | lib*0    | 共有ライブラリの実体                  |
| soname     | lib*.so.0   | lib*0    | 互換性のためのrealnameへのsymlink     |
| linkername | lib*.so     | lib*-dev | コンパイラが要求するsonameへのsymlink |

## *.orig.tar.gzの挙動
プロジェクトディレクトリは`package-version`の形で、アーカイブファイルは`package_version.orig.tar.gz`の形で保存する。アーカイブファイルが異なる命名の場合、debmakeは正規の命名のsymlinkを作成する。

```
$ wget http://ftp.gnu.org/gnu/gnujump/gnujump-1.0.8.tar.gz
$ tar -xf gnujump-1.0.8.tar.gz
$ cd gnujump-1.0.8
$ debmake
:
$ ls -l ../
合計 2456
drwxr-xr-x 9 liqsuq liqsuq    4096  7月 27 10:17 gnujump-1.0.8
-rw-rw-r-- 1 liqsuq liqsuq 2508641  7月 25  2012 gnujump-1.0.8.tar.gz
lrwxrwxrwx 1 liqsuq liqsuq      20  7月 27 10:23 gnujump_1.0.8.orig.tar.gz -> gnujump-1.0.8.tar.gz
```

## テンプレートファイル生成を制御する
`debmake`は`-x`オプションでテンプレートファイルの詳細さを指定出来る。デフォルトは多分1。0はDebianポリシーに従わずに`dpkg-buildpackage`が通る最低限。3以降はテンプレートファイルが多すぎて使いづらいがパッケージ作り込みの当たりをつけるには便利かも。

例えばdebian/copyrightに使用するライセンスの例は`-x4`オプションでdebian/license-examples/以下に生成される。

## バイナリのインストール先について
debパッケージングの際のバイナリのインストール先は`/usr/bin/`を推奨される。一方で一般的OSSでのインストール先は`/usr/local/bin/`だ。以下には「`/usr/bin/`はパッケージ管理されたバイナリを格納する」と書いてあり、セルフビルドのOSSからパッケージ管理システムに組み込む時の処理と言える。

- [「/bin」「/usr/bin」「/usr/local/bin」ディレクトリの使い分け | LPI-Japan](https://linuc.org/study/knowledge/544/)

## debchange
Ubuntuでnativeフォーマットの場合、`debchange`で変更ログを追加したらバージョンが「0.1」->「0.2」の様になってくれるのが期待だが、残念ながら自動でそうなってくれるオプションは存在しない模様。`debchange -R`を実行すると「0.1build1」となるエントリが生成されるのでそれを「0.2」に直すのが妥当か。

## help2man
manページに使われているroff形式は最早昨今では書くのが手間過ぎるのでhelp2manなり他のビルドツールに頼った方が良い。一応、手で書く人のためにroff形式で書いたファイルを整形して表示するためのコマンドを残しておく。

```
$ cat test.1 | groff -Tutf8 -mandoc -mja | less -s
```

# まとめ
以上のようにソースパッケージからのパッケージングは`dpkg-dev --build`を使った方法よりもツール群をフルに活用出来る。また、ツール群はdebian/以下にファイルを集約することで開発領域を分離し、ソースの変更がしやすい作りになってる。


# 参考
- [Debianパッケージ構築のメモ - walf443's blog](https://walf443.hatenablog.com/entry/20090616/1245111017)
- [Debian 開発者向けマニュアル](https://www.debian.org/doc/devel-manuals)
- [Debian メンテナー用ガイド](https://www.debian.org/doc/manuals/debmake-doc/debmake-doc.ja.pdf)
- [Debian 新メンテナーガイド](https://www.debian.org/doc/manuals/maint-guide/maint-guide.ja.pdf)
- [Debian パッケージングチュートリアル](https://www.debian.org/doc/manuals/packaging-tutorial/packaging-tutorial.ja.pdf)

※文書中にも書かれているが、新メンテナーガイドよりもメンテナー用ガイドの方が新しいことに注意。