前へ | 次へ | 目次 | 英語原版(gnu.org)

10 暗黙のルールの使い方

 ターゲットファイルを作り直すための、ある決まったやり方というものが、非常によく使われます。たとえば、オブジェクトファイルを作る慣習的な方法のひとつは、C ソースファイルから C コンパイラ cc を使って生成する、というものです。

 暗黙のルール(implicit rule)は、こうした慣習的なやり方を make に教えておくしくみです。これによって、それらを使いたいときにいちいち詳しく書かなくても済むようになります。たとえば C のコンパイルには暗黙のルールが用意されています。どの暗黙のルールが実行されるかは、ファイル名によって決まります。たとえば C のコンパイルでは、ふつう .c ファイルから .o ファイルを作ります。そこで make は、こうしたファイル名の末尾の組み合わせを見つけると、C コンパイル用の暗黙のルールを適用します。

 複数の暗黙のルールが連鎖して順に適用されることもあります。たとえば make は、.y ファイルから .c ファイルを経由して .o ファイルを作り直します。

 組み込みの暗黙のルールは、そのレシピの中でいくつかの変数を使っています。そのため、変数の値を変えるだけで、暗黙のルールの動き方を変えることができます。たとえば、C コンパイル用の暗黙のルールが C コンパイラに渡すフラグは、変数 CFLAGS で制御できます。

 パターンルール(pattern rule)を書くことで、独自の暗黙のルールを定義することもできます。

 サフィックスルール(suffix rule)は、暗黙のルールを定義するための、より限定された方法です。パターンルールのほうが汎用的で分かりやすいのですが、サフィックスルールは互換性のために残されています。

10.1 暗黙のルールを使う

 ターゲットファイルを更新する慣習的な方法を make に見つけさせるためにすべきことは、自分でレシピを書かないようにすることだけです。レシピのないルールを書くか、あるいはそのターゲットのルールをまったく書かないでおきます。すると make は、どんなソースファイルが存在するか、あるいは作れるかをもとに、どの暗黙のルールを使うかを判断してくれます。

 たとえば、makefile が次のようになっているとします:

foo : foo.o bar.o
        cc -o foo foo.o bar.o $(CFLAGS) $(LDFLAGS)

 ここで foo.o に言及しているのにそのルールを与えていないので、make はそれをどう更新すればよいかを教えてくれる暗黙のルールを自動的に探します。これは foo.o というファイルが現在存在するかどうかに関係なく行われます。

 暗黙のルールが見つかれば、それはレシピと、ひとつ以上の前提条件(ソースファイル)の両方を提供してくれます。foo.o についてレシピのないルールを書きたくなるのは、暗黙のルールが供給できないような追加の前提条件——たとえばヘッダファイルなど——を指定する必要があるときです。

 それぞれの暗黙のルールには、ターゲットパターンと前提条件パターンがあります。同じターゲットパターンを持つ暗黙のルールがいくつもあることもあります。たとえば、「.o」ファイルを作るルールはたくさんあります。あるものは「.c」ファイルから C コンパイラで作り、別のものは「.p」ファイルから Pascal コンパイラで作る、といった具合です。実際に適用されるのは、その前提条件が存在するか、または作れるルールです。つまり、foo.c というファイルがあれば make は C コンパイラを実行し、そうでなくて foo.p というファイルがあれば Pascal コンパイラを実行する、という具合になります。

 もちろん makefile を書くときには、make にどの暗黙のルールを使ってほしいかは分かっているはずです。そして、どの前提条件ファイルが存在するはずかを知っているので、make がそのルールを選ぶことも分かっているはずです。あらかじめ定義されている暗黙のルールの一覧については、組み込みルールのカタログを参照してください。

 先ほど、必要な前提条件が「存在するか、または作れる」場合に暗黙のルールが適用される、と述べました。あるファイルが「作れる」のは、それが makefile の中でターゲットまたは前提条件として明示的に言及されている場合か、あるいはそれを作る方法が暗黙のルールによって再帰的に見つかる場合です。暗黙の前提条件が別の暗黙のルールの結果である場合、連鎖(chaining)が起こっていると言います。暗黙のルールの連鎖を参照してください。

 一般に make は、レシピを持たないそれぞれのターゲットと、レシピを持たないそれぞれのダブルコロンルールについて、暗黙のルールを探します。前提条件としてしか言及されていないファイルは、何も指定していないルールを持つターゲットとみなされるので、それについても暗黙のルールの探索が行われます。探索がどのように行われるかの詳細は、暗黙のルールの探索アルゴリズムを参照してください。

 なお、明示的に書かれた前提条件は、暗黙のルールの探索に影響しないという点に注意してください。たとえば、次のような明示的なルールを考えてみましょう:

foo.o: foo.p

 foo.p という前提条件があるからといって、make が Pascal ソースファイル(.p ファイル)からオブジェクトファイル(.o ファイル)を作る暗黙のルールに従って foo.o を作り直すとは限りません。たとえば foo.c も存在する場合は、C ソースファイルからオブジェクトファイルを作る暗黙のルールのほうが使われます。なぜなら、それはあらかじめ定義されている暗黙のルールの一覧の中で Pascal のルールより先に現れるからです(組み込みルールのカタログを参照してください)。

 レシピを持たないターゲットに対して暗黙のルールを使ってほしくない場合は、そのターゲットにセミコロンを書くことで空のレシピを与えることができます(空のレシピの定義を参照してください)。

10.2 組み込みルールのカタログ

 ここに、あらかじめ定義されている暗黙のルールのカタログを示します。これらは、makefile が明示的にオーバーライドしたり取り消したりしない限り、常に利用できます。暗黙のルールを取り消したりオーバーライドしたりする方法については、暗黙のルールの取り消しを参照してください。「-r」または「--no-builtin-rules」オプションを使うと、あらかじめ定義されたルールがすべて取り消されます。

 このマニュアルが説明するのは、POSIX ベースのオペレーティングシステムで利用できるデフォルトのルールだけです。VMS、Windows、OS/2 などの他のオペレーティングシステムでは、デフォルトのルールの組が異なる場合があります。あなたの使っている GNU make で利用できるデフォルトのルールと変数の完全な一覧を見るには、makefile のないディレクトリで「make -p」を実行してください。

 これらのルールが、「-r」オプションを付けていないときでも常にすべて定義されるとは限りません。あらかじめ定義された暗黙のルールの多くは、make の内部ではサフィックスルールとして実装されています。そのため、どれが定義されるかはサフィックスリスト(特別なターゲット .SUFFIXES の前提条件のリスト)に依存します。デフォルトのサフィックスリストは次のとおりです: .out.a.ln.o.c.cc.C.cpp.p.f.F.m.r.y.l.ym.lm.s.S.mod.sym.def.h.info.dvi.tex.texinfo.texi.txinfo.w.ch .web.sh.elc.el。 以下で説明する暗黙のルールのうち、前提条件がこれらのサフィックスのいずれかを持つものは、実はすべてサフィックスルールです。サフィックスリストを変更すると、有効になるあらかじめ定義されたサフィックスルールは、あなたが指定したリストに載っているサフィックスの一つまたは二つで構成されるものだけになります。サフィックスがリストに載っていないルールは無効になります。サフィックスルールの詳細については、昔ながらのサフィックスルールを参照してください。

