[ < ] [ > ]   [ << ] [] [ >> ]         [冒頭] [目次] [見出し] [ ? ]

3. Makefileの記述

makefileと呼ばれるデータベースを読み取ることによって、 どのように再コンパイルするかの情報をmakeに伝えます。


[ < ] [ > ]   [ << ] [] [ >> ]         [冒頭] [目次] [見出し] [ ? ]

3.1 Makefileに含まれるもの

Makefileは5つの項目を含んでいます。それは、explicit rulesimplicit rulesvariable definitionsdirectivescommentsです。また、ルール、変数とディレクティブについては章の後半で 説明しています。


[ < ] [ > ]   [ << ] [] [ >> ]         [冒頭] [目次] [見出し] [ ? ]

3.2 Makefileの名前のつけ方

デフォルトではmakeはmaefileを探しますが、その際には、‘GNUmakefile’、 ‘makefile’、‘Makefile’の順序で探します。

通常は、makefileを‘makefile’あるいは‘Makefile’としたほうがよく、 こうしておけば、‘README’などの重要なファイルのあるディレクトリの リストの先頭に出てきます。名前のチェックでは、ほとんどの場合 ‘GNUmakefile’は推奨しません。この名前は、とくにGNUのmakeを 使用する場合に用いますが、ほかのバージョンのmakeでは 認識されないでしょう。ほかのmakeプログラムは、‘makefile’あるいは ‘Makefile’は認識しますが、‘GNUmakefile’は認識しません。

もしmakeがこれらのファイルを探し出せなかった場合には、 makefileを用いません。したがって、コマンドの引数でゴールを指定する必要があり、 makeは組み込まれている暗黙のルールにのみ従ってremakeしようとします。 See section 暗黙のルールの使用.。

標準的なmakefile以外の名前を用いたい場合には、‘-f’あるいは ‘--file’オプションをつけてmakefileの名前を指定できます。引数 ‘-f name’あるいは‘--file=name’によって makenameをmakefileだと認識させられます。また、‘-f’ あるいは‘--file’オプションによって、複数のmakefileの指定を行なうことも できます。指定されたすべてのmakefileは順序に従って効果的に連結されます。 また、‘-f’あるいは‘--file’オプションを使用した場合には、 デフォルトの名前である‘GNUmakefile’や‘makefile’や‘Makefile’は 自動的にチェックは行なわれません。


[ < ] [ > ]   [ << ] [] [ >> ]         [冒頭] [目次] [見出し] [ ? ]

3.3 ほかのMakefileをインクルードする

includeディレクティブは、makeに対してmakefileの読み込みを 中断し、1つあるいは複数のほかのmakefileを読み込んでから継続するように 指示します。makefileのなかのディレクティブは以下のようなものです。

 
include filenames

filenamesは、シェルのファイル名のパターンを含むことができます。

行の先頭では、スペースは無視されるのでかまいませんが、タブは許されません。 タブで始まる行はコマンド行と認識されてしまいます。また、includeと ファイル名のあいだには空白が必要で、2つ以上の空白やディレクティブの 終わりの空白は無視されます。行の終わりに‘#’で始まるコメントも 可能です。さらに、ファイル名がなんらかの変数や関数の参照を含んでいる場合には それが展開されます。See section 変数の使用法.。

たとえば、3つの‘.mk’すなわち、‘a.mk’、‘b.mk’、‘c.mk’を 含んでいる場合には、bish bashとともに展開され、以下のようになります。

 
include foo *.mk $(bar)

は、以下と同様です。

 
include foo a.mk b.mk c.mk bish bash

makeincludeディレクティブを処理する際は、makefileの 読み込みを中断し、かわりにリストされたファイルの読み込みを実行します。その後、 makeはディレクティブの現われた箇所に戻り読み込み処理を続けます。

さまざまなディレクトリにある個々のmakefileによって処理されるいくつかの プログラムが変数定義の標準的なセットを必要とする場合にinclude ディレクティブを使用します(see section 変数の設定.、あるいは パターンルールについては see section パターンルールの定義と再定義.)。

