超初歩的なmakeまとめ
これまでGNU環境で、プログラムを作成するに当たってMakefileが必要になったとき、公開されている既存のものを参考にして、必要な部分のみの修正で事が足りていました。
しかし、1からMakefileを作成するとなると、やはりその基本を抑えておく必要があります。
そこで、いろいろと調べた結果などをまとめたいと思います。
尚、今回使用したmakeのバージョンは GNU Make 3.81 です。
超基本的なMakefile文法解説
Makefileは以下のような構文ブロック(エントリ)から成り立っています。
ターゲット: コンポーネント # 依存関係行/ルール行 <tab>コマンド # コマンド行
- ターゲットに対してコンポーネントは複数指定でき、省略することも可能。
- コンポーネントは、同Makefile中の別のエントリのターゲットを指定することも可能。
- コマンド行は先頭がtabで、ターゲットのためのコマンドラインを記述。
- コマンド行は1エントリ中に複数書く事ができ、省略することも可能。
- ターゲットは複数指定することも可能。
- #以降はコメント
超基本的な動作解説
makeの基本的な動作の流れをつかむため、先の文法に倣い、以下のようなファイルを作成します。
A : C B echo A B : D C : echo C D : echo D
ファイル名をMakefileで保存し、makeを実行すると、
% make -s C D A
と出力されました。(-s は進捗状況出力を抑えます。結果を見やすくするために指定しました)
ポイントは、
- コンポーネントが指定されている場合は、左側のコンポーネントから順次評価される。
- そのコンポーネントが別のエントリのターゲットの場合、構成するコンポーネントを評価…と末尾まで評価されていく。
- make実行時、ターゲットを省略した場合、Makefileの一番上に記述されたエントリのみが評価される。
という点です。
次に、以下のようなMakefileを考えます。
hoge: foo bar cat foo bar > hoge foo: touch foo bar: touch bar
このMakefileに対して立て続けに2回実行してみると、警告を発して終了します。
% make touch foo touch bar cat foo bar > hoge % make make: `hoge' は更新済みです
理由は、ターゲットを評価する時点で、
この両方が成立すると、makeはターゲットを生成しないためです。
試しに以下のように外部からコンポーネントを更新しmakeすると、
% touch foo % make cat foo bar > hoge
上記の条件は成立しなくなるため、最終ターゲットは生成されます。
サフィックスルール
コンパイル/アセンブルを行う際、構築のためのコマンドに対するソースファイルと、その結果となる出力ファイルのサフィックスは、言語によって通例的に決まっています。(C言語で言うならccで.c→.o)
簡単に言ってしまうと、このサフィックスの関係の定義がサフィックスルールです。
入力/出力も含めて、サフィックスルールで登場するサフックスの定義は以下のように行います。
.SUFFIXES: サフィックス サフィックス ...
そして、サフィックスルールはエントリと同じように定義しますが、依存関係行を以下のようにします。
.サフィックス.サフィックス:
出力用の2つ目のサフィックスは省略可能で、その場合、出力ファイルはサフィックスがないものとして扱われます。
また、コンポーネントは指定しても無視されます。
以下のMakefileは実際にサフィックスルールを利用したものです。
.SUFFIXES: .x .y .z dst: src.z mv src.z dst .y.z: cp src.y src.z .x.y: cp src.x src.y src.x: touch src.x
1行目がサフィックスルールで使用するサフィックスの定義、2・3つ目がサフィックスルールを定義したエントリです。
結果は以下のようになります。
% make touch src.x cp src.x src.y cp src.y src.z mv src.z dst rm src.y
依存関係の流れの概要は、
- 最終ターゲットdstはコンポーネントsrc.zに依存しており、
- src.zは2つ目のルール「*.y→*.z」が適用されて、src.yに依存し、
- src.yがターゲットである3つ目のルール「*.x→*.y」が適用され、src.xに依存し、
- srx.xをターゲットとする4つ目のエントリのコマンドから順次処理されていく。
となります。
最後に記述にないrmが実行されていますが、これは、サフィックスルールを適用する過程で生成され、最終的に不要になるコンポーネントをmakeが削除しているためです。
また、サフィックスルールは標準で定義されており(デフォルトルール)、暗黙のうちに適用されるものがあります。
デフォルトルールを確認するにはmake実行時に-pオプションを指定します。
その他特殊ターゲット
その他、makeには特殊なターゲットが用意されています。以下にまとめます。
ターゲット | 効能 |
---|---|
.SILENT: | コマンド行の状況を出力しない。-sと同等。 |
.IGNORE: | コマンド行が失敗しても処理を継続する。 |
.DEFAULT: | Makefileにエントリがなかった場合に評価されるターゲットエントリ。 |
.PRECIOUS:ファイル名 | 指定したファイルをmakeが消去しないようにする。 |
.PHONY:ターゲット | ファイルが不要なターゲットを定義する。 |
.PRECIOUSはサフィックスルールの解説例で、src.yを指定すれば最後に勝手に削除されるのを防止できます。
.PHONYは以下のようなcleanターゲットでよく利用されます。
.PHONY: clean clean: rm *.o
理由は、仮にcleanというファイルが存在した場合、コンポーネントを持たないターゲットとして扱われ、コマンドが実行されません。
そのため、.PHONYによってcleanというターゲットはファイル名ではない事を指示します。
マクロ
Makefile中に環境変数のような感覚で、マクロを利用する事ができます。
マクロを定義する場合の例は以下の通りです。
CORE = main.o low.o PLATFORM = peripheral.o ${CORE} print_objs: echo ${PLATFORM}
定義したマクロを参照する際の{と(はどちらでもOKです。1文字のマクロは括弧不要です。
exportされている環境変数はマクロとして扱う事ができます。
また、以下のようにコマンドラインからマクロを定義する事も可能です。
% MACRO1=macro1 make MACRO2=macro2
makeコマンドの前後どちらでも定義可能ですが、以下の同名マクロの優先順位付けにより意味が異なります。
- makeで定義された標準のマクロ
- 環境変数とコマンドラインのmakeより前に定義されたマクロ(上の例ではMACRO1)
- Makefile中に定義されたマクロ
- コマンドラインのmakeより後に定義されたマクロ(上の例ではMACRO2)
1.の標準で定義されているマクロから、よく使われるものを以下に示します。
マクロ | 効能 | 注意点 |
---|---|---|
$@ | ターゲット名を示す | 依存関係行では$$@ |
$? | 指定されたコンポーネントのうち、ターゲットより新しいもの全てを示す | サフィックスルールでは使用不可 |
$ | ターゲットより後に更新されたコンポーネント名 | サフィックスルールと.DEFAULTエントリのみ使用可 |
$* | $<のサフィックスを除いたもの | サフィックスルールのみ使用可 |
その他、デフォルトで定義されているマクロはオプション-pで確認する事ができます。