C プログラムのコンパイル

n.on.c から、「$(CC) $(CPPFLAGS) $(CFLAGS) -c」という形のレシピで自動的に作られます。

C++ プログラムのコンパイル

n.on.ccn.cpp、または n.C から、「$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c」という形のレシピで自動的に作られます。C++ のソースファイルには、大文字小文字を区別しないファイルシステムでもうまく扱えるように、「.C」ではなく「.cc」または「.cpp」のサフィックスを使うことをおすすめします。

Pascal プログラムのコンパイル

n.on.p から、「$(PC) $(PFLAGS) -c」というレシピで自動的に作られます。

Fortran および Ratfor プログラムのコンパイル

n.on.rn.F、または n.f から、Fortran コンパイラを実行することで自動的に作られます。実際に使われるレシピは次のとおりです:

.f

$(FC) $(FFLAGS) -c」。

.F

$(FC) $(FFLAGS) $(CPPFLAGS) -c」。

.r

$(FC) $(FFLAGS) $(RFLAGS) -c」。

Fortran および Ratfor プログラムの前処理

n.fn.r または n.F から自動的に作られます。このルールはプリプロセッサだけを実行して、Ratfor プログラムまたは前処理が必要な Fortran プログラムを、純粋な Fortran プログラムに変換します。実際に使われるレシピは次のとおりです:

.F

$(FC) $(CPPFLAGS) $(FFLAGS) -F」。

.r

$(FC) $(FFLAGS) $(RFLAGS) -F」。

Modula-2 プログラムのコンパイル

n.symn.def から、「$(M2C) $(M2FLAGS) $(DEFFLAGS)」という形のレシピで作られます。n.on.mod から作られ、その形は「$(M2C) $(M2FLAGS) $(MODFLAGS)」です。

アセンブラプログラムのアセンブルと前処理

n.on.s から、アセンブラ as を実行することで自動的に作られます。実際のレシピは「$(AS) $(ASFLAGS)」です。

n.sn.S から、C プリプロセッサ cpp を実行することで自動的に作られます。実際のレシピは「$(CPP) $(CPPFLAGS)」です。

単一のオブジェクトファイルのリンク

nn.o から、プログラムをリンクするために C コンパイラを実行することで自動的に作られます。実際に使われるレシピは「$(CC) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS)」です。

 このルールは、ソースファイルがひとつだけの単純なプログラムに対して、ちょうどよい働きをします。また、(おそらく別のいくつかのソースファイルから来た)複数のオブジェクトファイルがあり、そのうちの一つの名前が実行可能ファイルの名前と一致する場合にも、うまく働きます。したがって、

x: y.o z.o

というルールは、x.cy.cz.c がすべて存在するとき、次のように実行されます:

cc -c x.c -o x.o
cc -c y.c -o y.o
cc -c z.c -o z.o
cc x.o y.o z.o -o x
rm -f x.o
rm -f y.o
rm -f z.o

 実行可能ファイルの名前から導かれる名前のオブジェクトファイルが存在しない場合など、もっと複雑なケースでは、リンク用の明示的なレシピを自分で書かなければなりません。

 「.o」オブジェクトファイルへと自動的に作られる各種のファイルは、コンパイラ(「$(CC)」、「$(FC)」、または「$(PC)」。「.s」ファイルのアセンブルには C コンパイラ「$(CC)」が使われます)を「-c」オプションなしで使うことで、自動的にリンクされます。これは「.o」オブジェクトファイルを中間ファイルとして使うことでも実現できますが、コンパイルとリンクを一段階で行ったほうが速いので、そのようにしています。

C プログラム用の Yacc

n.cn.y から、「$(YACC) $(YFLAGS)」というレシピで Yacc を実行することで自動的に作られます。

C プログラム用の Lex

n.cn.l から、Lex を実行することで自動的に作られます。実際のレシピは「$(LEX) $(LFLAGS)」です。

Ratfor プログラム用の Lex

n.rn.l から、Lex を実行することで自動的に作られます。実際のレシピは「$(LEX) $(LFLAGS)」です。

 C コードを生成する場合でも Ratfor コードを生成する場合でも、Lex ファイルに同じ「.l」サフィックスを使うという慣習があるため、make は具体的なケースでそのどちらの言語が使われているのかを自動的に判別できません。make が「.l」ファイルからオブジェクトファイルを作り直すよう求められたときには、どちらのコンパイラを使うかを推測しなければなりません。make は C コンパイラだと推測します。そのほうが一般的だからです。Ratfor を使っている場合は、makefile の中で n.r に言及して、make にそのことを知らせてください。あるいは、C ファイルを一切使わず Ratfor だけを使っているのであれば、次のようにして暗黙のルールのサフィックスのリストから「.c」を取り除いてください:

.SUFFIXES:
.SUFFIXES: .o .r .f .l …
C、Yacc、Lex プログラムからの Lint ライブラリの作成

n.lnn.c から、lint を実行することで作られます。実際のレシピは「$(LINT) $(LINTFLAGS) $(CPPFLAGS) -i」です。同じレシピは、n.yn.l から生成された C コードに対しても使われます。

TeX と Web

n.dvin.tex から、「$(TEX)」というレシピで作られます。n.texn.web から「$(WEAVE)」で、あるいは n.w(および、存在するか作れるなら n.ch)から「$(CWEAVE)」で作られます。n.pn.web から「$(TANGLE)」で作られ、n.cn.w(および、存在するか作れるなら n.ch)から「$(CTANGLE)」で作られます。

Texinfo と Info

n.dvin.texinfon.texi、または n.txinfo から、「$(TEXI2DVI) $(TEXI2DVI_FLAGS)」というレシピで作られます。n.infon.texinfon.texi、または n.txinfo から、「$(MAKEINFO) $(MAKEINFO_FLAGS)」というレシピで作られます。

RCS

任意のファイル n は、必要であれば n,v または RCS/n,v という名前の RCS ファイルから取り出されます。実際に使われるレシピは「$(CO) $(COFLAGS)」です。n がすでに存在する場合は、たとえ RCS ファイルのほうが新しくても、RCS から取り出されることはありません。RCS のルールは終端(terminal)です(何にでもマッチするパターンルールを参照してください)。そのため、RCS ファイルは別のソースから生成することはできません。実際に存在していなければなりません。

SCCS

