GNU make コマンドの使い方を自分用にメモしておく。
なお、十人十色に書かれた「Makefileの書き方」ドキュメントが既に広くWeb上に存在する。
従ってこちらのメモでは、Makefileの細かい部分までメモする事はなく、あくまでも自分用のざっくりとしたリファレンスとして書き付けておく。
特に記述がない場合はCentOS 5.2 の GNU Make 3.81 のmanページを元にしている。その他のUNIX環境やWindowsのmakeについてはそれぞれ独自の機能拡張、あるいはGNU Makeにのみ実装されている機能、などがあると思うので、特に自動定義の変数や拡張子(SUFFIXES)に応じた事前定義のルールについてはそれぞれの環境で、都度manやドキュメントを調べる必要がある。
ファイル名は、Makefile/makefileなどにする。GNU Makeの場合は"-f"オプションで任意のファイル名を指定できるが、"Makefile"という頭大文字で始める場合が多い。
#コメント 変数名 = 値 ターゲット: 依存物 (TAB)コマンド
なお、少なくとも GNU Makeの場合は以下のように";"に続けてコマンドを書く事も出来る。
ターゲット: 依存物; コマンド1 (TAB)コマンド2
バックスラッシュを使う事で、
ただし、シェルスクリプトの途中でバックスラッシュを使う場合は展開されるとどうなるかに注意する必要がある。また Windows の場合はバックスラッシュがディレクトリ区切り文字になるため、パス名部分はそのままバックスラッシュとして使える。ただしその代わりワイルドカード文字が使えなくなる。もしワイルドカード文字による展開機能を使いたい場合は、通常のスラッシュ("/")をディレクトリ区切り文字として使う事。
特にシェルスクリプトが混在している中でのバックスラッシュについては、GNU Makeの本家マニュアルを"backslash"で検索して慎重に確認しつつ使う方が良いだろう。
行頭の"@"は、コマンド行自体は表示しない事を意味する。
sample: @echo "ABCDEFG"
→ "ABCDEFG" とだけ表示される。"echo ABCDEFG"と表示されるわけではない。
行頭の"-"は、実行したコマンドの終了ステータスが0以外の場合も実行を継続する事を意味する。
sample: @echo "cleaning directory start." -$(RM) foobar/* @echo "done."
→ "foobar"ディレクトリが無くとも、"done."まで表示される。
sample: cd ./foobar/ $(RM) abc.txt
上記のような場合、コマンド行が分かれている為 "$(RM) abc.txt" は "./foobar/" 内ではなく、カレントディレクトリ内で実行される。
cdしてその中で何かさせたい場合は、";"で分割して一行に収める。
sample: cd ./foobar/ ; $(RM) abc.txt
またforなどを使った複数行のシェルを実行する場合も、コマンド行を分けずに、バックスラッシュで分割して記述する。
sample: for f in ./html/*.html; do \ cp $$f /opt/foobar/html \ done
".PHONY"ターゲットの依存物に指定したターゲットは、実在のファイルやディレクトリではなく常に更新されたものとして扱われる。また、GNU Makeの場合は暗黙のルール(Implicit Rule)の検索も行われなくなる為、パフォーマンスを向上させる。
具体的には"all"や"install", "clean"などのターゲットを".PHONY"に指定する。
.PHONY: all install clean
これにより、これらのターゲットで設定されているコマンドは「常に」実行されるようになる。もしMakefileと同じディレクトリに"all"や"clean"など同名のファイル・ディレクトリが有っても、それらの更新日時は無視される。
例:
.PHONY: all all: prog1 prog2 prog3 prog1: dep1; touch prog1 prog2: dep2; touch prog2 prog3: dep3; touch prog3 dep1: ; touch dep1 dep2: ; touch dep2 dep3: ; touch dep3
.PHONYの詳細はGNU Make本家ドキュメントを参照。
マクロとも呼ばれる。
$@ : ターゲット名
$< : 依存物の先頭
$^ : そのターゲットで指定されている依存物全て(GNU Makeのみ?)
$$ : "$"それ自体(変数ではないけど一応ここで紹介)
C言語に関連した主要なのを数点メモしておく。括弧内はCentOS 5.2 GNU Make 3.81で確認したデフォルト値。
RM | ファイル削除用コマンド(rm -f) |
CC | Cコンパイラ(cc) |
CPP | Cプリプロセッサ($(CC) -E) |
CXX | C++コンパイラ(g++) |
LD | リンカ(ld) |
CFLAGS | $(CC)に与えるオプション |
CPPFLAGS | $(CPP)に与えるオプション |
CXXFLAGS | $(CXX)に与えるオプション |
LDFLAGS | リンク時に指定するオプション |
他の環境のMakeでも暗黙のルールで使われるかは不明だが、合わせておいた方がメンテもし易いだろう。
make実行時に "変数名=値" 形式でコマンドライン引数で指定する事により、Makefile中の値を上書きできる。
$ more Makefile VAR1=abc all: @echo "VAR1=$(VAR1)"
$ make VAR1=abc $ make VAR1=foo VAR1=foo
暗黙のルール(Implicit Rule)についてはプラットフォーム毎のMake実装依存が大きい為、メモしない。
自分でルール定義をする場合に良く使う基本パターンのみをメモしておく。
.SUFFIXES # 空指定する事により、これ以前に定義されている.SUFFIXESを無効化 .SUFFIXES .c .o # "*.c", "*.o" をsuffixルール対象にする # suffixルール:"*.o" は "*.c" に依存する .c.o: $(CC) $(CFLAGS) -c -o $@ $<
(GNU以外のMakeで実装されているかは不明。)
suffixルールの弱点は、指定したsuffix以外のsuffixファイルを依存物に含める事が出来ない点にある。
.c.o: foo.h $(CC) $(CFLAGS) -c -o $@ $<
上記のようにすると、".c.o"がターゲットになり、"foo.h"が依存物となってしまう。
GNU Makeの場合、パターンルール(pattern rule)を使って以下のように書ける。
%.o: %.c foo.h $(CC) $(CFLAGS) -c -o $@ $<
-f ファイル名 | makefile名を指定 |
-n | 実行するコマンドの表示だけを行い、実際の実行を行わない。 |
-t | コマンドを実行せずにファイルにタッチする(実際にはファイルを変更せず、最新の印を付ける)。このオプションを使うと見かけ上コマンドが実行されたことになり、後で起動する make をだますことができる。 |
以下のML記事にある通り、GNU Makeは様々なMakeから色々と機能を取り込んでいる。中には由来が不明の機能も多数有るようだ。
他のプラットフォームのMakeでも動くようなMakefileを書こうとすると相当苦労しそうである。いっそ、GNU MakeオンリーやそれぞれのプラットフォームのMakeオンリーの書き方にした方が楽かも知れない。