Chapter 24. pkgsrc の基盤の設計

Table of Contents

24.1. 変数定義の意図するもの
24.2. 問題を未然に防ぐ
24.3. 変数の評価
24.3.1. 読み込み時
24.3.2. 実行時
24.4. 変数の仕様を定める方法は?
24.5. Makefile の断片のインターフェースを設計する
24.5.1. 引数を伴うプロシージャー
24.5.2. 引数に応じたアクション
24.6. ファイルが読み込まれる順序
24.6.1. bsd.prefs.mk での順序
24.6.2. bsd.pkg.mk での順序

pkgsrc の基盤は、Makefile の小さな断片がたくさん集まってできています。 それぞれの断片に、適切なインターフェースを定義することが必要です。 本章では、そのようなインターフェースの何たるかを説明します。

24.1. 変数定義の意図するもの

pkgsrc の基盤において変数が定義されている場合、 変数が定義されている場所や定義の方法自体が、 その変数の使用目的について多くを語っています。 また、変数を定義しているファイルの冒頭のコメントや、 この手引きに、さらなる資料があることもあります。

特別なファイルとして、 mk/defaults/mk.conf があります。このファイルには、 利用者が定義する変数がすべて書かれています。 これらの変数のなかには ?= 演算子を使って定義されているものもありますが、 そうでないものは、何かを定義すると yes を意味することになるため、 定義されていません。これらの変数はすべて、 pkgsrc 利用者が MAKECONF ファイルで定義して上書きすることができます。

このファイル以外では、以下のようなならわしとなっています。 ?= 演算子を使って定義されている変数は、 個々のパッケージで上書きすることができます。

また、= 演算子を使って定義されている変数は、 実行時に読み出し専用で使うことができます。

変数名が下線で始まる変数は、 pkgsrc の基盤以外からは一切読み書きできません。 これらは、特記のない限り、変更してもかまいません。

Note

以上のならわしは、現在のところ、 pkgsrc の基盤全体に一貫して適用されているわけではありません。

24.2. 問題を未然に防ぐ

リストを含む変数はすべて、標準状態では空になっているものです。 このならわしに従わない変数は、 USE_LANGUAGESDISTFILES の二つです。この二変数は、 パッケージの Makefile (その他、ここからインクルードされるファイル) において、 += 演算子を使って単純に変更することができません。 あらかじめ値が設定されているかどうかや、 何が設定されているかがまったくわからないからです。 DISTFILES については、 パッケージ側で標準の値がわかっているので、 以下の例のように定義するだけですみます。

DISTFILES=      ${DISTNAME}${EXTRACT_SUFX} additional-files.tar.gz

このような標準の値を使っているために、 同じ値が多くのパッケージの Makefile に現れます。 USE_LANGUAGES についても同様ですが、 こちらは、標準の値 (c) が非常に短いために目立ちません。 とはいえ、多くのファイルにこの値が書かれています。

24.3. 変数の評価

24.3.1. 読み込み時

変数の評価は、変数が使われる文脈によって、 読み込み時におこなわれる場合と、実行時におこなわれる場合があります。 変数が読み込み時に評価されるのは、以下のような文脈においてです。

  • := および != 演算子の右辺

  • .if.for のような make ディレクティブ

  • (訳註: make(1) の) 依存性を記述した行。

特別な例外として、.for ループの反復変数があります。 これは、どの文脈で使われるかにかかわらず、 インライン展開されます。

変数の値は読み込みによって変わる可能性があるので、 誤って評価することのないよう注意する必要があります。 読み込み時に評価してはいけない変数の典型例は、 DEPENDS および CONFIGURE_ARGS です。 評価の結果何が起きるかをわかりやすくするため、 以下の例を見てください。

CONFIGURE_ARGS=         # none
CFLAGS=                 -O
CONFIGURE_ARGS+=        CFLAGS=${CFLAGS:Q}

CONFIGURE_ARGS:=        ${CONFIGURE_ARGS}

CFLAGS+=                -Wall
	

このコードからわかることは、:= 演算子を使うと、 容易に、予期しない結果を生むということです。 最初の段落はごくふつうのコードです。二つ目の段落では CONFIGURE_ARGS を評価しており、この結果、 CFLAGS=-O になります。三つ目の段落では、 -WallCFLAGS に付け加えていますが、この追加が CONFIGURE_ARGS には反映されません。 実際のコードではたいてい、 この三つの段落が完全に無関係のファイルに現れます。

24.3.2. 実行時

ファイルがすべて読み込まれた後は、変数の値は一切変更することができません。 シェルコマンド内で使われる変数は、 この時点で展開されます。

24.4. 変数の仕様を定める方法は?

バグや (ほとんどは文書化されていない) 方針への違反を検出するために、 変数の定義や使い方を制限する方法はたくさんあります。詳細は、 pkglint の開発者向けドキュメンテーションをご覧ください。

24.5. Makefile の断片のインターフェースを設計する

ほとんどの .mk ファイルは、 以下の二種類のいずれかに分類されます。 一つのファイルが複数の種類の性質を持つと、 見つけにくいバグの原因となることがしばしばあるので、そういうことは避けるようにします。