任意のファイル n は、必要であれば s.n または SCCS/s.n という名前の SCCS ファイルから取り出されます。実際に使われるレシピは「$(GET) $(GFLAGS)」です。SCCS のルールは終端(terminal)です(何にでもマッチするパターンルールを参照してください)。そのため、SCCS ファイルは別のソースから生成することはできません。実際に存在していなければなりません。

 SCCS の便宜のため、ファイル nn.sh からコピーされ、(すべてのユーザに対して)実行可能にされます。これは SCCS にチェックインされているシェルスクリプトのためのものです。RCS はファイルの実行権限を保持するので、RCS ではこの機能を使う必要はありません。

 SCCS の使用は避けることをおすすめします。RCS は SCCS より優れていると広く認められており、しかも自由(フリー)です。同等の(あるいは劣った)プロプライエタリなソフトウェアの代わりに自由なソフトウェアを選ぶことで、あなたはフリーソフトウェア運動を支援することになります。

 ふつう変更したくなるのは、上記の表に挙げた変数だけでしょう。これらの変数は次の節で説明します。

 しかし、組み込みの暗黙のルールのレシピは、実際には COMPILE.cLINK.pPREPROCESS.S といった変数を使っています。これらの変数の値の中に、上に挙げたレシピが含まれているのです。

 make は、.x ソースファイルをコンパイルするルールが変数 COMPILE.x を使う、という規約に従っています。同様に、.x ファイルから実行可能ファイルを作るルールは LINK.x を使い、.x ファイルを前処理するルールは PREPROCESS.x を使います。

 オブジェクトファイルを生成するすべてのルールは、変数 OUTPUT_OPTION を使います。make は、コンパイル時のオプションに応じて、この変数を「-o $@」を含む値に定義するか、空に定義します。ソースファイルが別のディレクトリにあるとき(VPATH を使っている場合など。前提条件のためのディレクトリ探索を参照してください)、出力が正しいファイルに入るようにするためには「-o」オプションが必要です。しかし、システムによってはオブジェクトファイルに対する「-o」スイッチを受け付けないコンパイラもあります。そのようなシステムで VPATH を使うと、一部のコンパイルが出力を間違った場所に置いてしまいます。この問題への回避策のひとつは、OUTPUT_OPTION に「; mv $*.o $@」という値を与えることです。

10.3 暗黙のルールが使う変数

 組み込みの暗黙のルールのレシピは、あらかじめ定義されたいくつかの変数をふんだんに使っています。これらの変数の値は、makefile の中で、make への引数で、あるいは環境の中で変更できます。そうすることで、ルールそのものを再定義しなくても、暗黙のルールの動き方を変えられます。暗黙のルールが使うすべての変数は、「-R」または「--no-builtin-variables」オプションで取り消すことができます。

 たとえば、C ソースファイルをコンパイルするのに使われるレシピは、実際には「$(CC) -c $(CFLAGS) $(CPPFLAGS)」となっています。使われる変数のデフォルト値は、「cc」と空文字列なので、結果として「cc -c」というコマンドになります。「CC」を「ncc」に再定義すれば、暗黙のルールが行うすべての C コンパイルで「ncc」が使われるようにできます。「CFLAGS」を「-g」に再定義すれば、各コンパイルに「-g」オプションを渡せます。C コンパイルを行うすべての暗黙のルールは「$(CC)」を使ってコンパイラのプログラム名を取得し、すべてがコンパイラに与える引数の中に「$(CFLAGS)」を含めます。

 暗黙のルールで使われる変数は、二つの種類に分けられます。CC のようにプログラム名であるものと、CFLAGS のようにプログラムへの引数を含むものです。(「プログラム名」にはコマンド引数がいくつか含まれていてもかまいませんが、必ず実際の実行可能プログラム名で始まらなければなりません。)変数の値が複数の引数を含む場合は、それらを空白で区切ります。

 以下の表は、比較的よく使われるあらかじめ定義された変数のいくつかを説明したものです。このリストは網羅的なものではなく、ここに示すデフォルト値は、あなたの環境で make が選ぶものとは異なるかもしれません。あなたの使っている GNU make のあらかじめ定義された変数の完全な一覧を見るには、makefile のないディレクトリで「make -p」を実行してください。

 ここに、組み込みルールでプログラム名として使われる、比較的よく使われる変数の表を示します:

AR

アーカイブ管理プログラム。デフォルトは「ar」。

AS

アセンブリファイルをコンパイルするプログラム。デフォルトは「as」。

CC

C プログラムをコンパイルするプログラム。デフォルトは「cc」。

CXX

C++ プログラムをコンパイルするプログラム。デフォルトは「g++」。

CPP

C プリプロセッサを実行し、結果を標準出力に出すプログラム。デフォルトは「$(CC) -E」。

FC

Fortran および Ratfor プログラムをコンパイルまたは前処理するプログラム。デフォルトは「f77」。

M2C

Modula-2 ソースコードのコンパイルに使うプログラム。デフォルトは「m2c」。

PC

Pascal プログラムをコンパイルするプログラム。デフォルトは「pc」。

CO

RCS からファイルを取り出すプログラム。デフォルトは「co」。

GET

SCCS からファイルを取り出すプログラム。デフォルトは「get」。

LEX

Lex の文法定義をソースコードに変換するのに使うプログラム。デフォルトは「lex」。

YACC

Yacc の文法定義をソースコードに変換するのに使うプログラム。デフォルトは「yacc」。

LINT

ソースコードに対して lint を実行するのに使うプログラム。デフォルトは「lint」。

MAKEINFO

Texinfo ソースファイルを Info ファイルに変換するプログラム。デフォルトは「makeinfo」。

TEX

TeX ソースから TeX の DVI ファイルを作るプログラム。デフォルトは「tex」。

TEXI2DVI

Texinfo ソースから TeX の DVI ファイルを作るプログラム。デフォルトは「texi2dvi」。

WEAVE

Web を TeX に変換するプログラム。デフォルトは「weave」。

CWEAVE

C Web を TeX に変換するプログラム。デフォルトは「cweave」。

TANGLE

Web を Pascal に変換するプログラム。デフォルトは「tangle」。

CTANGLE

C Web を C に変換するプログラム。デフォルトは「ctangle」。

RM

ファイルを削除するコマンド。デフォルトは「rm -f」。

 ここに、値が上記のプログラムへの追加引数となる変数の表を示します。これらの変数のデフォルト値は、特に断りのない限りすべて空文字列です。

ARFLAGS

アーカイブ管理プログラムに与えるフラグ。デフォルトは「rv」。

ASFLAGS

(「.s」または「.S」ファイルに対して明示的に起動されたときに)アセンブラに与える追加のフラグ。

CFLAGS

C コンパイラに与える追加のフラグ。

CXXFLAGS

C++ コンパイラに与える追加のフラグ。

COFLAGS

RCS の co プログラムに与える追加のフラグ。

CPPFLAGS

C プリプロセッサと、それを使うプログラム(C および Fortran コンパイラ)に与える追加のフラグ。

FFLAGS

Fortran コンパイラに与える追加のフラグ。

GFLAGS

SCCS の get プログラムに与える追加のフラグ。

LDFLAGS

コンパイラがリンカ「ld」を起動するときに、それらのコンパイラに与える追加のフラグ。たとえば -L など。ライブラリ(-lfoo)は、代わりに LDLIBS 変数に追加すべきです。

LDLIBS

コンパイラがリンカ「ld」を起動するときに、それらのコンパイラに与えるライブラリのフラグや名前。LOADLIBESLDLIBS の非推奨(ただし現在もサポートされている)の代替です。-L のようなライブラリ以外のリンカフラグは LDFLAGS 変数に入れるべきです。

LFLAGS

Lex に与える追加のフラグ。

YFLAGS

Yacc に与える追加のフラグ。

PFLAGS

Pascal コンパイラに与える追加のフラグ。

RFLAGS

Ratfor プログラムのために Fortran コンパイラに与える追加のフラグ。

LINTFLAGS

lint に与える追加のフラグ。