また、ソースファイルから必要条件を自動的に生成する場合にもinclude ディレクティブを用います。その場合、必要条件はメインのmakefileに 含まれるようにファイルとして生成されます。この方法は、従来のほかの バージョンのmakeのようにメインのmakefileの最後に追加していく 方法よりもすっきりしています。 See section 必要条件の自動生成.。

もし、指定したファイルの名前がスラッシュで始まるものでない場合や カレントディレクトリにない場合には、いくつかのディレクトリがサーチされます。 その際に、まず‘-I’あるいは‘--include-dir’で指定されたディレクトリが サーチされ(see section オプションのサマリー.)、 次に(存在する場合には)以下のディレクトリがサーチされます。 ‘prefix/include’(普通は‘/usr/local/include’ ですが、MS-DOSとMS-Windowsの場合は、DJGPPツリー階層のルートディレクトリ であるようにGNUのMakeはコンパイルを行ないます)、 ‘/usr/gnu/include’、‘/usr/local/include’、 ‘/usr/include’。

もし、含まれているmakefileがどのディレクトリでもみつからない場合には、 警告メッセージが生成されますが、これはすぐに致命的なエラーということではなく、 includeを含むmakefileの処理は継続します。そして、makefileの 読み込みが終了するとmakeは期限切れや存在しないファイルを 再構成しようとします。See section Makefileの作られ方.。 ただし、makefile自体を変更しようとする方法をみつけた場合には再構成は 失敗します。そして致命的なエラーとして、makefileの存在を診断しようとします。

存在しないため、変更しようのないmakefileをエラーメッセージなしに単純に 無視する場合には、以下のようにincludeディレクティブのかわりに -includeを使用してください。

 
-include filenames

filenameがまったく存在せず、エラーがないという場合を除けば、 この動作はincludeによく似ています。これはほかのmake インプリメンテーションとの互換性のためで、 sinclude-includeの別名となっています。


[ < ] [ > ]   [ << ] [] [ >> ]         [冒頭] [目次] [見出し] [ ? ]

3.4 MAKEFILESの変数

環境変数MAKEFILESが定義されている場合には、makeはその変数を、 先行して読み込むmakefileの名前のリスト(空白で区切られた)と みなします。この動作はincludeディレクティブとたいへん似ていて、 さまざまなディレクトリをサーチします (see section ほかのMakefileをインクルードする.)。さらに、デフォルトの ゴールはこれらのmakefileから得られることはなく、MAKEFILESに リストされたファイルが、たとえみつからない場合でもエラーとなることは ありません。

MAKEFILESの主な用途は、makeの再帰的な呼び出しの際の通信です。 (see section makeの再帰的用法.)通常は、トップレベルの makeの呼び出しのまえに環境変数を設定することは好ましくありません。 なぜなら、外部からmakefileに対して干渉しないことがよいからです。しかし ながら、makefileを指定せずにmakeを実行する場合には、 MAKEFILESのなかのmakefileは組み込まれた暗黙のルールが定義された サーチパスよりもうまく機能します (see section 必要条件のためのディレクトリサーチ.)。

ユーザーによっては、ログイン時に自動的にMAKEFILESを環境に設定して、 このような動作をするように設定したがりますが、これはよくないアイデアと いえます。なぜなら、異なるユーザーによって実行された場合には 失敗してしまうからです。したがって、明示的にincludeディレクティブを 記述するほうがずっとよいのです。 See section ほかのMakefileをインクルードする.。


[ < ] [ > ]   [ << ] [] [ >> ]         [冒頭] [目次] [見出し] [ ? ]

3.5 Makefileの作られ方

makefileはRCSやSCCSファイルから作られる場合があります。このようにほかの ファイルからmakefileが作られる場合には、makeが最新のバージョンの makefileを読み込むことが期待されます。

すべてのmakefileを読み込んだあと、makeはそれぞれをゴールのターゲットと みなし、アップデートしようと試みます。あるmakefileがその(まさにその makefileまたは別のmakefile)アップデートの方法についてのルールを持つ場合 (see section 暗黙のルールの使用.)、あるいは暗黙のルールを 持つ場合には必要に応じてアップデートされるでしょう。すべてのmakefileが チェックされたあと、なんらかの変更が行なわれた場合には、makeは クリーン動作を行ないすべてのmakefileの読み込みをふたたび開始します。 (それぞれのアップデートもふたたび試みられますが、通常はアップデートされている はずなので、再度変更を加えることはしません。)

