FreeBSD ports を作る際の調査ノウハウ

# はじめに
ports を作ろうと思ってテンプレやハンドブックを参考にして作業していると、パターンにはまらないケースや、特殊な振る舞いをするケースで、どうやって追跡すべきか、上手く差し込むにはどうすればいいか、悩ましいケースがあります。

例えば ports からインストールする（`make install`）場合、おおよそ以下の順番で実行されるのが知られています。

```
make fetch
make extract
make patch
make build
make install
```

また、各ターゲットのプレフィックスとして `pre-` や `post-` （`pre-fetch` や `post-patch` など）を入れることで、自分がやらせたいターゲットの前後に、実行してもらいたいことを仕込むことが可能です。
さらには `do-` プレフィックスを指定（上書く）することで ports デフォルトの挙動すらもコントロール可能となっています。
この辺りの順番や制御は下記の通りとなります。

```
make fetch
 +- make pre-fetch
 +- make do-fetch
 +- make post-fetch
make extract
 +- make pre-extract
 +- make do-extract
 +- make post-extract
make patch
 +- make pre-patch
 +- make do-patch
 +- make post-patch
make configure
 +- make pre-configure
 +- make do-configure
 +- make post-configure
make build
 +- make pre-build
 +- make do-build
 +- make post-fetch
make install
 +- make pre-install
 +- make do-install
 +- make post-install
```

そもそもそのターゲットを無効にしたいケース（`NO_BUILD`/`NO_INSTALL`/`NO_TEST`、各々 `make build`、`make install`、`make test` が無効になる）や、明示的にターゲットを有効にしたいケース（`HAS_CONFIGURE`/`GNU_CONFIGURE` いずれも `make configure` が有効になる）など、ports 毎に千差万別です。

実際にはもっと細かいところに、色々なフックが発生しています。完全にリストアップするにはあまりにもツライので調査ポイントでもメモしておきます。

# ターゲットステージ

先に述べたようによく知られたターゲットは
- `all`
- `fetch`
- `extract`
- `patch`
- `configure`
- `build`
- `install`
になるかと思います。これに
- `config`/`showconfig`/`rmconfig`
- `package`/`repackage`
- `test`
- `clean`
- `deinstall`/`reinstall`
- `makesum`/`makepatch`
など、いくつか知っておくべきターゲットが加わることになります。

上記のターゲットのうち、ports のビルドで実行される一連のターゲットについては `_TARGETS_STAGES` という変数で定義されます。もちろん `bsd.port.mk` 中に定義される変数で、上書きを想定していません。適当な ports ディレクトリで `make -V_TARGETS_STAGES` を実行するとわかるのですが、`SANITY PKG FETCH EXTRACT PATCH CONFIGURE BUILD INSTALL TEST PACKAGE STAGE` というような内容になっています。

上記変数の内容に基づいて、各ステージでは `_ステージ名_SEQ` 変数で細かく順序が設定され、`_ステージ名_DEP` で依存が定義されます。特に `_SEQ` で終る変数は `優先順位:ターゲット` と定義され、後から追加されても順番に実行されるよう制御されます。

たとえばＧｏ言語なアプリの場合、Ｇｏ特有のフェッチ `go mod download` の実行が行われます。

```
make -V_FETCH_SEQ
make -V_FETCH_REAL_SEQ
```

極めて特殊なタイミングで差し込みたい場合は、このフローに合わせるように仕込みを入れることになります。

# make コマンドによるデバッグ

ports の場合、様々な簡略化表現を実現するために、表面上はいくらかシンプルになっています。が、その結果、実装は極めて複雑になっています。先のターゲットステージについても、概略の理解は可能かも知れませんが、実際に何が起こって失敗しているのか調査するのは大変です。そこで `make` コマンドのデバッグオプション（`-dＸ`／`Ｘ` は別途機能別オプション）の登場です。

特に `-dl` オプションは bsd.port.mk などを含む Makefile 中の `@` で隠蔽されているコマンドの実行が、表示されるようになります。

```
make -dl
```

あるいは `make -de` でしょうか。こちらは実行に失敗したコマンドのみを表示します。
ビルドに失敗した場合、何のコマンドを実行して失敗したのか見たい場合、まずは　`make -de` を確認し、全体のフローで何が起きているのかを `make -dl` で確認すると、問題を掌握しやすくなると思います。

また `make -dx` の場合、呼び出されるシェルコマンドが `-x` オプション付で呼び出されるようになるため、特にシェルスクリプト中で実行される内容が表示されるようになります。もちろんコマンド呼び出しの度に…なので、`make -dl` と区別付かないこともあります。

# よくある質問とその答え

## Ｑ．あんまり取りまとまってないけど何で書いたの？

Ａ．ＭａｖｅｎというかＧｒａｄｌｅが悪いんや。こいつらＧｏ言語のようにプリフェッチしまくるのは１００歩譲って許すとしても、うまくキャッシュしてくれないから、どうすりゃ良いんだ…と調べまくった。

## Ｑ．それで解決したのですか？

Ａ．続きはウェブで！

# 参考文献

- [Mk/bsd.port.mk](https://cgit.freebsd.org/ports/tree/Mk/bsd.port.mk)
- [make(1)](https://man.freebsd.org/cgi/man.cgi?make(1))
- [FreeBSD port 作成者のためのハンドブック](https://docs.freebsd.org/ja/books/porters-handbook/)
- [FreeBSD Porter's Handbook](https://docs.freebsd.org/en/books/porters-handbook/)
- [ports の Makefile のテンプレート](https://cgit.freebsd.org/ports/tree/Templates/Makefile)