10.4 暗黙のルールの連鎖

 ときには、あるファイルが一連の暗黙のルールの連続によって作られることがあります。たとえば、ファイル n.o は、まず Yacc を、次に cc を実行することで n.y から作ることができます。このような連続を連鎖(chain)と呼びます。

 ファイル n.c が存在するか、makefile の中で言及されている場合は、特別な探索は必要ありません。make は、オブジェクトファイルが n.c からの C コンパイルで作れることを見つけます。そして後で n.c をどう作るかを検討するときに、Yacc を実行するルールが使われます。最終的に n.cn.o の両方が更新されます。

 しかし、n.c が存在せず、makefile の中でも言及されていなくても、maken.on.y の間をつなぐ失われた環として、それを思い描くことができるのです! この場合、n.c中間ファイル(intermediate file)と呼ばれます。いったん make が中間ファイルを使うと決めると、それは makefile の中で言及されていたかのように、それを作る方法を示す暗黙のルールとともに、データベースに登録されます。

 中間ファイルも、他のすべてのファイルと同じように、そのルールを使って作り直されます。ただし、中間ファイルは二つの点で異なる扱いを受けます。

 一つ目の違いは、中間ファイルが存在しない場合に何が起こるかです。ふつうのファイル b が存在せず、makeb に依存するターゲットを検討する場合、make は必ず b を作り、それからその b をもとにターゲットを更新します。しかし b が中間ファイルである場合は、make はそのまま放っておくことができます。b の前提条件のどれかが古くなっていない限り、makeb を作りません。これは、b に依存するターゲットも、それを更新する別の理由——たとえばターゲットが存在しないとか、別の前提条件がターゲットより新しいとか——がない限り、作り直されないことを意味します。

 二つ目の違いは、make が何か別のものを更新するために b実際に作った場合、もはや不要になった後でその b を削除する、という点です。したがって、make を実行する前に存在しなかった中間ファイルは、make の実行後にも存在しません。make は、どのファイルを削除しているかを示す「rm」コマンドを表示することで、その削除をあなたに知らせます。

 ファイルを特別なターゲット .INTERMEDIATE の前提条件として並べることで、そのファイルを明示的に中間ファイルとして指定できます。これは、そのファイルが他の何らかの形で明示的に言及されていても効力を持ちます。

 あるファイルが makefile の中でターゲットまたは前提条件として言及されている場合、そのファイルは中間ファイルにはなれません。したがって、中間ファイルの削除を避ける方法のひとつは、それを何らかのターゲットの前提条件として追加することです。ただし、そうすると make がパターンルールを探索するときに余分な処理をすることがあります(暗黙のルールの探索アルゴリズムを参照してください)。

 別の方法として、ファイルを特別なターゲット .NOTINTERMEDIATE の前提条件として並べると、(そのファイルを他の方法で言及するのと同じように)そのファイルが中間ファイルとみなされなくなります。また、パターンルールのターゲットパターンを .NOTINTERMEDIATE の前提条件として並べると、そのパターンルールを使って生成されるターゲットが中間ファイルとみなされないようになります。

 makefile の中で中間ファイルを完全に無効にするには、.NOTINTERMEDIATE を前提条件のないターゲットとして与えます。その場合、それは makefile 内のすべてのファイルに適用されます。

 あるファイルが存在しないというだけの理由で make に作らせたくはないが、かといって make にそのファイルを自動的に削除させたくもない、という場合は、それを二次的(secondary)ファイルとして指定できます。そのためには、それを特別なターゲット .SECONDARY の前提条件として並べます。ファイルを二次的ファイルとして指定すると、そのファイルは中間ファイルとしても指定されます。

 一つの連鎖に二つより多くの暗黙のルールが関わることもあります。たとえば、RCS、Yacc、cc を実行することで、RCS/foo.y,v からファイル foo を作ることができます。この場合、foo.yfoo.c はどちらも中間ファイルであり、最後に削除されます。

 一つの暗黙のルールが、一つの連鎖の中に二回以上現れることはできません。つまり make は、リンカを二回実行して foo.o.o から foo を作る、などというばかげたことは検討すらしません。この制約には、暗黙のルールの連鎖の探索が無限ループに陥るのを防ぐという、付随的な利点もあります。

 本来であれば連鎖で処理されるはずの特定のケースを最適化するための、特別な暗黙のルールがいくつかあります。たとえば、foo.c から foo を作る処理は、foo.o を中間ファイルとして使い、別々の連鎖ルールでコンパイルとリンクを行うことでも処理できます。しかし実際に起こるのは、このケース専用の特別なルールが、一つの cc コマンドでコンパイルとリンクを行う、ということです。この最適化されたルールは、ルールの並び順の中で先に現れるので、段階を追った連鎖よりも優先して使われます。

 最後に、性能上の理由から、make は暗黙のルールの前提条件を作るルールを探索するときには、非終端の何にでもマッチするルール(すなわち「%:」)を検討しません(何にでもマッチするパターンルールを参照してください)。

10.5 パターンルールの定義と再定義

 暗黙のルールは、パターンルール(pattern rule)を書くことで定義します。パターンルールはふつうのルールに似ていますが、ターゲットに文字「%」を(ちょうど一つだけ)含んでいる点が違います。ターゲットはファイル名にマッチさせるためのパターンとして扱われます。「%」は空でない任意の部分文字列にマッチし、それ以外の文字はその文字自身にしかマッチしません。前提条件も同様に「%」を使って、その名前がターゲット名とどう関係するかを示します。

 したがって、パターンルール「%.o : %.c」は、別のファイル stem.c から任意のファイル stem.o をどう作るかを示すものです。

 なお、パターンルールにおける「%」を使った展開は、変数や関数の展開の後で行われるという点に注意してください。変数や関数の展開は makefile が読み込まれるときに行われます。変数の使い方およびテキストを変換する関数を参照してください。

10.5.1 パターンルール入門

 パターンルールは、ターゲットに文字「%」を(ちょうど一つだけ)含みます。それ以外の点では、ふつうのルールとまったく同じに見えます。ターゲットはファイル名にマッチさせるためのパターンです。「%」は空でない任意の部分文字列にマッチし、それ以外の文字はその文字自身にしかマッチしません。

 たとえば、パターンとしての「%.c」は、「.c」で終わる任意のファイル名にマッチします。パターンとしての「s.%.c」は、「s.」で始まり「.c」で終わる、少なくとも 5 文字以上の任意のファイル名にマッチします。(「%」にマッチする文字が少なくとも一つはなければなりません。)「%」にマッチした部分文字列を語幹(stem)と呼びます。

 パターンルールの前提条件における「%」は、ターゲットの「%」がマッチしたのと同じ語幹を表します。パターンルールが適用されるためには、そのターゲットパターンが検討中のファイル名にマッチし、かつ(パターン置換後の)すべての前提条件が、存在するか作れるファイルを指していなければなりません。これらのファイルがターゲットの前提条件になります。

 したがって、次の形のルールは、

%.o : %.c ; recipe

