まだ完成途中です
注意: このページの内容には、おそらく多くの間違いがあります。
リンクされているので残しておきますが、利用には注意してください。(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 は
% make
とだけタイプすることで、Makefile を読み込みターゲットの生成を開始する。
このように何も指定せずに make を実行すると、make はその最終目標として
Makefile の一番最初に書かれているターゲットを生成しようとする。
例えば先の Makefile では、make は a.out という
ターゲットを生成しようとする。
生成するターゲットを指定して make を実行するには、
% make sub1.o
のように実行すればよい。この場合、make は Makefile の一番最初に書いてある
ターゲットのかわりに、「sub1.o」というターゲットを生成するにとどめる。
make がデフォルトで読み込むファイルは 「Makefile」 という名前でなければ ならない。しかし、それ以外のファイルを Makefile として利用したい場合は、
% make -f Makefile.unix
のように指定する。これで、make は Makefile.unix というファイルを
Makefile の代わりに使う。
また、make はマクロの定義をシェル引数からでもできる。
% make CC=gcc
とすれば、make の実行時にはあらかじめ CC マクロが定義される。
この値は Makefile 中で定義されているマクロの値よりも優先して使われる。
こうすることで、Makefile を書きかえることなく手軽にいろいろな
状況でファイルを生成することができる。
Make の実行オプションは普通シェルから指定するが、 環境変数 MFLAGS でも指定できる。これは多段 make (make がその中で さらに入れ子となった make を実行すること、多段 make 参照) で、親 make が実行オプションをその子 make に継承するために使う。
Makefile は慣習として、つぎのような構造におおまかに分けられている。
これらをファイルの先頭からだらだらと書いていけばよい。 セミコロン ; などの特別な行末の印は必要ない (ただし 生成コマンドだけは行頭にタブ文字を使う必要があるので注意、 詳しくは 生成規則定義部 を参照)。 コメントは「#」を書くことで始まり、 以下行末までがコメントとみなされる。
行頭から、
マクロ名 = 値のように書く。値の中で、さらに別のマクロを参照してもよい。
例:
CC = gcc
OBJ1 = sub1.c
OBJS = $(OBJ1) sub2.c
ただし、自分自身を参照してはいけない
(例: OBJS = $(OBJS) sub.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 のついたファイルに依存している」
a.out: sub1.o
cc -o $@ sub1.o
.c.o:
cc -c $<
sub1.c: header.h
これは、make が sub1.c → sub1.o の依存関係を知らないからだ。
以下のように書くとうまく動く :
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 $< いつでもこのコマンドを使うこと