1つあるいは複数のmakefileが変更できないことを知っていて、しかも暗黙の ルールのサーチをmakeにさせないようにしたい場合、おそらくその理由は 効率の問題で、暗黙のルールのルックアップは通常の方法で防止することができます。 たとえば、明示的なルールをターゲットとしてmakefileに記述し、 空のコマンド文字列を書いておけばよいのです (see section 空のコマンドの使用.)。

必要条件ではなく、命令でファイルを変更するために2つのコロンのルールを makefileで指定する場合には、ファイルはつねに変更されます (see section ダブルコロンルール.)。つまり、命令と2つのコロンの ついた必要条件でないルールはmakeが実行されるたびに実行され、 ふたたびmakeが実行される際に再度読み込みも行なわれます。 これは無限ループを引き起こします。makeはつねにmakefileを変更しようと 試み、ほかに何もしないことになります。したがって、これを避けるために、 命令と2つのコロンのついた必要条件でないルールのターゲットとして指定された makefileについてはmakeは変更しようとしません。

-f’や‘--file’オプションでmakefileを何も指定しない場合は、 makeはデフォルトの名前のmakefileを試します (see section Makefileの名前のつけ方.)。 ‘-f’や‘--file’オプションで明示的に要求されたmakefileと異なり、 makeはファイルの存在をあてにしません。しかしながら、デフォルトの makefileが存在せず、かつmakeの実行によって生成される場合には、 makefileが使用されるようにルールの実行が行なわれたほうがよいことになります。

したがって、もしデフォルトのmakefileが存在しない場合には、makeは サーチされる順序でそれを生成しようとしますが (see section Makefileの名前のつけ方.)、サーチする 名前を使い果たしてしまいます。注意しなければならないのは、makeが makefileをサーチあるいは生成できなかったとしてもこれはエラーとはなりません。 なぜなら、makefileがつねに必要というわけではないからです。

-t’あるいは‘--touch’オプション (see section コマンド実行の代替.)を 使用する際には、どのターゲットにtouchするかを決定するために期限切れの makefileを使用したいとは考えないはずです。したがって、‘-t’オプションは makefileのアップデートには何の効果も与えません。同様に、‘-q’ (あるいは‘--question’)や‘-n’ (あるいは‘--just-print’) オプションは、makefileのアップデートを妨げません。 なぜなら期限切れのmakefileはほかのターゲットに対して誤った出力を 行なってしまうからです。したがって、‘make -f mfile -n foo’は‘mfile’を アップデートし、それを読み込みます。そして実行することなしに、命令を出力して ‘foo’と必要条件をアップデートします。‘foo’に出力された命令は、 ‘mfile’のアップデートされた内容において指定されたものです。

しかしながら、ときにはmakefileのアップデートを止めたいと考えることも あるかもしれません。その場合、makefileのなかで行なうようにmakefile自体を ゴールに指定することで、実現できます。明示的なゴールとしてmakefileが 指定されている場合には、‘-t’などのオプションが適用されます。

したがって、‘make -f mfile -n mfile foo’はmakefile ‘mfile’を読み込み 実際に実行することはせずに、アップデートに必要な命令を出力します。そして、 ‘foo’のアップデートに必要な命令も出力します。‘foo’に対する命令は ‘mfile’の実際の内容によって指定されたものとなります。


[ < ] [ > ]   [ << ] [] [ >> ]         [冒頭] [目次] [見出し] [ ? ]

3.6 ほかのMakefileの部分的なオーバーライド

まれに、もう1つほとんど同じmakefileを持つことが有益な場合があります。 その場合、‘include’ディレクティブによってもう一方をインクルードするように します。そして、より多くのターゲットあるいは変数定義を付け加えます。しかし、 同じターゲットに対して2つのmakefileが異なる命令を与える場合にはmakeは この方法は用いることができません。この場合には別の方法があります。