ファイル n.c が存在するか作れることを条件として、別のファイル n.c を前提条件としてファイル n.o をどう作るかを指定します。

 「%」を使わない前提条件があってもかまいません。そのような前提条件は、このパターンルールで作られるすべてのファイルに付随します。こうした変化しない前提条件は、ときに役に立ちます。

 パターンルールには、「%」を含む前提条件がなくてもよく、実際まったく前提条件がなくてもかまいません。そのようなルールは、事実上、汎用のワイルドカードとして働きます。それは、ターゲットパターンにマッチする任意のファイルを作る方法を提供します。最後の手段となるデフォルトルールの定義を参照してください。

 複数のパターンルールが一つのターゲットにマッチすることもあります。その場合、make は「最もよく合う」ルールを選びます。パターンはどうマッチするかを参照してください。

 パターンルールは複数のターゲットを持つこともできます。ただし、すべてのターゲットが % 文字を含んでいなければなりません。パターンルールの複数のターゲットパターンは、それらが : を使うか &: 区切りを使うかにかかわらず、常にグループ化されたターゲットとして扱われます(ルール内の複数のターゲットを参照してください)。

 ただし一つだけ例外があります。あるパターンターゲットが古いか存在しないにもかかわらず、makefile がそれをビルドする必要がない場合、そのターゲットは他のターゲットを古いとみなさせる原因にはなりません。なお、この歴史的な例外は GNU make の将来のバージョンで取り除かれる予定なので、頼りにすべきではありません。make がこの状況を検出した場合、pattern recipe did not update peer target(パターンレシピが対になるターゲットを更新しなかった)という警告を出します。ただし、make がそのような状況をすべて検出できるわけではありません。レシピが実行されるときには、すべてのターゲットパターンを必ず更新するようにしてください。

10.5.2 パターンルールの例

 ここに、make に実際にあらかじめ定義されているパターンルールの例をいくつか示します。まず、「.c」ファイルを「.o」ファイルにコンパイルするルールです:

%.o : %.c
        $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@

これは、任意のファイル x.ox.c から作れるルールを定義しています。このレシピは、自動変数「$@」と「$<」を使って、ルールが適用される各ケースでのターゲットファイル名とソースファイル名を置き換えています(自動変数を参照してください)。

 二つ目の組み込みルールです:

% :: RCS/%,v
        $(CO) $(COFLAGS) $<

これは、サブディレクトリ RCS 内の対応するファイル x,v から、何であれ任意のファイル x を作れるルールを定義しています。ターゲットが「%」なので、このルールは適切な前提条件ファイルが存在しさえすれば、どんなファイルにも適用されます。ダブルコロンは、このルールを終端(terminal)にします。これは、その前提条件が中間ファイルであってはならないことを意味します(何にでもマッチするパターンルールを参照してください)。

 このパターンルールは二つのターゲットを持ちます:

%.tab.c %.tab.h: %.y
        bison -d $<

これは、レシピ「bison -d x.y」が x.tab.cx.tab.h の両方を作る、ということを make に伝えます。もしファイル foo がファイル parse.tab.oscan.o に依存し、さらにファイル scan.o がファイル parse.tab.h に依存している場合、parse.y が変更されると、レシピ「bison -d parse.y」は一度だけ実行され、parse.tab.oscan.o の両方の前提条件が満たされます。(おそらく、ファイル parse.tab.oparse.tab.c から、ファイル scan.oscan.c から再コンパイルされ、一方 fooparse.tab.oscan.o、およびその他の前提条件からリンクされて、それ以降めでたく動き続けることでしょう。)

10.5.3 自動変数

 「.c」ファイルを「.o」ファイルにコンパイルするパターンルールを書いているとしましょう。正しいソースファイル名に対して動作するように、「cc」コマンドをどう書けばよいでしょうか? レシピの中にその名前を書くことはできません。なぜなら、暗黙のルールが適用されるたびに名前が違うからです。

 そこで使うのが、make の特別な機能、自動変数(automatic variable)です。これらの変数は、実行される各ルールについて、そのルールのターゲットと前提条件をもとに、その都度あらためて値が計算されます。この例では、オブジェクトファイル名には「$@」を、ソースファイル名には「$<」を使うことになります。

 自動変数の値が利用できる範囲が限られていることを認識しておくことは、非常に重要です。これらの値は、レシピの中でしか値を持ちません。特に、ルールのターゲットリストの中ではどこでもこれらを使うことはできません。そこでは値を持たず、空文字列に展開されます。また、ルールの前提条件リストの中でも直接アクセスすることはできません。よくある間違いは、前提条件リストの中で $@ を使おうとすることです。これはうまくいきません。ただし、GNU make には二次展開(二次展開を参照してください)という特別な機能があり、これを使えば前提条件リストの中で自動変数の値を使うことができます。

 ここに自動変数の表を示します:

$@

ルールのターゲットのファイル名。ターゲットがアーカイブメンバである場合、「$@」はアーカイブファイルの名前になります。複数のターゲットを持つパターンルール(パターンルール入門を参照してください)では、「$@」は、ルールのレシピを実行させる原因となったターゲットの名前になります。

$%

ターゲットがアーカイブメンバである場合の、ターゲットのメンバ名。makeでアーカイブファイルを更新するを参照してください。たとえばターゲットが foo.a(bar.o) である場合、「$%」は bar.o、「$@」は foo.a になります。ターゲットがアーカイブメンバでない場合、「$%」は空になります。

$<

最初の前提条件の名前。ターゲットが暗黙のルールからそのレシピを得た場合、これは暗黙のルールによって追加された最初の前提条件になります(暗黙のルールの使い方を参照してください)。

$?

ターゲットより新しいすべての前提条件の名前を、空白で区切って並べたもの。ターゲットが存在しない場合は、すべての前提条件が含まれます。アーカイブメンバである前提条件については、指定されたメンバだけが使われます(makeでアーカイブファイルを更新するを参照してください)。

 「$?」は、変更された前提条件だけを操作したい場合には、明示的なルールの中でも役に立ちます。たとえば、lib という名前のアーカイブが、いくつかのオブジェクトファイルのコピーを格納することになっているとします。次のルールは、変更されたオブジェクトファイルだけをアーカイブにコピーします:

lib: foo.o bar.o lose.o win.o
        ar r lib $?
$^

すべての前提条件の名前を、空白で区切って並べたもの。アーカイブメンバである前提条件については、指定されたメンバだけが使われます(makeでアーカイブファイルを更新するを参照してください)。一つのターゲットは、依存する各ファイルについて前提条件を一つしか持ちません。同じファイルが前提条件として何回並べられていても同じです。したがって、一つのターゲットに対して同じ前提条件を二回以上並べても、$^ の値にはその名前のコピーが一つだけ含まれます。このリストには順序のみの前提条件は含まれません。それらについては、後述の「$|」変数を参照してください。

$+

これは「$^」に似ていますが、二回以上並べられた前提条件は、makefile の中で並べられた順序のまま重複して含まれます。これは主に、ライブラリファイル名を特定の順序で繰り返すことに意味があるリンクコマンドで役に立ちます。

$|

すべての順序のみの前提条件の名前を、空白で区切って並べたもの。

$*

