まだ完成途中です
注意: このページの内容には、おそらく多くの間違いがあります。
リンクされているので残しておきますが、利用には注意してください。(2008年3月、新山)
ここではおもに make の使い方 と Makefile の書き方について 説明しています。じつは make の種類にはいろいろあり、ここでは GNU make (gmake というコマンド名のこともある) を 対象にしています (BSD の pmake でも基本的な部分は同じですが、 マクロ定義などは違うところもあるので注意してください)。 わかりにくい箇所とか、まちがってる箇所がある場合はメールください。
例えばつぎのような C のソースファイルがあるとして、これらから 最終的に実行可能ファイル a.out を生成する Makefile を書く。
header.h は sub1.c, sub2.c にそれぞれ #include されているものとする :
sub1.c :
/* sub1.c */ #include "header.h" ..
sub2.c :
/* sub2.c */ #include "header.h" ..
a.out は sub1.o と sub2.o (それぞれ sub1.c, sub2.c をコンパイルした オブジェクトファイル) をリンクしてできる実行可能ファイルである。
まず a.out は当然 sub1.c と sub2.c に 依存している。したがって、sub1.c, sub2.c のどちらかが 更新された場合には、a.out を 再コンパイル (この場合はリンク) する必要がある。
さらに sub1.c, sub2.c は両方ヘッダファイル header.h に依存している (なぜなら、両方とも header.h を #include しているから)。 したがって、header.h が更新された場合には、sub1.c, sub2.c ともに再コンパイルする必要がある。 当然、それらの影響を受けて a.out も再度リンクしなければならない。
では以上のような状況で、作業を軽減するための Makefile をかくと どうなるだろうか?
# Makefile 1 (「#」は行末までのコメント) a.out: sub1.o sub2.o # ターゲット a.out の依存ファイルは sub1.o, sub2.o cc -o a.out sub1.o sub2.o # a.out の生成コマンド sub1.o: sub1.c # sub1.o の依存ファイルは sub1.c cc -c sub1.c # sub1.o の生成コマンド sub2.o: sub2.c # sub2.o の依存ファイルは sub2.c cc -c sub2.c # sub2.o の生成コマンド # header.h はコンパイル時に include されるので、実際には何もしなくてよい sub1.c: header.h # sub1.c の依存ファイルは header.h sub2.c: header.h # sub2.c の依存ファイルは header.h
上の例で、header.h は sub1.c, sub2.c 中に #include されているので、 最後の sub1.c と sub2.c のための規則は、 実際には何も行わない。 これらの規則は header.h を修正したときのためにある。 こうしておくと、make は header.h の更新を チェックすることで sub1.c や sub2.c も 更新されたとみなし、sub1.c と sub2.c を 自動的にコンパイルしなおしてくれる。
さて、 上の Makefile には似たような部分がいくつもある。 このためファイルが増えてくると書くのが大変だ (make は ソースファイルの数が何十という レベルのときに真の効果を発揮する)。 そこで「サフィックスルール」を使って、これを短縮してみよう。
# Makefile 2 a.out: sub1.o sub2.o cc -o a.out sub1.o sub2.o # サフィックスルール (.c → .o) .c.o: cc -c $< sub1.o: header.h # 注意: .c ではなく .o が依存している sub2.o: header.h
ここで使われているサフィックスルールは、次のようなことを意味している。
「サフィックス .c のファイルに対しては、これによって make は 「なんとか.o」というファイルが必要で、かつ 「なんとか.c」というファイルがあるときは、 いつもこの生成コマンドを使う。 ここでは先の例と違って sub1.o, sub2.o が header.h に依存していると書かれていることに注意。 これを sub1.c と sub2.c のままにしておくと、 make はうまく動いてくれない。cc -c そのファイル という生成コマンドを使って サフィックス .o のファイルを生成せよ」
この例で、「$<」はマクロの一種である。 マクロとはいわゆる変数のようなもので、これをうまく使うと上の Makefile はさらに短縮できる。
# Makefile 3 # マクロ定義部 CC = cc OBJS = sub1.o sub2.o # 生成規則部 a.out: $(OBJS) # $(OBJS) → "sub1.o sub2.o" $(CC) -o $@ $(OBJS) # $@ → "a.out", $(CC) → "cc" .c.o: $(CC) -c $< sub1.o: header.h sub2.o: header.h
マクロ定義はふつう Makefile の先頭に書く (詳細は、マクロ定義の書き方の項を参照)。 この例では、依存ファイルとコンパイラのコマンドをマクロにすることで、 変更すべき箇所を少なくしている。make を実行するときはコンパイラや コンパイラオプションをいろいろ変えてみることが多いので、 このようにしておくと便利である。生成コマンドの中で使われている 「$@」というマクロは、ターゲット名 (この場合は a.out) に 展開され、「$<」というマクロは、先の例でも述べたように サフィックスルール中でコンパイルすべきファイル名のひとつ (たとえば、サフィックスルールが sub1.c → sub1.o に適用されていたら その場合は sub1.c) に展開される。 このようなマクロを上手に使うのが、かしこい Makefile を書くコツである。
make は
とだけタイプすることで、Makefile を読み込みターゲットの生成を開始する。 このように何も指定せずに make を実行すると、make はその最終目標として Makefile の一番最初に書かれているターゲットを生成しようとする。 例えば先の Makefile では、make は a.out という ターゲットを生成しようとする。 生成するターゲットを指定して make を実行するには、% make
のように実行すればよい。この場合、make は Makefile の一番最初に書いてある ターゲットのかわりに、「sub1.o」というターゲットを生成するにとどめる。% make sub1.o
make がデフォルトで読み込むファイルは 「Makefile」 という名前でなければ ならない。しかし、それ以外のファイルを Makefile として利用したい場合は、
のように指定する。これで、make は Makefile.unix というファイルを Makefile の代わりに使う。% make -f Makefile.unix
また、make はマクロの定義をシェル引数からでもできる。
とすれば、make の実行時にはあらかじめ CC マクロが定義される。 この値は Makefile 中で定義されているマクロの値よりも優先して使われる。 こうすることで、Makefile を書きかえることなく手軽にいろいろな 状況でファイルを生成することができる。% make CC=gcc
Make の実行オプションは普通シェルから指定するが、 環境変数 MFLAGS でも指定できる。これは多段 make (make がその中で さらに入れ子となった make を実行すること、多段 make 参照) で、親 make が実行オプションをその子 make に継承するために使う。
Makefile は慣習として、つぎのような構造におおまかに分けられている。
これらをファイルの先頭からだらだらと書いていけばよい。 セミコロン ; などの特別な行末の印は必要ない (ただし 生成コマンドだけは行頭にタブ文字を使う必要があるので注意、 詳しくは 生成規則定義部 を参照)。 コメントは「#」を書くことで始まり、 以下行末までがコメントとみなされる。
行頭から、
マクロ名 = 値のように書く。値の中で、さらに別のマクロを参照してもよい。
例:
ただし、自分自身を参照してはいけない (例: OBJS = $(OBJS) sub.c はダメ)。また、以下の項にも 書いてあるように、マクロの値はこれだけで決定されるとは限らず、 シェル引数や環境変数の内容によっても影響を受ける。CC = gcc OBJ1 = sub1.c OBJS = $(OBJ1) sub2.c
マクロに入っている値を展開するいちばん基本的なやり方は $(CC) のようにする方法である。こうすれば、 その部分がマクロ CC で定義された文字列 (上の例では gcc)に展開される。make はいくつかのマクロ 展開方法をサポートしている :
例:
a.out: sub1.o cc -o $@ sub1.o
ここで、
$@ → a.out
に展開される。
例:
.c.o: cc -c $<
ここで、make が sub1.c から sub1.o を生成するために
この生成コマンドを実行するならば、
$< → sub1.c
に展開される。
例:
paper.ps: paper.dvi dvips $*
ここで、
$* → paper
に展開される。
例:
a.out: sub1.c sub2.c echo "$? are modified."
ここで、もし sub1.c だけが a.out よりも新しければ
$? → sub1.c
に展開される。
あまり使われないが、以下のようなマクロもある。
VAR = CC CC = gcc ここで、 $($(VAR)) → $(CC) → gcc
OBJS = sub1.o sub2.o sub3.o ここで、 $(OBJS:.o=.c) → sub1.c sub2.c sub3.c
NAMES = aaa bbb ccc ここで、 $(NAMES/*/sub_&.c) → sub_aaa.c sub_bbb.c sub_ccc.c
NAMES = aaa.c bbb.c ccc.c ここで、 $(NAMES/^/sub_) → sub_aaa.c sub_bbb.c sub_ccc.c
NAMES = sub_aaa sub_bbb sub_ccc ここで、 $(NAMES/$/.c) → sub_aaa.c sub_bbb.c sub_ccc.c
ひとつの生成規則はさらに 2つの部分に分かれる。これらは
make は、依存関係を書いた行と生成コマンドを書いた行を 行頭にタブがあるかないかで区別している。したがって、
例 :
a.out: sub1.o sub2.o # 依存関係 cc -o a.out sub1.o sub2.o # 生成コマンド1 strip a.out # 生成コマンド2
しかし、make では 行末を「\」でエスケープすることができるので、 内部的には 1行の依存関係でも見かけは複数行として扱うことができる (これは生成コマンドでも同じである)。
行末をエスケープした例:
a.out: sub1.o \ sub2.o cc -o a.out sub1.o \ sub2.o strip a.out
この場合も機能は上とまったく同じである。
書式 (どちらも必ず行頭から書くこと) :
例 1: (ターゲット a.out は sub1.o, sub2.o という2つのファイルに 依存していることを表す)
a.out: sub1.o sub2.o cc -o a.out sub1.o sub2.o # 生成コマンド
例 2: (べつに依存ファイルはなくてもよい)
logfile: touch logfile # logfile という空のファイルを作成
なお、よく使われる make のコツとして、実際には生成されない ターゲット名をつかったバッチ処理がある。 Makefile の例 を参照。
「サフィックス2 のついたファイルから、ことを表す。つまり、
サフィックス1 のついたファイルを生成できる」
の関係である。これを左右逆に書いてしまうミスに注意。生成元 → 生成先 .サフィックス1.サフィックス2:
注意1: サフィックスルールに期待しすぎないこと。 サフィックスルールは、あくまで 「生成コマンドが省略されたときにこのルールを使用せよ」 というものであり、依存関係の代用にはならない。 つまり、.c.o のサフィックスルールを書いたからといって、
「.o のついたファイルは必ず、と宣言したことにはならない。 サフィックスルールが規定するのは あくまで省略時の生成コマンドだけなのだ。
.c のついたファイルに依存している」
これは、make が sub1.c → sub1.o の依存関係を知らないからだ。 以下のように書くとうまく動く :a.out: sub1.o cc -o $@ sub1.o .c.o: cc -c $< sub1.c: header.h
あるいは、以下のようにする :a.out: sub1.o cc -o $@ sub1.o .c.o: cc -c $< sub1.o: sub1.c sub1.c: sub1.h
a.out: sub1.o cc -o $@ sub1.o .c.o: cc -c $< sub1.o: sub1.h
注意2: サフィックスルールで .c , .o, .h, .a 以外のサフィックスを使う場合は、make がそれを サフィックスであると認識できるように、 あらかじめ Makefile 先頭で次のように定義しておく必要がある :
.SUFFIXES: .tex .dvi .ps .java .class # 新たに追加するサフィックス .tex.dvi: jlatex $< # tex ソースから dvi ファイルを生成 .dvi.ps: dvips $< # dvi ファイルから PostScript ファイルを生成 .java.class: javac $< # java ソースから class ファイルを生成
生成コマンドはただふつうにシェルで実行するコマンドを 書けばよいが、必ず行頭にタブ文字を入れること。
書式 :
例 :
sub1.o: sub1.c # この行は依存関係 cc -c prog.c # この行が生成コマンド ↑↑↑↑ (この空きは TAB キーを押して作ること、スペースを並べてはダメ)
make はそのターゲットの生成コマンドを上から順に一行ずつ実行する。 具体的には生成コマンド一行ごとに make はまずその内容を標準出力へ表示し、 sh (Bourne Shell) を起動し、その行の内容を実行させる。 このとき、Makefile内 で定義されたマクロは環境変数の値として export される。カレントディレクトリは現在 make を実行している ディレクトリになる。
生成コマンドがエラーを発生すると make はそれ以降の生成を中止するが、 このような事態を防止するためには make に -k オプションをつけるか、 以下のような書式を使えばよい :
その他の書式 :
例 :
clean: -rm a.out *.o # 失敗しても make は中断しない ↑↑↑↑ (この空きは TAB キーを押して作ること、スペースを並べてはダメ)
例 :
clean: @rm a.out *.o # このコマンドを表示せずに実行 ↑↑↑↑ (この空きは TAB キーを押して作ること、スペースを並べてはダメ)
生成コマンドを書く際の注意点 :
だめな例 :
a.out: cd dist # sh が 2回起動される cc -o $@ $(OBJS) $(LIBS)
これは、最初の cd と次の cc はそれぞれ別のシェルで実行されている ためである。したがってカレントディレクトリはまた元に戻ってしまう。 次のように cd と cc をひとつのシェルで動かせばうまくいく :
うまくいく例 :
a.out: cd dist; cc -o $@ $(OBJS) $(LIBS)
なお、生成コマンドの改行は \ でエスケープできるため、 見かけは複数行の生成コマンドを書くのに有効である :
複数行に見えるがうまくいく例 :
a.out: cd dist; \ # sh は 1回だけ起動される cc -o $@ $(OBJS) $(LIBS)
ある Makefile 中で、他のファイルの内容を取り込みたいときは include コマンドを使う。
で、その include がある位置にファイルがとり込まれる。 C のプリプロセッサにおける #include などとまったく同じ。include ファイル名
例 :
include subdir/Makefile.macro
Makefile のなかには、その中でさらに他の make を 実行するようになっているものがある。これらはおもにソースツリーの サブディレクトリ中の Makefile を実行するものが多く、これによって プログラムの生成は何回かの make に分けて行われる。 このメリットとしては、サブディレクトリ中のファイルはサブディレクトリの Makefile によって分散化され、Makefile の見通しがすっきりすることが あげられる。ただしこれはあくまできちんとサブディレクトリごとに わかりやすい Makefile を書いたときの話で、書き方がへただと 自分自身をまた make で呼び出したりなど、たいへん読みにくいものに なってしまうこともある。
# Makefile for gserver # マクロ定義 CC = cc CFLAGS = -O LDFLAGS = INCLUDES = -I/usr/local/include -I../libmisc -I. LIBS = -L../libmisc -lmisc -lX11 -lGL -lGLU -lm TARGET = gserver2 OBJS = main.o command.o x11window.o resident.o shape.o \ matrix.o object.o stream.o # 生成規則 all: $(TARGET) test: $(TARGET) ./$(TARGET) -test $(TARGET): $(OBJS) $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) clean: -rm -f $(TARGET) $(OBJS) .nfs* *~ \#* core .c.o: $(CC) $(CFLAGS) $(INCLUDES) -c $< gserver.h: object.h matrix.h gtypes.h command.o: gserver.h main.o: gserver.h matrix.o: matrix.h object.o: object.h resident.o: gserver.h shape.o: gserver.h stream.o: gserver.h x11window.o: gserver.h
# Makefile for java applet hoge .SUFFIXES: .eucjava .java .class TARGET = Hoge all: $(TARGET).class java $(TARGET) run: $(TARGET).class appletviewer $(TARGET).html clean: -rm *.class .eucjava.java: native2ascii -encoding EUCJIS $*.eucjava $*.java .java.class: javac -deprecation $<
# Makefile for thesis TARGET = final FIGS = eps/agent.eps \ eps/broadcast.eps \ eps/jikken.eps \ eps/object1.eps \ eps/planning.eps \ eps/screen.eps \ eps/system.eps LPR = lpr -P$(PRINTER) XDVI = xdvi DVIPS = dvips TEX = jlatex .SUFFIXES: .ps .dvi .tex .eps all: $(TARGET).dvi $(XDVI) $(TARGET).dvi force: clean all print: $(TARGET).ps $(LPR) $(TARGET).ps clean: -rm -f $(TARGET).* .tex.dvi: -rm -f *.aux *.toc *.lot *.lof $(TEX) $< .dvi.ps: $(DVIPS) $< $(TARGET).ps: $(TARGET).dvi $(TARGET).dvi: $(TARGET).tex $(FIGS)
この文書では make のふるまいを説明するのに 以下のような用語を使っています。
Makefile における依存関係の例 :
sub1.o: sub1.c ← 依存関係: 「sub1.o が sub1.c に依存している」 cc -c sub1.c ← 生成コマンド: sub1.c から sub1.o を生成する
詳しくは 依存関係の書き方参照。
Makefile におけるターゲットの例 :
Makefile における依存ファイルの例 :
Makefile における生成コマンドの例 :
詳しくは 依存関係の書き方参照。
Makefile におけるサフィックスルールの例 :
sub1.o: sub1.c
^^^^^^
ターゲット
sub1.o: sub1.c
^^^^^^
依存ファイル
sub1.o: sub1.c ← 依存関係: 「sub1.o が sub1.c に依存している」
cc -c sub1.c ← 生成コマンド: sub1.c から sub1.o を生成する
.c.o: ← 「〜.c」から「〜.o」を生成するときには、
$(CC) -c $< いつでもこのコマンドを使うこと