24.5.1. 引数を伴うプロシージャー

伝統的な命令型プログラミング言語の言葉で説明すると、 いくつかの .mk ファイルはプロシージャーということになります。 プロシージャーは入力引数をとり、—インクルードされた後に— 出力引数を返します。Makefile 内の変数はすべて大域的なスコープをもつため、 すでに別の意味で使われている引数名を使わないよう注意する必要があります。 たとえば、PKGNAME は、引数名としては不適切なものです。

プロシージャーは、プリプロセッシングの際に完全に評価されます。 このため、プロシージャーを呼ぶときには、 入力引数はすべて完全に解決可能である必要があります。たとえば、 CONFIGURE_ARGS は、たいていは、 プロシージャーを呼んだ後にテキストが追加されることから、 変数の一部しかプロシージャーに渡されないことになるので、 決して入力引数として使ってはいけません。 また、他の変数から導かれる値への参照は、 プロシージャーの呼び出しの後に更新されます。

プロシージャーは、その出力引数を、 プリプロセッシングディレクティブ内で使うものとして、または、 実行時のみに利用可能なものとして、いずれかを宣言することができます。 後者は、他の実行時変数への参照を含む変数用です。

プロシージャーは、複数の呼び出しが可能なように書くものです。 つまり、ファイルに多重インクルードの防護策を施してはいけません。

プロシージャーの例としては、 mk/bsd.options.mkmk/buildlink3/bsd.builtin.mk があります。 引数が読み込み時に評価されることを表すため、 引数は := 演算子を使って与えます。 この演算子は、この目的のためだけに使うようにします。

24.5.2. 引数に応じたアクション

アクションファイルは、入力引数をとり、 実行時変数を定義することができます。 読み込み時変数を定義することはできません。 アクションファイルには pkgsrc の基盤によって暗黙のうちにインクルードされるものもありますが、 そのようなもの以外は明示的にインクルードする必要があります。

アクションファイルの例としては、 mk/subst.mk があります。

24.6. ファイルが読み込まれる順序

パッケージの Makefile は、通常、 一連の変数の定義からできており、最後の行で ../../mk/bsd.pkg.mk ファイルをインクルードしています。 コンパイラーや X11 の実装の種類など、 特定の機能の有無を問い合わせる必要がある場合は、 最後のインクルードの前に、これ以外の各種 *.mk ファイルをインクルードすることができます。 .if.for のようなプリプロセッサーディレクティブを多用しているので、 ファイルを読み込む場所と順序が問題になります。

本節では、各種ファイルをどこで読み込むか、 および、その順序の理由を説明します。

24.6.1. bsd.prefs.mk での順序

bsd.prefs.mk で最初におこなわれることは、 OPSYS, OS_VERSION, MACHINE_ARCH など、基本的な変数をいくつか定義することです。

次に、MAKECONF (通常は mk.conf) で指定されているファイルから、ユーザーによる設定が読み込まれます。 それから、ユーザーによって上書きされたもの以外の変数が mk/defaults/mk.conf から読み込まれます。

ユーザーによる設定の後に、 システムの設定とプラットフォームの設定が読み込まれます。 これらはユーザーによる設定を上書きすることがあります。

その後、ツールの定義が読み込まれます。 この時点では、ツールのラッパーはまだ影響しません。 ラッパーは、パッケージを構築する時に影響をおよぼします。 このため、ツール名を直接使うのではなく、適切な変数を使う必要があります。

最後に、ラッパーおよびパッケージシステムのフレーバーから、 必須の変数がいくつか、 パッケージ構築過程の初期段階でキャッシュされていた変数とともに、 読み込まれます。

24.6.2. bsd.pkg.mk での順序

最初に、bsd.prefs.mk が読み込まれます。

次に、パッケージ側で定義されない変数の標準状態の値を定義している、 各種の *-vars.mk ファイルが読み込まれます。 この変数は、後になって、無関連のファイルで使われる可能性もあります。

その次に、bsd.pkg.error.mk ファイルから error-check ターゲットが提供されます。 このターゲットは、 DELAYED_ERROR_MSG または DELAYED_WARNING_MSG を使う他のターゲットすべてに対して、特別な依存性として追加されます。

その後、hacks.mk から、 パッケージ固有のハックがインクルードされます。

そして、他の各種ファイルのインクルードが続きます。 この段階でインクルードされるファイルのほとんどは、 インクルードされる順序に関して依存性を持ちませんが、 なかには依存性を持つものもあります。

ここで、PKG_FAIL_REASONPKG_SKIP_REASON を検査するコードが実行されます。 ここまでの段階でインクルードされるすべてのファイルに対しては、 この両変数の使用が制限されます。 これより後にインクルードされるファイルでは、黙って無視されます。

それから、目的のターゲットに対応するファイルが、 この後で実行される順序でインクルードされますが、 実際の順序は問題とはならないはずです。

最後に、何ら興味深い変数を設定するものではなく、 実行される make ターゲットを定義するだけのファイルが、 さらにいくつかインクルードされます。