暗黙のルールがマッチした語幹(パターンはどうマッチするかを参照してください)。ターゲットが dir/a.foo.b で、ターゲットパターンが a.%.b である場合、語幹は dir/foo です。語幹は、関連するファイルの名前を組み立てるのに役立ちます。

 静的パターンルールでは、語幹はターゲットパターンの「%」にマッチしたファイル名の一部です。

 明示的なルールには語幹がないので、そのような方法では「$*」を決めることができません。その代わり、ターゲット名が認識されるサフィックス(昔ながらのサフィックスルールを参照してください)で終わっている場合、「$*」はターゲット名からそのサフィックスを取り除いたものに設定されます。たとえば、ターゲット名が「foo.c」であれば、「.c」はサフィックスなので、「$*」は「foo」に設定されます。GNU make がこのような奇妙なことをするのは、他の make 実装との互換性のためだけです。「$*」は、暗黙のルールや静的パターンルールの中以外では、一般に使わないようにすべきです。

 明示的なルールでターゲット名が認識されるサフィックスで終わっていない場合、そのルールでは「$*」は空文字列に設定されます。

 上に挙げた変数のうち、四つは単一のファイル名を値とし、三つはファイル名のリストを値とします。これら七つの変数には、ファイルのディレクトリ名だけ、あるいはディレクトリ内のファイル名だけを取り出すバリアントがあります。バリアント変数の名前は、末尾にそれぞれ「D」または「F」を付けて作ります。関数 dirnotdir を使っても同様の効果が得られます(ファイル名のための関数を参照してください)。ただし、「D」のバリアントはすべて末尾のスラッシュを省く点に注意してください。dir 関数の出力には末尾のスラッシュが必ず現れます。ここにバリアントの表を示します:

$(@D)

ターゲットのファイル名のディレクトリ部分から、末尾のスラッシュを取り除いたもの。「$@」の値が dir/foo.o であれば、「$(@D)」は dir です。「$@」がスラッシュを含まない場合、この値は . になります。

$(@F)

ターゲットのファイル名の、ディレクトリ内のファイル名部分。「$@」の値が dir/foo.o であれば、「$(@F)」は foo.o です。「$(@F)」は「$(notdir $@)」と等価です。

$(*D)
$(*F)

語幹のディレクトリ部分とディレクトリ内のファイル名部分。この例では dirfoo です。

$(%D)
$(%F)

ターゲットのアーカイブメンバ名の、ディレクトリ部分とディレクトリ内のファイル名部分。これは archive(member) という形のアーカイブメンバターゲットに対してのみ意味があり、member がディレクトリ名を含みうる場合にのみ役立ちます。(ターゲットとしてのアーカイブメンバを参照してください。)

$(<D)
$(<F)

最初の前提条件の、ディレクトリ部分とディレクトリ内のファイル名部分。

$(^D)
$(^F)

すべての前提条件の、ディレクトリ部分のリストとディレクトリ内のファイル名部分のリスト。

$(+D)
$(+F)

すべての前提条件の、ディレクトリ部分のリストとディレクトリ内のファイル名部分のリスト。重複した前提条件の複数のインスタンスも含みます。

$(?D)
$(?F)

ターゲットより新しいすべての前提条件の、ディレクトリ部分のリストとディレクトリ内のファイル名部分のリスト。

 なお、これらの自動変数について述べるときには、特別な文体上の慣習を使っている点に注意してください。私たちは、objectsCFLAGS のようなふつうの変数について書くときのように「変数 <」と書くのではなく、「「$<」の値」と書いています。この特別なケースでは、その慣習のほうが自然に見えると考えているからです。これに深い意味があると思わないでください。「$<」は、ちょうど「$(CFLAGS)」が CFLAGS という名前の変数を指すのと同じように、< という名前の変数を指しているだけです。「$<」の代わりに「$(<)」と書いても、まったく同じです。

10.5.4 パターンはどうマッチするか

 ターゲットパターンは、接頭辞と接尾辞の間に「%」を置いて構成されます。接頭辞・接尾辞のどちらか一方、または両方が空でもかまいません。パターンがファイル名にマッチするのは、そのファイル名が接頭辞で始まり接尾辞で終わり、かつ両者が重ならない場合だけです。接頭辞と接尾辞の間のテキストを語幹(stem)と呼びます。したがって、パターン「%.o」がファイル名 test.o にマッチするとき、語幹は「test」です。パターンルールの前提条件は、「%」という文字を語幹で置き換えることによって、実際のファイル名に変換されます。したがって、同じ例で前提条件の一つが「%.c」と書かれていれば、それは「test.c」に展開されます。

 ターゲットパターンがスラッシュを含まない場合(ふつうは含みません)、ファイル名中のディレクトリ名は、ターゲットの接頭辞・接尾辞と比較される前にファイル名から取り除かれます。ファイル名とターゲットパターンの比較の後で、ディレクトリ名は、それを終わらせるスラッシュとともに、パターンルールの前提条件パターンとファイル名から生成された前提条件ファイル名に付け加えられます。ディレクトリが無視されるのは、使用する暗黙のルールを見つける目的のときだけであって、そのルールの適用においてではありません。したがって、「e%t」はファイル名 src/eat にマッチし、語幹は「src/a」になります。前提条件がファイル名に変換されるとき、語幹からのディレクトリが先頭に付け加えられ、語幹の残りの部分が「%」に置き換えられます。語幹「src/a」と前提条件パターン「c%r」からは、ファイル名 src/car が得られます。

 パターンルールがあるファイルをビルドするために使えるのは、そのファイル名にマッチするターゲットパターンがあり、かつそのルールのすべての前提条件が存在するか、またはビルドできる場合だけです。あなたが書いたルールは、組み込みのルールより優先されます。ただし、他の暗黙のルールを連鎖させずに満たせるルール(たとえば前提条件がない、あるいは前提条件がすでに存在するか言及されているルール)は、他の暗黙のルールを連鎖させて作らなければならない前提条件を持つルールよりも、常に優先されるという点に注意してください。

 これらの基準を満たすパターンルールが二つ以上ある場合もあります。その場合、make は最も短い語幹を持つルール(つまり、最も限定的にマッチするパターン)を選びます。最も短い語幹を持つパターンルールが複数ある場合、make は makefile の中で最初に見つかったものを選びます。

 このアルゴリズムの結果として、より汎用的なルールよりも、より限定的なルールが優先されます。たとえば:

%.o: %.c
        $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@

%.o : %.f
        $(COMPILE.F) $(OUTPUT_OPTION) $<

lib/%.o: lib/%.c
        $(CC) -fPIC -c $(CFLAGS) $(CPPFLAGS) $< -o $@

 これらのルールがあって、bar.cbar.f の両方が存在するときに bar.o をビルドするよう求められると、make は最初のルールを選び、bar.cbar.o にコンパイルします。同じ状況で bar.c が存在しない場合は、make は二番目のルールを選び、bar.fbar.o にコンパイルします。

 makelib/bar.o をビルドするよう求められ、lib/bar.clib/bar.f の両方が存在する場合は、三番目のルールが選ばれます。なぜなら、このルールの語幹(「bar」)が最初のルールの語幹(「lib/bar」)より短いからです。lib/bar.c が存在しない場合は、三番目のルールは適格ではなくなり、たとえ語幹が長くても二番目のルールが使われます。

