ルールではコマンドはシェルコマンドで実行していく一行一行から成り立っています。コマンド行ではそれぞれの行をタブから始めなければなりません。ただし、最初のコマンド行はターゲットと依存関係行の最後にセミコロンをつけて、その直後に続ける事もできます。何もない行(Blank lines)やコメントだけの行がコマンド行の間にあってもよく、その場合はその部分は無視します。(ただし、気をつけておいて下さい。真に"空白(blank)"の行(タブで始まっている行)である場合は何もない(blank)行ではありません!そういう行は空のコマンドになります。これについては空のコマンドの利用の項を参照して下さい。)
ユーザーはそれぞれに異なったシェルプログラムを使っていて、その種類は数多くありますが、makefileが他の方法を指定しない限りはmakefileのコマンドは常に`/bin/sh'で処理します。コマンド実行の項を見て下さい。
コマンド行でコメントを使えるかどうか、その構文はどんなものか、という事は使用するシェルによって決まります。`/bin/sh'がシェルの時は、コメントは`#'から行末までになります。`#'は行の始めじゃなくても構いません。また、`#'の前のテキストはコメントにはなりません。
make
は普通コマンドを実行する前に、実行するコマンドを画面に表示します。あなたが入力したコマンドを表示することからこの機能の事をエコー(echoing=反響)といいます。
`@'ではじまる行はエコーせず、また`@'はシェルでコマンドを処理する前に除外されます。この機能の典型的な使い方として、makefileの処理過程を示すためのecho
コマンドのように、出力のみが目的のコマンドを対象として使います。
@echo 配布ファイルの作成について
make
に`-n'フラグか`--just-print'フラグを与えると実行する事なく処理内容を全てエコーします。これについてはオプション要約の項を参照して下さい。この場合、というよりも唯一この場合だけは`@'で始まる行も表示します。このフラグはmake
が必要とするコマンドを実際に実行せずに知るのに便利です。
`-s'フラグか`--silent'フラグを使えば全部の行に`@'をつけたような動作をし、全くエコーしなくなります。makefileに特別なターゲットの.SILENT
を依存関係なしで記述するのも同じ効果になります(特別なビルトイン・ターゲット名の項を参照)。さらに柔軟な機能を持った`@'があるので本質的には.SILENT
は廃れた機能です。
ターゲットを更新する際、実行するコマンドは各行それぞれで新しいサブシェルを使って処理されます。(実際のmake
の内部実装ではもっと処理を簡略化しています。)
重要: このことはcd
のようにローカル変数をセットするシェルコマンドを使ってもそれ以後のコマンド行に影響しない事を示唆しています。(2) 次のコマンドにcd
の結果を反映させるには、セミコロンを使って一つの行に二つのコマンドを書けばmake
がそれを一つのコマンドであると判断して二つ続けて一つのシェルで処理してくれます。以下がその例です。
foo : bar/lose cd bar; gobble lose > ../foo
一つのシェルコマンドを複数の行に分けて記述したければ各分割行の最後以外の行末にバックスラッシュをつければそうできます。この複数にわたる行ではシェルに渡される前にバックスラッシュと改行(newline)が並ぶものは削除して、その結果としてできた一行をシェルに渡します。それゆえに以下のものは前述の例と全く同意です。
foo : bar/lose cd bar; \ gobble lose > ../foo
シェルとして呼び出すプログラムはSHELL
変数で指定でき、その指定をしなければデフォルトとして`/bin/sh'を使います。
MS-DOSではSHELL
をセットしなかった場合、(デフォルトで常にセットしてある)COMSPEC
変数の値を代わりにシェルプログラムとして呼び出します。
MS-DOS環境ではSHELL
変数をMakefileでセットしたときの動作が異なります。
標準的なシェルである`command.com'があまりにもバカげた機能に限られているためにmake
のユーザーの多くは代わりのシェルをインストールする傾向にあります。このためMS-DOSではmake
はSHELL
の値で指定したシェルがUnix形式かDOS形式かで動作を変えます。このおかげでSHELL
に`command.com'を指定しても理に適った機能性を提供します。
MS-DOS環境でSHELL
にUnix形式のシェルを指定した場合、さらにmake
はそのシェルを実際に探して存在するかを調べます。探して見つからないとSHELL
を指定している行を無視します。MS-DOS環境ではGNU make
はシェルを次に示す場所から検索します。
SHELL
の値で指定したのと寸分違わぬ場所。例えばmakefileで`SHELL = /bin/sh'と指示してあるのならmake
が探す場所はカレントドライブの`/bin'というディレクトリです。
PATH
変数にあるディレクトリ全部(探す順番は指定順に同じ)。
make
はそれぞれの試行ディレクトリで、まず第一に(上の例の`sh'のような)指示ファイルを探します。それで見つからなければ実行可能ファイルを見分けるものとしてよく知られた拡張子を指示ファイルに一つ付加してそれも探します。例えば`.exe',`.com', `.bat', `.btm', `.sh'などです。
試行した結果どれかが成功すれば見つかったシェルのフルパスをSHELL
の値としてセットします。また、試行作業を通して全く発見できなければSHELL
の値が変わる事はないため、変数指定行は事実上無視された事になります。以上のことから、make
を実行する環境にUNIX形式のシェルが実際にあれば、make
はUnix形式のシェル特有の機能だけをサポートすることになる、という結果になります。
このシェル用拡張サーチ機能という機能はMakefileでセットしたSHELL
だけに限られており、コマンドラインや環境でのセットではシェルのUNIXにある通りのフルパスをセットしなければならない事に気をつけておいてください。
PATH
変数に入れたディレクトリに例えば`sh.exe'がインストールしてあって、(UNIXのmakefileでするように)このまま`SHELL = /bin/sh'とMS-DOSのMakefileで書く場合にDOS環境特有の処理が行われます。
他の多くの変数と違ってSHELL
変数は環境からの指定を受け付けません。これは対話用のシェルプログラムとしてユーザーが選択したシェルを指定するために環境変数SHELL
があるからです。makefileの処理にユーザー指定のものが影響するのは
最悪です。これについては環境からの変数の項を見て下さい。ところがMS-DOSとMS-Windows上ではほとんどのユーザーがこの変数を指定しないので、環境変数SHELL
の値を利用します。このことからほとんどmake
で使うためだけにこの環境変数を設定できます。 MS-DOS環境ではSHELL
での設定がmake
に不適ならMAKESHELL
変数にmake
に使わせるシェルを指定することもでき、指定した場合SHELL
の値を上書きします。
GNU make
では複数のコマンドを一度に実行させることもできます。make
は一度に一つのコマンドを実行し、そのコマンドが終了するのを待って次のコマンドを実行するのが通常の動作ですが、make
呼び出し時に`-j'オプションか`--jobs'オプションを使えばたくさんのコマンドを同時に実行するようになります。
MS-DOSではマルチプロセスをサポートしていないため、`-j'オプションは無効になります。
`-j'に整数を続ければそれがジョブスロットの数、すなわち一度に実行するコマンドの数になります。 `-j'オプションの後に整数らしきものを全くつけなければ、ジョブスロットの数に制限されなくなります。ジョブスロットのデフォルトの数は1で、これは直列実行(一度に一つしか実行しない)ということになります。
複数コマンドの同時実行のひとつの欠点は、複数のコマンドが同時に出力をすればその全ての出力を受けることになり、その結果別々のコマンドが出力したメッセージがそれぞれバラバラになってしまう事です。
もう一つの欠点は二つのプロセスが同じデバイスから入力を受けることはできないため、make
は一度にたった一つのコマンドだけでもターミナルからの入力をちゃんと受けさせたいので実行している一つを除き全てのコマンドの標準入力ストリームを無効にしてしまいます。この結果、標準入力読み込みという試行作業は、マルチプロセスだと大抵ほとんどの子プロセスで(`パイプの欠陥(Broken pipe)'シグナルという)致命的(fatal)エラーを出すことになるのです。
どのコマンドが有効な標準入力ストリーム(ターミナルからのもの、またはmake
でリダイレクト(置き換え)するようにあなたが指定した標準入力)を使っているかは予想できないことです。内部では一番最初のコマンド実行は常に最初に標準入力ストリームを取得し、それが終了した直後に開始したコマンドが次にそれを取得する…というようになるからです。
もしも、現状のものよりも良い方法を発見したならmake
の動作を変えるつもりです。まだ劣悪な動作をしている現在は、標準入力を使うコマンドは並列処理に頼らず、標準入力を使うコマンドでも全く通常に動作してくれる(デフォルトの)直列処理を使うべきです。
あるコマンドが(シグナルによる中断か、非ゼロのステータスを返したかで)失敗し、エラーになったコマンドを無視しない設定(コマンド内エラーの項を参照)であれば残されたコマンド行のうち同ターゲットの更新をおこなう行は無視されることになります。`-k'オプションか`--keep-going'オプションをつけていない場合(see section オプション要約の項を参照)はコマンドが失敗するとmake
の処理を中断します。
make
が複数の子プロセス実行中に(シグナルを含め)何らかの理由で終了する時は全部が終わるのを待ってから終了します。
システムの負荷が重い(大きい)場合、多分負荷が軽い(小さい)時よりもジョブ実行数を少なくしてほしいと思います。`-l'オプションをつければmake
はジョブ実行数の平均に基づいて一度に実行するジョブの数を制限してくれます。`-l'オプションと`--max-load'オプションには浮動小数を続けて使います。
例えば…
-l 2.5
とすれば、負荷平均が2.5を超えた時はmake
に一つもジョブを開始させません。`-l'オプションに数値をつけないものは一つ前に`-l'オプションで与えられた負荷制限を解除する効果があります。
make
がすでに一つ以上のジョブを実行していてこれから一つのジョブを開始させようとしている時は最も、現在の負荷平均のチェックが正確になります。具体的には
`-l'で与えた制限以上の時にmake
の処理を、負荷平均が制限以下になるか他のジョブが全部終わるまで待たせるようになります。
デフォルトでは負荷制限はありません。
make
は各シェルコマンドの終了後に戻り値(exist status)を調べます。コマンドが完全に成功したら次の行を新しいシェルで実行し、最後のコマンド行が終了すればルールの処理が完了した事になります。
エラーがあった(戻り値(exit status)がゼロ以外なった)場合make
は現在のルールの処理を諦めて、それから多分全てのルールでも諦めることになります。
ある種のコマンドは失敗しても問題にはなりません。例えばmkdir
コマンドを確実にディレクトリを存在させるために使う事ができるのですが、mkdir
を使ったときにすでにディレクトリが存在していた場合エラーを報告します。しかしあなたは、make
にこのエラーを無視して続けさせたいと思うはずです。
そういうとき、コマンド行の本文の初め(先頭のタブの直後)に`-'と書けばそのコマンド行でのエラーを無視させることができます。`-'はシェルにコマンドを渡して実行させる前に削除されます。
例えばこうします。
clean: -rm -f *.o
この場合rm
がファイルを削除できなくても先を続けさせるようになります。
`-i'フラグか`--ignore-errors'フラグをmake
につけると、全てのルールの全てのコマンドのエラーを無視するようになります。makefileで.IGNORE
という特別なターゲットを依存関係なしで書いたルールも同じ効果があります。`-'のほうが用途に富むのでこれらの機能は時代遅れのエラー無視手段です。
`-'か`-i'フラグでエラーを無視させると、make
は対象となったコマンドがエラーになった時に返り値のコード(exist status code)を出力してエラーが無視された事を報告する以外は成功したものと同然に処理します。
make
に無視するように命令していないエラーが起こる事は、現在のターゲットどころか、それに直接的または間接的に依存するいかなるターゲットも正確に更新されていない可能性がある事を示唆しています。そういうターゲットに対するコマンドは仮定条件が達成されていないために、もはやそれ以上実行されません。
こういう状態では普通、ゼロ以外のステータスが返されると直ちに中断します。ところが`-k'フラグか`--keep-going'フラグを指定すると中断してゼロ以外のステータスを返す前に、必要であればやりかけのターゲットの残りの依存関係を更新させます。例えば、あるオブジェクトファイルをコンパイルするときにエラーが発生してリンクが不可能だとわかっていても`make -k'なら他のオブジェクトをコンパイルし続けます。これについてはオプション要約の項を見て下さい。
通常は指定したターゲットを更新する事を目的だと仮定して動作するため、それが不可能だと分かるとmake
は直ちに失敗を報告するようにします。`-k'オプションは真の目的がプログラム作成作業での変更をできるだけ多くテストすることにあると命令し、次回コンパイルさせる時までに完全に問題を修正しておくのに独立したいくつかの問題を発見するのを助けます。Emacsのcompile
コマンドではこういう理由からデフォルトで`-k'フラグを渡します。
コマンドが失敗したのに少しでもターゲットファイルが変更されていたなら、そのファイルは劣化して使えなくなった事になります。完全に更新されていなくても、です。ファイルのタイムスタンプがもう新しいのだから次回のmake
の動作でそのファイルを更新しようとする事もなくなります。これはコマンドがシグナルで中断された時と全く同じです。これについてはmake
を邪魔するか中断させるの項を見て下さい。だからファイルを変更し始めた直後にコマンドが失敗した場合、ターゲットファイルを削除する事が一般的には正しい事であり、.DELETE_ON_ERROR
をターゲットにするとmake
はそう動作します。このことはほとんど毎回make
にやって欲しい事なのですが、これは歴史的な動作ではないため、互換性を維持するために明示的にリクエストしなければならない仕様になっています。
make
を邪魔するか中断させる
make
のコマンド実行中にやめさせるシグナル(合図; a fatal signal)を出すと、コマンドで更新することになっていたターゲットファイルは削除されます。ターゲットファイルの最終修正日がmake
が最初にチェックした時から変更されていた場合にこの削除作業が行われます。
ターゲットを削除するのは次回のmake
実行で削除された状態から新しくちゃんと作らせるのが目当てです。どうしてか? もしあなたがコンパイラ実行中に[Ctrl]+Cと入力し、もうその時は既に`foo.o'というオブジェクトファイルを操作し始めていたとします。すると[Ctrl]+Cがコンパイラの実行を中止し、`foo.c'というソースファイルより最終修正時刻が新しいのに不完全なファイルが残ってしまいます。しかしmake
も[Ctrl]+Cというシグナルを受け取るので不完全なファイルを削除してくれます。make
がもしもそうしなければmake
が次回作動した時`foo.o'は更新の必要がないと考えてしまい、リンカが一部欠落したオブジェクトファイルをリンクしようとし、その結果おかしなエラーメッセージを出すことになります。
.PRECIOUS
という特別なターゲットにターゲットファイルを依存させればそのターゲットファイルの削除を防ぐことが可能です。make
はターゲットを更新する前に.PRECIOUS
の依存関係に対象のターゲットがないかを調べ、そこからシグナル発生時にターゲットを削除すべきかを判断します。削除させない理由には、ターゲットを微小にしか更新しないため、とか、(中身によらず)修正時刻を記録するためだけにあるターゲットである、とか、別の類のトラブルを防ぐためにどんな時も存在していなければならないターゲットである、といったものがあります。
make
の再帰利用とはmake
をmakefileのコマンドとして使う事を指しています。このテクニックは大きなシステムを構成するのにそれより小さい様々なサブシステムのmakefileをその分割ファイルとして使う場合に役立ちます。例えば、`subdir'というサブディレクトリにmakefileがあり、そのディレクトリの親ディレクトリにあるmakefileでそのサブディレクトリでのmake
を実行させたいとすると、こういう風に書くことで実現できます。
subsystem: cd subdir && $(MAKE)
また、こうしても同じです(オプション要約の項を参照)。
subsystem: $(MAKE) -C subdir
この例をそのままコピーすればmake
コマンドの再帰呼び出しを使えますが、どう動くのか、なぜそう動くか、それにサブ(下位)のmake
とトップレベルのmake
がどう関連するのか、という事については知っておくべき事が数多くあります。
利便性からGNU make
ではCURDIR
という変数にカレント・ワーキング・ディレクトリ(現在の作業の中心になっているディレクトリ)にパス名をセットします。-C
を使うと元のものではなく新しいディレクトリのパスが有効になります。この値はmakefileの中でセットするのと同じ優先順位を持ちます(デフォルトでは環境変数CURDIR
はこの値を上書きしません)。この変数をセットしてもmake
の作業に影響がないことに注意しておいてください。
make
コマンドの再帰呼び出しでは`make'とコマンド名を明示せず、以下のようにMAKE
変数を常に使うべきです。
subsystem: cd subdir && $(MAKE)
この変数の値には現在作動中のmake
のファイル名が入っています。このファイル名が`/bin/make'というものなら、上のコマンドは`cd subdir && /bin/make'と解釈して実行します。トップレベルのmakefileで特別版のmake
を使っているなら再帰起動でも同じ特別版のものを実行してくれます。
特別な機能として、`-t' (`--touch'), `-n' (`--just-print'), `-q' (`--question')の各オプションはMAKE
変数をmakefileのコマンド内で使うと影響を違った効果になります。MAKE
変数を使うのと`+'という文字をコマンド行の初めに使うのは同じ効果があります。これについてはコマンドを実行する代わりに…の項を見て下さい。
前述の例で`make -t'というコマンドを使った場合を考えて下さい。(`-t'オプションは実際のコマンドの実行なくしてターゲットを更新させたという印をつけるもので、これについてはコマンドを実行する代わりに…の項に書かれています。) `-t'の一般定義に基づけば`make -t'コマンドを例で使うと`subsystem'というファイルを作成する以外は何もしない事になります。本当にして欲しいことは`cd subdir && make -t'を実行することなのに、このコマンドの実行を要求しても`-t'が何もコマンドを実行しないように命令してしまいます。
MAKE
変数がルールのコマンド行中にある時は常に、`-t'、`-n'、`-q'というフラグをその行に適用しない、という特別な機能が働くお陰で、して欲しい事をちゃんとやってくれるようになります。MAKE
を含むコマンド行ではコマンドを実行させなくするフラグがあるにもかかわらず普通に実行されます。MAKEFLAGS
のメカニズムのほうは、いつもどおり下位のmake
にフラグを渡すので(サブmake
にオプションを伝えるの項を参照)、サブシステムにファイルのタッチ(touch)やコマンドの出力といった希望の動作は継承されます。
make
に変数を伝える
明示的に要求すればトップレベルのmake
から下位(サブ)のmake
に変数の値を環境を通して渡すことができます。渡せる変数は下位のmake
でデフォルトでも定義されていますが、`-e'スイッチを使わなければmakefile内で指定した値のうち下位make
のmakefileでも使われるものをデフォルト値が上書きする事はありません(オプション要約の項を参照)。
make
は変数を受け継がせる、つまりエクスポート(export)する事を、実行中の各コマンドに対して目的の変数と値を環境に追加する事で実現しています。そうしてから次に下位のmake
が変数の値の表(table of variable values)を環境を使って初期化します。これについては環境からの変数の項を見て下さい。
make
に明示的な要求をしない場合、初めに環境で定義したかコマンド行でセットした変数だけしかエクスポートせず、エクスポートする変数名はアルファベット、数字、アンダースコア("_")のみで構成される名前でなければなりません。いくつかのシェルでは環境変数の名前にアルファベット、数字、アンダースコア以外の文字が非対応になっています。
特別な変数であるSHELL
とMAKEFLAGS
は(そうさせないようにしない限り)常にエクスポートされます。MAKEFILES
は何かをセットした場合にエクスポートされます。
make
はコマンド行で定義した変数の値を自動的にMAKEFLAGS
に取り込んで下位に渡します。これについては次の項を見て下さい。
make
でデフォルトで作成される変数は、普通は下位に渡されません(暗黙ルールに用いられる変数の項を参照)。サブのmake
ではこういう変数を独自に定義します。
特定の変数をサブmake
にエクスポートするにはexport
ディレクティヴをこうやって使います。
export 変数 ...
ある変数をエクスポートしたくなければunexport
ディレクティヴをこうやって使います。
unexport 変数 ...
次のようにすれば変数定義とエクスポートを同時にできてお手軽です。
export variable = value
は、下のものと同様の結果になります。
variable = value export variable
それから、
export variable := value
は、下のものと同様の結果になります。
variable := value export variable
あと、
export variable += value
は、次のものと全く同様です。
variable += value export variable
変数にもっと多くのテキストを入れるの項を見て下さい。
おそらくシェルsh
で動作するexport
ディレクティヴとunexport
ディレクティヴと同じ方法でmake
でも二つのディレクティヴが動作していることに気づくと思います。
全ての変数をデフォルトでエクスポートしたいなら次のようにexport
を単体で使って下さい。
export
こうするとexport
かunexport
かのディレクティヴで明示していないものをエクスポートするようにmake
に指示します。unexport
ディレクティヴで個々に指定した変数についてはこの方法では敢えてエクスポートしません。デフォルトで変数をエクスポートさせるのにexport
を単体で使うという方法だけでは、英数字か下線("_")以外を名前に含む変数はエクスポートされません。そういう変数もエクスポートするには、さらにそれだけをexport
ディレクティヴで個々に書かなければなりません。
過去のバージョンのGNU make
では単体でexport
ディレクティヴを使った時の動作がデフォルトでした。この動作に依存したmakefileで古いバージョンのmake
との互換性を持たせたい場合はexport
ディレクティヴを使う代わりに.EXPORT_ALL_VARIABLES
という特別なターゲットのルールを書いて下さい。こうすれば過去のmake
ではこの部分が無視され、export
ディレクティヴを使った場合に起こる構文エラーを避けられます。
また、unexport
を単体で使えばデフォルトで変数をエクスポートしないようにmake
に指示します。これはもともとデフォルトの動作なので、それより前に(多分インクルードしたmakefileのどれかで)export
が単体で使われている場合以外は指示する必要はありません。一部のコマンドをエクスポートし、残りをそうさせないようにするのに、単体のexport
と単体のunexport
を併用することはできません。単体のexport
と単体のunexport
のうち後のものがmake
の全部の動作を決定します。
特別な機能として、MAKELEVEL
という変数が各階層において下位に渡していくと、MAKELEVEL
の内容は変わります。この変数の値は階層の深さを10進数値で示す文字列です。この値は`0'がトップレベル(最上階層)のmake
をあらわし、それから`1'がサブ(下位)のmake
、`2'がサブサブmake
、というようになっています。この数値増加はmake
がコマンドのために環境をセットしたときに起こります。
MAKELEVEL
の主な用途は条件分岐ディレクティヴでの判断(Makefilesの条件分岐部分の項を参照)であり、これを利用する事で再帰呼び出し時とあなたが直接実行した時とで動作を変えるmakefileを記述する事が可能になります。
MAKEFILES
変数は、サブ起動の全てのmake
コマンドでmakefileを追加利用させるのに使います。MAKEFILES
の値はファイル名が空白で区切られたリストです。もしこの変数が深い層(outer-level)のmakefileで定義されると、それは環境を通して下に渡されて、通常のmakefileか指定したmakefileを読み込む前に読ませる、余分なmakefileのリストがサブのmake
に与えられたような動作をします。これについてはMAKEFILES
変数の項を見て下さい。
`-s'や`-k'のようなフラグはMAKEFLAGS
を通して自動的にサブ(下位)make
に渡されます。この変数はmake
が受けとったフラグ文字を自動的にmake
が格納したものです。だから、もし`make -ks'とすればMAKEFLAGS
には`ks'という値が入ります。
どのサブmake
も結果的にMAKEFLAGS
から環境で値を受け取ることになります。動作としてはこの変数の値からフラグを取得し、そういう引数が与えられたように処理します。オプション要約の項を見て下さい。
また、コマンド行で定義された変数はMAKEFLAGS
を通してサブmake
に受け渡されます。MAKEFLAGS
の値に`='を含んだ語句があるとmake
はそれをコマンド行にあるときと全く同様に変数定義として扱います。変数の上書きの項を見て下さい。
`-C', `-f', `-o', `-W'の各オプションはMAKEFLAGS
の対象外であり、これらオプションは下位継承されません。
`-j'オプションは特例です(並列実行の項を参照)。このオプションに数値を設定した場合、MAKEFLAGS
には指定したものではなくて常に`-j 1'が入る事になります。これはなぜかというと、もしも`-j'オプションがサブmake
にそのまま受け渡してしまうと、頼んでいた以上のジョブを並列実行してしまうことになるでしょう。可能な限り実行させるという意味で`-j' に何も数値の引数を付加しなければ、複数の無限は一つの無限を超えないため、そのまま下位にこの引数を継承します。
他のフラグを継承させたくないならMAKEFLAGS
の値をこういう風にして変更しなければなりません。
subsystem: cd subdir && $(MAKE) MAKEFLAGS=
コマンド行での変数定義は実際にはMAKEOVERRIDES
という変数の中に現れて、MAKEFLAGS
がこの変数への参照を格納しています。コマンド行での変数定義は下位に継承させたくないがフラグだけは通常通りに継承させたい場合はMAKEOVERRIDES
をこういう風にして空っぽにリセットすれば良いのです。
MAKEOVERRIDES =
これはあんまり便利な事ではありません。ですが環境のサイズが限られていて、MAKEFLAGS
の値でも情報量が上回るくらい小さいというシステムもあります。`引数のリストが長すぎる(Arg list too long)'というエラーが出た場合これが原因になっているのかもしれません。
(特殊ターゲット`.POSIX'がmakefileに現れるとPOSIX.2に厳格に従い、MAKEOVERRIDES
の変更がMAKEFLAGS
に影響しなくなります。おそらくこの事はあなたにとってどうでも良い事でしょう。)
よく似た変数にMFLAGS
というものも歴史的互換性の維持のためにあります。この変数はMAKEFLAGS
と同じ値になりますが、コマンド行での変数定義を含まず、空っぽの時以外は常にハイフン("-")から始まります(MAKEFLAGS
もハイフンから始まる事がありますが、それは一文字だけではない`--warn-undefined-variables'のようなオプションが最初にあった場合だけです)。次にあるように、MFLAGS
は再帰呼び出しのmake
コマンドでは伝統的に明示的に利用することになっていました。
subsystem: cd subdir && $(MAKE) $(MFLAGS)
しかしMAKEFLAGS
によって、今はもうこの慣習は余計なものになりました。makefileに古いmake
プログラムとの互換性を持たせたいなら、現在のmake
でも通用するこのテクニックを使って下さい。
`-k'(オプション要約の項を参照)のような特定のオプションをmake
を毎回実行するときにセットさせるのにもMAKEFLAGS
変数が役立ちます。単純に環境のMAKEFLAGS
に値を入力しておけばいいのです。makefileに影響力を持たせるフラグを追加指定するのにmakefileのMAKEFLAGS
にセットすることもできます。
(注意:MFLAGS
ではこういう事はできません。この変数は互換性のためだけにセットされるため、どのように値をセットしても、make
がこれを解釈することはありません。)
make
が(環境からだろうがmakefileからだろうが)MAKEFLAGS
の値を解釈するときには、まず初めにハイフンから始まっていないものにハイフンを付け加えます。そして値を空白に区切られた語句に切り離して、それぞれの語句をコマンド行で与えられたようにして処理していきます(`-C', `-f', `-h',`-o', `-W'とこれらのロングネーム版は例外的に無視されます。ちなみに無効なオプションについてはエラーを出しません)。
環境のMAKEFLAGS
に入力をする場合は、徹底的にmake
の動作に影響する、すなわちmakefileの目的やmake
自身の目的を蝕むようなオプションはインクルードしないようにすべきです。例を挙げると`-t', `-n', `-q'オプションのうち一つでも変数に入力してしまうと、悲惨な結果になり、少なからず驚いてしまうような、イライラする効果が当然のように出てきます。
make
の再帰多重呼び出しを行う場合、`-w'オプションか`--print-directory'オプションを使うとmake
が処理を始めたディレクトリと処理を終えたディレクトリを目で見てずっと簡単に理解できます。たとえば、`/u/gnu/make'というディレクトリで`make -w'が実行された場合、make
は以下のような一文を出力するでしょう。
make: Entering directory `/u/gnu/make'.
今のが処理前のもので、次のような一文が処理完了後のものです。
make: Leaving directory `/u/gnu/make'.
`-w'オプションは`-C'オプションが使われるとサブのmake
で自動的に有効になってくれるので、通常はこのオプションを指定する必要がありません。`--no-print-directory'で明示的に無効にするか、`-s'で沈黙するように命令した場合は、make
が`-w'を自動的に有効にすることはありません。
色々なターゲットを作るのに同じ一連のコマンドを使うのが役に立つことなら、define
ディレクティヴで一続きになっているものを缶詰めのように一塊で定義すれば、そういうターゲットを対象とするルールで缶詰めにされた一連の処理を参照して利用できるようになります。この「一連の処理が入った缶詰」とは実際には変数なので、他の変数名と競合する名前をつけてはいけません。
ここにあるのがコマンド連鎖の缶詰めの定義例です。
define run-yacc yacc $(firstword $^) mv y.tab.c $@ endef
この例ではrun-yacc
が定義変数名で、endef
が定義終了を示し、間にある行が目当てのコマンドになります。define
ディレクティヴでは、缶詰めにされた処理の中では変数参照や関数呼び出しを展開せず、`$'という文字や括弧や変数名など全てのものが定義した変数の値の一部になります。
一字一句違わずに変数を定義するの項を見ればdefine
について全ての解説があります。
この例の最初のコマンドでは、この缶詰化処理を使った全てのルールの依存関係の第一要素を対象にYaccを実行させます。Yaccが出力するファイルは常に`y.tab.c'という名前になっています。二つ目のコマンドで、この出力ファイルをルールのターゲットファイル名に変更(move)させます。
缶詰化された処理を利用するには、ルールにある目的のコマンド群を変数に入れ替えて下さい。他にある変数と同じように代用できます(変数参照の基本の項を参照)。define
で定義された変数は再帰的に展開される変数であるため、define
の中であなたが記述した全部の変数参照はここでやっと展開されます。
たとえば、
foo.c : foo.y $(run-yacc)
run-yacc
の値にある`$^'変数には`foo.y'が代入され、`$@'には`foo.c'が代入されることになります。
これは現実的な例ですが、実のところはこうする必要がありません。なぜならmake
には処理に絡むファイル名を基準にコマンドを見出してくれる暗黙のルールがあるからです
(暗黙ルールの利用の項を参照)。
コマンドの実行中には缶詰化処理は、それぞれのルールの中で普通にタブをつけて書いた場合と同じように扱われます。さらに詳しくいえば、make
は各行でばらばらのサブシェルを起動します。(`@', `-', `+'という)特別な接頭語を使って缶詰化処理内のコマンド行の動作に影響を与えることも可能です。ルール行でのコマンドの記述の項を見て下さい。
たとえばこれも缶詰化処理として使えます。
define frobnicate @echo "frobnicating target $@" frob-step-1 $< -o $@-step-1 frob-step-2 $@-step-1 -o $@ endef
make
はecho
コマンドを使う最初の行をエコーさせません。しかし、下に続く二つのコマンド行はちゃんとエコーしてくれます。
また、缶詰化処理を参照するコマンド行で頭につけた文字(接頭語)は缶詰内の処理の全ての行に適用されます。このため、下のルールでは…
frob.out: frob.in @$(frobnicate)
どのコマンドでもエコーさせません。 (コマンドエコーの項を見れば`@'についての全情報があります。)
何もさせないコマンドを定義するのが便利な場合もあります。この定義は空白だけから成るコマンドを単純に与えるだけでいいのです。
たとえば、
target: ;
とすると、`target'を対象に空っぽのコマンド文字列を定義します。空っぽのコマンド文字列を定義するのにタブ文字から始まる行を用いることも可能ですが、こういう行は見かけ上はまったく空っぽのように見えるだけなので混乱の原因に成りかねません。
何もしてくれない空っぽのコマンド文字列を定義するのにどういう意義があるのか疑問に思われるでしょう。便利だという唯一の理由は、ターゲットが暗黙のコマンド(暗黙のルールや.DEFAULT
という特別ターゲット)を利用するのを防ぐ事にあります(これについては暗黙ルールの利用の項と最後の手段を定義するデフォルトルールの項を見て下さい)。
多分、依存関係を更新させるためだけにある実際には存在しないファイルをターゲットとするルールに空っぽのコマンド文字列を定義することに心が揺れたと思います。ですが、こうするとターゲットファイルがちゃんと存在してしまうと依存関係が更新されなくなってしまうので、これは最良の方法ではありません。もっといい方法が偽りのターゲット(Phony)の項にあります。