Table of Contents
pkgsrc の基盤は、Makefile の小さな断片がたくさん集まってできています。 それぞれの断片に、適切なインターフェースを定義することが必要です。 本章では、そのようなインターフェースの何たるかを説明します。
pkgsrc の基盤において変数が定義されている場合、 変数が定義されている場所や定義の方法自体が、 その変数の使用目的について多くを語っています。 また、変数を定義しているファイルの冒頭のコメントや、 この手引きに、さらなる資料があることもあります。
特別なファイルとして、
mk/defaults/mk.conf
があります。このファイルには、
利用者が定義する変数がすべて書かれています。
これらの変数のなかには ?=
演算子を使って定義されているものもありますが、
そうでないものは、何かを定義すると “yes” を意味することになるため、
定義されていません。これらの変数はすべて、
pkgsrc 利用者が MAKECONF
ファイルで定義して上書きすることができます。
このファイル以外では、以下のようなならわしとなっています。
?=
演算子を使って定義されている変数は、
個々のパッケージで上書きすることができます。
また、=
演算子を使って定義されている変数は、
実行時に読み出し専用で使うことができます。
変数名が下線で始まる変数は、 pkgsrc の基盤以外からは一切読み書きできません。 これらは、特記のない限り、変更してもかまいません。
以上のならわしは、現在のところ、 pkgsrc の基盤全体に一貫して適用されているわけではありません。
リストを含む変数はすべて、標準状態では空になっているものです。
このならわしに従わない変数は、
USE_LANGUAGES
と
DISTFILES
の二つです。この二変数は、
パッケージの Makefile
(その他、ここからインクルードされるファイル) において、
+=
演算子を使って単純に変更することができません。
あらかじめ値が設定されているかどうかや、
何が設定されているかがまったくわからないからです。
DISTFILES
については、
パッケージ側で標準の値が“わかっている”ので、
以下の例のように定義するだけですみます。
DISTFILES= ${DISTNAME}${EXTRACT_SUFX} additional-files.tar.gz
このような標準の値を使っているために、
同じ値が多くのパッケージの Makefile に現れます。
USE_LANGUAGES
についても同様ですが、
こちらは、標準の値 (“c
”)
が非常に短いために目立ちません。
とはいえ、多くのファイルにこの値が書かれています。
変数の評価は、変数が使われる文脈によって、 読み込み時におこなわれる場合と、実行時におこなわれる場合があります。 変数が読み込み時に評価されるのは、以下のような文脈においてです。
:=
および !=
演算子の右辺
.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
になります。三つ目の段落では、
-Wall
を
CFLAGS
に付け加えていますが、この追加が
CONFIGURE_ARGS
には反映されません。
実際のコードではたいてい、
この三つの段落が完全に無関係のファイルに現れます。
バグや (ほとんどは文書化されていない)
方針への違反を検出するために、
変数の定義や使い方を制限する方法はたくさんあります。詳細は、
pkglint
の開発者向けドキュメンテーションをご覧ください。
ほとんどの .mk
ファイルは、
以下の二種類のいずれかに分類されます。
一つのファイルが複数の種類の性質を持つと、
見つけにくいバグの原因となることがしばしばあるので、そういうことは避けるようにします。
伝統的な命令型プログラミング言語の言葉で説明すると、
いくつかの .mk
ファイルはプロシージャーということになります。
プロシージャーは入力引数をとり、—インクルードされた後に—
出力引数を返します。Makefile
内の変数はすべて大域的なスコープをもつため、
すでに別の意味で使われている引数名を使わないよう注意する必要があります。
たとえば、PKGNAME
は、引数名としては不適切なものです。
プロシージャーは、プリプロセッシングの際に完全に評価されます。
このため、プロシージャーを呼ぶときには、
入力引数はすべて完全に解決可能である必要があります。たとえば、
CONFIGURE_ARGS
は、たいていは、
プロシージャーを呼んだ後にテキストが追加されることから、
変数の一部しかプロシージャーに渡されないことになるので、
決して入力引数として使ってはいけません。
また、他の変数から導かれる値への参照は、
プロシージャーの呼び出しの後に更新されます。
プロシージャーは、その出力引数を、 プリプロセッシングディレクティブ内で使うものとして、または、 実行時のみに利用可能なものとして、いずれかを宣言することができます。 後者は、他の実行時変数への参照を含む変数用です。
プロシージャーは、複数の呼び出しが可能なように書くものです。 つまり、ファイルに多重インクルードの防護策を施してはいけません。
プロシージャーの例としては、
mk/bsd.options.mk
や
mk/buildlink3/bsd.builtin.mk
があります。
引数が読み込み時に評価されることを表すため、
引数は :=
演算子を使って与えます。
この演算子は、この目的のためだけに使うようにします。
パッケージの Makefile
は、通常、
一連の変数の定義からできており、最後の行で
../../mk/bsd.pkg.mk
ファイルをインクルードしています。
コンパイラーや X11 の実装の種類など、
特定の機能の有無を問い合わせる必要がある場合は、
最後のインクルードの前に、これ以外の各種
*.mk
ファイルをインクルードすることができます。
.if
や
.for
のようなプリプロセッサーディレクティブを多用しているので、
ファイルを読み込む場所と順序が問題になります。
本節では、各種ファイルをどこで読み込むか、 および、その順序の理由を説明します。
bsd.prefs.mk
で最初におこなわれることは、
OPSYS
, OS_VERSION
,
MACHINE_ARCH
など、基本的な変数をいくつか定義することです。
次に、MAKECONF
(通常は mk.conf
)
で指定されているファイルから、ユーザーによる設定が読み込まれます。
それから、ユーザーによって上書きされたもの以外の変数が
mk/defaults/mk.conf
から読み込まれます。
ユーザーによる設定の後に、 システムの設定とプラットフォームの設定が読み込まれます。 これらはユーザーによる設定を上書きすることがあります。
その後、ツールの定義が読み込まれます。 この時点では、ツールのラッパーはまだ影響しません。 ラッパーは、パッケージを構築する時に影響をおよぼします。 このため、ツール名を直接使うのではなく、適切な変数を使う必要があります。
最後に、ラッパーおよびパッケージシステムのフレーバーから、 必須の変数がいくつか、 パッケージ構築過程の初期段階でキャッシュされていた変数とともに、 読み込まれます。
最初に、bsd.prefs.mk
が読み込まれます。
次に、パッケージ側で定義されない変数の標準状態の値を定義している、
各種の *-vars.mk
ファイルが読み込まれます。
この変数は、後になって、無関連のファイルで使われる可能性もあります。
その次に、bsd.pkg.error.mk
ファイルから
error-check
ターゲットが提供されます。
このターゲットは、
DELAYED_ERROR_MSG
または
DELAYED_WARNING_MSG
を使う他のターゲットすべてに対して、特別な依存性として追加されます。
その後、hacks.mk
から、
パッケージ固有のハックがインクルードされます。
そして、他の各種ファイルのインクルードが続きます。 この段階でインクルードされるファイルのほとんどは、 インクルードされる順序に関して依存性を持ちませんが、 なかには依存性を持つものもあります。
ここで、PKG_FAIL_REASON
と
PKG_SKIP_REASON
を検査するコードが実行されます。
ここまでの段階でインクルードされるすべてのファイルに対しては、
この両変数の使用が制限されます。
これより後にインクルードされるファイルでは、黙って無視されます。
それから、目的のターゲットに対応するファイルが、 この後で実行される順序でインクルードされますが、 実際の順序は問題とはならないはずです。
最後に、何ら興味深い変数を設定するものではなく、 実行される make ターゲットを定義するだけのファイルが、 さらにいくつかインクルードされます。