10.5.5 何にでもマッチするパターンルール

 パターンルールのターゲットがただの「%」である場合、それは何であれ任意のファイル名にマッチします。私たちはこのようなルールを何にでもマッチする(match-anything)ルールと呼びます。これらは非常に役立ちますが、make がこれらについて検討するのに多くの時間がかかることがあります。なぜなら、ターゲットまたは前提条件として並べられた各ファイル名について、そのようなルールをすべて検討しなければならないからです。

 makefile が foo.c に言及しているとしましょう。このターゲットについて、make はそれを、オブジェクトファイル foo.c.o をリンクして作る、あるいは foo.c.c から C のコンパイルとリンクを一段階で行って作る、あるいは foo.c.p から Pascal のコンパイルとリンクを行って作る、といった、ほかにもたくさんの可能性を検討しなければならなくなります。

 foo.c は C のソースファイルであって実行可能ファイルではないので、これらの可能性がばかげていることは私たちには分かっています。make がこれらの可能性を検討したとしても、foo.c.ofoo.c.p のようなファイルは存在しないので、最終的にはそれらを却下することになります。しかし、これらの可能性は非常に数が多いので、もし make がそれらを検討しなければならないとしたら、make は非常に遅くなってしまうでしょう。

 速度を上げるために、私たちは make が何にでもマッチするルールを検討する方法にさまざまな制約を設けました。適用できる制約は二種類あり、何にでもマッチするルールを定義するたびに、そのルールについてどちらか一方を選ばなければなりません。

 一つの選択肢は、その何にでもマッチするルールを、ダブルコロンで定義することによって終端(terminal)として指定することです。ルールが終端である場合、そのルールはその前提条件が実際に存在しない限り適用されません。他の暗黙のルールで作れる前提条件では不十分です。言い換えれば、終端ルールの先では、それ以上の連鎖は許されません。

 たとえば、RCS ファイルや SCCS ファイルからソースを取り出す組み込みの暗黙のルールは終端です。その結果、ファイル foo.c,v が存在しない場合、make はそれを foo.c,v.oRCS/SCCS/s.foo.c,v からの中間ファイルとして作ろうとすることを検討すらしません。RCS ファイルや SCCS ファイルは、一般に究極のソースファイルであり、他のどのファイルからも作り直されるべきではありません。したがって make は、それらを作り直す方法を探さないことで時間を節約できます。

 何にでもマッチするルールを終端として指定しない場合、それは非終端になります。非終端の何にでもマッチするルールは、暗黙のルールの前提条件には適用できず、また特定の種類のデータを示すファイル名にも適用できません。あるファイル名が特定の種類のデータを示すとは、何にでもマッチしない暗黙のルールのターゲットのいずれかがそれにマッチする場合のことです。

 たとえば、ファイル名 foo.c はパターンルール「%.c : %.y」(Yacc を実行するルール)のターゲットにマッチします。このルールが実際に適用可能かどうか(これは foo.y というファイルがある場合にのみ起こります)に関係なく、そのターゲットがマッチするという事実だけで、ファイル foo.c に対して非終端の何にでもマッチするルールが検討されるのを防ぐには十分です。したがって make は、foo.cfoo.c.ofoo.c.cfoo.c.p などから実行可能ファイルとして作ろうとすることを、検討すらしません。

 この制約の動機は次のとおりです。非終端の何にでもマッチするルールは、特定の種類のデータ(実行可能ファイルなど)を含むファイルを作るために使われ、一方、認識されるサフィックスを持つファイル名は、別の特定の種類のデータ(C ソースファイルなど)を示すものだからです。

 特定のファイル名を認識して、非終端の何にでもマッチするルールが検討されないようにするためだけに、特別な組み込みのダミーパターンルールが用意されています。これらのダミールールは前提条件もレシピも持たず、他のあらゆる目的に対しては無視されます。たとえば、次の組み込みの暗黙のルール

%.p :

は、foo.p のような Pascal ソースファイルが特定のターゲットパターンにマッチするようにし、それによって foo.p.ofoo.p.c を探すのに時間が無駄に費やされるのを防ぐために存在しています。

 「%.p」のためのもののようなダミーパターンルールは、サフィックスルールで使えるとして並べられたすべてのサフィックス(昔ながらのサフィックスルールを参照してください)について作られます。

10.5.6 暗黙のルールの取り消し

 組み込みの暗黙のルール(または自分で定義したルール)は、同じターゲットと前提条件を持ち、別のレシピを持つ新しいパターンルールを定義することで、オーバーライドできます。新しいルールが定義されると、組み込みのルールが置き換えられます。暗黙のルールの並びの中での新しいルールの位置は、その新しいルールをどこに書いたかによって決まります。

 組み込みの暗黙のルールは、同じターゲットと前提条件を持ち、レシピを持たないパターンルールを定義することで取り消すことができます。たとえば、次のものはアセンブラを実行するルールを取り消します:

%.o : %.s

10.6 最後の手段となるデフォルトルールの定義

 前提条件を持たない、終端の何にでもマッチするパターンルールを書くことで、最後の手段となる暗黙のルールを定義できます(何にでもマッチするパターンルールを参照してください)。これは他のどのパターンルールともまったく同じです。唯一特別な点は、それがどんなターゲットにもマッチするということです。そのため、そのようなルールのレシピは、自分自身のレシピを持たず、かつ他のどの暗黙のルールも適用されないすべてのターゲットと前提条件に対して使われます。

 たとえば、makefile をテストするとき、ソースファイルが本物のデータを含んでいるかどうかは気にせず、ただそれらが存在することだけを気にする、ということがあるかもしれません。そのようなときは、次のようにすることができます:

%::
        touch $@

これによって、(前提条件として)必要なすべてのソースファイルが自動的に作られるようにできます。

 その代わりに、ルールがまったくないターゲット——レシピを指定していないものさえ含む——に対して使われるレシピを定義することもできます。これは、ターゲット .DEFAULT に対するルールを書くことで行います。そのようなルールのレシピは、どの明示的なルールのターゲットとしても現れず、かつどの暗黙のルールも適用されないすべての前提条件に対して使われます。当然ながら、自分で書かない限り .DEFAULT ルールは存在しません。

 .DEFAULT をレシピも前提条件もなしで使った場合:

.DEFAULT:

それまで .DEFAULT に蓄えられていたレシピは消去されます。すると make は、.DEFAULT をまったく定義していなかったかのように振る舞います。

 あるターゲットに、何にでもマッチするパターンルールや .DEFAULT からレシピを得てほしくはないが、かといってそのターゲットに対して何のレシピも実行されてほしくない、という場合は、それに空のレシピを与えることができます(空のレシピの定義を参照してください)。

 最後の手段となるルールを使って、別の makefile の一部をオーバーライドすることもできます。別のMakefileの一部をオーバーライドするを参照してください。