他方をインクルードしようとするmakefileにおいては、そのmakefileに含まれる 内容から導けないどんなターゲットでも再構成できる何にでもマッチする パターンルールを使用することができ、makeは他方のmakefileを 読み取ることになります。パターンルールについては、 See section パターンルールの定義と再定義.。

たとえば、ターゲット‘foo’をmakeするための‘Makefile’があるとして、 もう1つ別の‘GNUmakefile’を作ることができ、その中身は、 以下のようにします。

 
foo:
        frobnicate > foo

%: force
        @$(MAKE) -f Makefile $@
force: ;

make foo’とした場合、makeは‘GNUmakefile’をみつけだし、 それを読み‘foo’をmakeしようとします。そしてコマンド ‘frobnicate > foo’を実行しようとします。また、‘make bar’とした 場合には、makeは‘GNUmakefile’のなかで‘bar’をmakeする方法を みつけられません。つまりここでは、‘make -f Makefile bar’という パターンルールを使おうとしたからです。もし‘Makefile’が‘bar’を アップデートするルールを提供するならば、makeはそれを適用します。 ‘GNUmakefile’がどのようにmakeするかを指示しないあらゆるターゲットに 対しても同様です。

この動作は、‘%’だけのパターンを持つパターンルールによります。‘%’は あらゆるターゲットにマッチします。たとえターゲットファイルがすでに 存在していても命令の実行を保証するために、ルールは‘force’という 必要条件を指定します。makeが暗黙のルールをサーチしないように空の 命令を‘force’ターゲットに与えます。そうしないと同一の何にでもマッチする ルールを‘force’に適用してしまい、必要条件のループを生成してしまいます。


[ < ] [ > ]   [ << ] [] [ >> ]         [冒頭] [目次] [見出し] [ ? ]

3.7 makeはどのようにMakefileを解釈するか

GNUのmakeは2つの異なったフェーズで仕事を行ないます。最初のフェーズでは、 すべてのmakefileを読み、makefileのインクルードを行ないすべての変数と値を内部の 値として持ち、暗黙および明示的なルールおよびすべてのターゲットと その必要条件の依存状態のグラフを構築します。次のフェーズでは、 どのターゲットが再構築される必要があり、ルールの適用が必要なのかを 決定するためにmakeは内部構造を使用します。

この2段階のアプローチを理解しておくのが重要なのは、変数と関数の展開による 直接的な影響があるからです。このことはしばしばmakefileを記述する際の混乱の もとになります。ここでは、makefileのなかの異なる構成に対する展開における2つの 段階の要約を示します。最初のフェーズで展開が行なわれる場合を immediateといい、この場合はmakeは構文解析されたmakefileとして 構成のセクションの部分にすべての変数と関数を展開します。また、展開がただちに 行なわれない場合をdeferredといい、即時の文脈のなかでその構成が出現しない 限り実行されることはなく、そうでない場合は2番目のフェーズで実行されることに なります。

読者はこの構成(物)に関してはまだ詳しくはないかもしれませんが、あとの章を 読み詳しくなるに従ってこの章を参照するとよいでしょう。

変数の割り当て

変数の定義は以下のように構文解析されます。

 
immediate = deferred
immediate ?= deferred
immediate := immediate
immediate += deferred or immediate

define immediate
  deferred
endef

+=’は付加オペレーターで、以前に変数が単純変数としてセット (‘:=’)されていてdeferredでない場合には、オペレーターの右側は immediateであるとみなされます。

条件付きのシンタックス

条件付きのすべてのインスタンスはただちに全体として構文解析され、これには ifdefifeqifndefifneq形式が含まれます。

ルールの定義

ルールは形式を問わず、つねに同じ方法で展開されます。

 
immediate : immediate ; deferred
	deferred

つまり、ターゲットと必要条件であるセクションはただちに展開されて、ターゲットを 構成するための命令はつねにdeferredとなります。この一般的なルールは明示的な ルール、パターンルール、サフィックスルール、静的なパターンルールと単純な 必要条件の定義に対してあてはまります。


[ << ] [ >> ]           [冒頭] [目次] [見出し] [ ? ]

この文書は新堂 安孝によって2009年9月22日texi2html 1.82を用いて生成されました。