まだ完成途中です
ここではおもにmake の使い方 とMakefile の書き方について説明しています。じつはmake の種類にはいろいろあり、ここではGNU make (gmake というコマンド名のこともある) を対象にしています (BSD のpmake でも基本的な部分は同じですが、マクロ定義などは違うところもあるので注意してください)。わかりにくい箇所とか、まちがってる箇所がある場合はメールください。
例えばつぎのような C のソースファイルがあるとして、これらから最終的に実行可能ファイルa.out を生成するMakefile を書く。
header.h はsub1.c, sub2.c にそれぞれ#include されているものとする :
sub1.c :
sub2.c :
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 をかくとどうなるだろうか?
上の例で、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 は ソースファイルの数が何十というレベルのときに真の効果を発揮する)。そこで「サフィックスルール」を使って、これを短縮してみよう。
sub2.o: header.h
ここで使われているサフィックスルールは、次のようなことを意味している。
「サフィックス.c のファイルに対しては、これによってmake は「なんとか.o」というファイルが必要で、かつ「なんとか.c」というファイルがあるときは、いつもこの生成コマンドを使う。ここでは先の例と違ってsub1.o,sub2.o がheader.h に依存していると書かれていることに注意。これをsub1.c とsub2.c のままにしておくと、make はうまく動いてくれない。cc -c そのファイル という生成コマンドを使って サフィックス.o のファイルを生成せよ」
この例で、「$<」はマクロの一種である。マクロとはいわゆる変数のようなもので、これをうまく使うと上のMakefile はさらに短縮できる。
マクロ定義はふつう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= ccCFLAGS= -OLDFLAGS=INCLUDES = -I/usr/local/include -I../libmisc -I.LIBS= -L../libmisc -lmisc -lX11 -lGL -lGLU -lmTARGET= gserver2OBJS= 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.hcommand.o: gserver.hmain.o: gserver.hmatrix.o: matrix.hobject.o: object.hresident.o: gserver.hshape.o: gserver.hstream.o: gserver.hx11window.o: gserver.h
# Makefile for java applet hoge.SUFFIXES: .eucjava .java .classTARGET= Hogeall:$(TARGET).classjava $(TARGET)run:$(TARGET).classappletviewer $(TARGET).htmlclean:-rm *.class.eucjava.java:native2ascii -encoding EUCJIS $*.eucjava $*.java.java.class:javac -deprecation $<
# Makefile for thesisTARGET= finalFIGS= eps/agent.eps \ eps/broadcast.eps \ eps/jikken.eps \ eps/object1.eps \ eps/planning.eps \ eps/screen.eps \ eps/system.epsLPR= lpr -P$(PRINTER)XDVI= xdviDVIPS= dvipsTEX= jlatex.SUFFIXES: .ps .dvi .tex .epsall:$(TARGET).dvi$(XDVI) $(TARGET).dviforce:clean allprint:$(TARGET).ps$(LPR) $(TARGET).psclean:-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 $< いつでもこのコマンドを使うこと