10.7 昔ながらのサフィックスルール

 サフィックスルール(suffix rule)は、make の暗黙のルールを定義する昔ながらの方法です。サフィックスルールは時代遅れです。なぜなら、パターンルールのほうがより汎用的で分かりやすいからです。サフィックスルールは、古い makefile との互換性のために GNU make でサポートされています。サフィックスルールには二種類あります。二重サフィックス(double-suffix)と単一サフィックス(single-suffix)です。

 二重サフィックスルールは、サフィックスの組——ターゲットサフィックスとソースサフィックス——によって定義されます。これは、名前がターゲットサフィックスで終わる任意のファイルにマッチします。対応する暗黙の前提条件は、ファイル名のターゲットサフィックスをソースサフィックスで置き換えることで作られます。二サフィックスルール「.c.o」(ターゲットサフィックスとソースサフィックスがそれぞれ「.o」と「.c」)は、パターンルール「%.o : %.c」と等価です。

 単一サフィックスルールは、ソースサフィックスである単一のサフィックスによって定義されます。これは任意のファイル名にマッチし、対応する暗黙の前提条件名は、ソースサフィックスを末尾に付け加えることで作られます。ソースサフィックスが「.c」である単一サフィックスルールは、パターンルール「% : %.c」と等価です。

 サフィックスルールの定義は、各ルールのターゲットを、既知のサフィックスの定義済みリストと照合することによって認識されます。make は、ターゲットが既知のサフィックスであるルールを見つけると、そのルールを単一サフィックスルールとみなします。make は、ターゲットが既知のサフィックスを二つ連結したものであるルールを見つけると、そのルールを二重サフィックスルールとみなします。

 たとえば、「.c」と「.o」はどちらもデフォルトの既知のサフィックスのリストに載っています。したがって、ターゲットが「.c.o」であるルールを定義すると、make はそれを、ソースサフィックスが「.c」、ターゲットサフィックスが「.o」の二重サフィックスルールとみなします。ここに、C ソースファイルをコンパイルするルールを昔ながらの方法で定義したものを示します:

.c.o:
        $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<

 サフィックスルールは、独自の前提条件を持つことはできません。もし前提条件を持つと、それらはサフィックスルールとしてではなく、おかしな名前を持つ通常のファイルとして扱われます。したがって、次のルール:

.c.o: foo.h
        $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<

は、前提条件ファイル foo.h からファイル .c.o をどう作るかを伝えるものであり、次のパターンルール:

%.o: %.c foo.h
        $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<

とはまったく別物です。後者は、「.c」ファイルから「.o」ファイルをどう作るかを伝えると同時に、このパターンルールで作られるすべての「.o」ファイルを foo.h にも依存させます。

 レシピのないサフィックスルールも無意味です。それは、レシピのないパターンルールが以前のルールを取り除く(暗黙のルールの取り消しを参照してください)のとは違って、以前のルールを取り除きません。単に、そのサフィックス、または連結したサフィックスの組を、ターゲットとしてデータベースに登録するだけです。

 既知のサフィックスとは、要するに特別なターゲット .SUFFIXES の前提条件の名前のことです。.SUFFIXES に対して前提条件を追加するルールを書くことで、自分のサフィックスを追加できます。次のようにします:

.SUFFIXES: .hack .win

これは、サフィックスのリストの末尾に「.hack」と「.win」を追加します。

 デフォルトの既知のサフィックスに追加するのではなく、それらを取り除きたい場合は、.SUFFIXES に対して前提条件のないルールを書きます。特別な計らいによって、これは .SUFFIXES の既存の前提条件をすべて取り除きます。その後、別のルールを書いて、欲しいサフィックスを追加できます。たとえば:

.SUFFIXES:            # デフォルトのサフィックスを削除する
.SUFFIXES: .c .o .h   # 自分のサフィックスリストを定義する

 「-r」または「--no-builtin-rules」フラグを使うと、デフォルトのサフィックスのリストが空になります。

 変数 SUFFIXES は、make がどの makefile を読み込むよりも前に、デフォルトのサフィックスのリストに定義されます。特別なターゲット .SUFFIXES に対するルールでサフィックスのリストを変更できますが、それはこの変数を変えるわけではありません。

10.8 暗黙のルールの探索アルゴリズム

 ここに、make がターゲット t に対して暗黙のルールを探索する際の手順を示します。この手順は、レシピを持たない各ダブルコロンルールについて、いずれもレシピを持たない通常のルールの各ターゲットについて、そしてどのルールのターゲットでもない各前提条件について、たどられます。また、暗黙のルールから来た前提条件についても、ルールの連鎖を探す中で再帰的にたどられます。

 このアルゴリズムでサフィックスルールに言及していないのは、サフィックスルールが、makefile が読み込まれた後に等価なパターンルールに変換されるからです。

 「archive(member)」という形のアーカイブメンバターゲットについては、以下のアルゴリズムが二回実行されます。一回目はターゲット名全体 t を使い、一回目でルールが見つからなかった場合は、二回目に「(member)」をターゲット t として使います。

  1. t を、ディレクトリ部分(d と呼ぶ)と残りの部分(n と呼ぶ)に分割します。たとえば t が「src/foo.o」であれば、d は「src/」、n は「foo.o」です。
  2. そのターゲットの一つが t または n にマッチするすべてのパターンルールのリストを作ります。ターゲットパターンがスラッシュを含む場合は t と照合し、そうでなければ n と照合します。
  3. そのリストの中に何にでもマッチするルールでないルールが一つでもある場合、または t が暗黙のルールの前提条件である場合は、リストから非終端の何にでもマッチするルールをすべて取り除きます。
  4. リストから、レシピを持たないルールをすべて取り除きます。
  5. リスト内の各パターンルールについて:
    1. 語幹 s を見つけます。これは、ターゲットパターンの「%」によってマッチした t または n の空でない部分です。
    2. s を「%」に代入することで前提条件名を計算します。ターゲットパターンがスラッシュを含まない場合は、各前提条件名の先頭に d を付け加えます。
    3. すべての前提条件が存在するか、または存在すべきかをテストします。(あるファイル名が、makefile の中でターゲットとして、またはターゲット T の明示的な前提条件として言及されている場合、それは存在すべきであると言います。)

      すべての前提条件が存在するか存在すべきである場合、あるいは前提条件が一つもない場合、このルールが適用されます。

  6. ここまででパターンルールが見つからなかった場合は、もっと頑張ってみます。リスト内の各パターンルールについて:
    1. そのルールが終端である場合は、それを無視して次のルールに進みます。
    2. 前と同じように前提条件名を計算します。
    3. すべての前提条件が存在するか、または存在すべきかをテストします。
    4. 存在しない前提条件のそれぞれについて、このアルゴリズムを再帰的にたどり、その前提条件が暗黙のルールで作れるかどうかを調べます。
    5. すべての前提条件が、存在するか、存在すべきか、または暗黙のルールで作れる場合、このルールが適用されます。
  7. それでもパターンルールが見つからなかった場合は、「存在すべき」の定義を修正して、ステップ 5 とステップ 6 を再度試みます。すなわち、あるファイル名がいずれかのターゲットのターゲットとして、または明示的な前提条件として言及されている場合、それは存在すべきであるとします。このチェックは、GNU Make の古いバージョンとの後方互換性のためだけに存在しています。これに頼ることはおすすめしません。
  8. どの暗黙のルールも適用されない場合は、もし .DEFAULT に対するルールがあれば、それが適用されます。その場合、t には .DEFAULT が持つのと同じレシピが与えられます。そうでなければ、t にはレシピがありません。

 適用されるルールが見つかると、そのルールのうち t または n にマッチしたもの以外の各ターゲットパターンについて、パターン内の「%」が s に置き換えられ、その結果得られるファイル名は、ターゲットファイル t を作り直すレシピが実行されるまで保存されます。レシピが実行された後、これらの保存されたファイル名のそれぞれがデータベースに登録され、更新済みとして、かつファイル t と同じ更新ステータスを持つものとして印が付けられます。

 パターンルールのレシピが t に対して実行されるとき、自動変数はそのターゲットと前提条件に対応して設定されます。自動変数を参照してください。


前へ | 次へ | 目次 | 英語原版(gnu.org)