このようにC言語によるプログラム開発はccなどを繰り返し呼び出して行きま す。先程の例を見てもわかるように毎回長い命令を入力するのは面倒です。当 然ですが、こういった要求に答えてくれるツールが用意されています。makeと いいます。makeは指定されたファイルの変更日付を比べて、例えばソースファ イルの方がオブジェクトファイルより新しければコンパイルしてくれます。オ ブジェクトファイルの方が実行可能ファイルより新しければリンクしてくれま す。もちろんこういったファイルの依存関係やコンパイルなどの仕方はある書 式で書かれていなければなりません。その依存関係などの書かれたファイルは 通常makefileもしくはMakefileというなまえにしておきます。makeコマンドは 現在のディレクトリの中にあるmakefileもしくはMakefileという名前のファイ ルを読み込んで実行します。先程の例を考えてみましょう。makefileのなかみ は例えば、
# makefile demo test: main.o mylib.a cc -o test main.o mylib.a mylib.a: sub1.o sub2.o sub3.o ar r mylib.a sub1.o sub2.o sub3.o ranlib mylib.a main.o: main.c cc -c main.c sub1.o: sub1.c cc -c sub1.c sub2.o: sub2.c cc -c sub2.c sub3.o: sub3.c cc -c sub3.c
#で始まる行はコメントです。書かれている順番に意味があります。上の方の 式から評価されて行きます。書式は、
標的ファイル:依存ファイル [依存ファイル...] コマンド ...
標的ファイルの日付が依存ファイルの日付より古いとコマンドが実行されます。 依存ファイルが下の方で標的ファイルになっていると先にそちらが評価実行さ れます。いまの例ではtestとmain.oが比較されますが、次のところでmain.oが main.cと比較されていますからまずmain.oとmain.cが比較されます。main.cが 新しいとコマンドcc -c main.cが実行されます。この結果main.oはtestより新 しくなりますからコマンドcc -o ...が実行されます。このように一番上に実 行可能ファイルを標的にした行を置き、下にそれが必要とするオブジェクトファ イルの作り方を並べます。このコマンドの前には必ずTAB文字が入っていなけ ればなりません。
基本的にはこれでよいのですが、main.oからsub3.oまで同じような記述が続い ています。依存ファイルが.cで標的ファイルが.oですから、cc -cを呼び出す ことは明らかです。実はmakeはそのことを知っていますのでcc -cの行は書く 必要がありません。さらにmain.oの依存ファイルが同じ名前の.cしかありませ んから、main.o: main.cの行も必要ありません。もちろんmain.cが例えばイン クルードファイルなどにも依存する場合は記述する必要はあります。これらは 暗黙の規則と呼ばれ、SUNの場合は/usr/include/makeにあるdefault. mkとい うファイルに記述されています。もし現在のディレクトリにもdefault.mkがあ るときはそちらが優先されます。自分用の暗黙の規則が作れるわけです。
例えばコンパイルの時に自分のホームディレクトリの下のincludeというサブ ディレクトリにあるファイルをインクルードする場合を考えましょう。そのま ま書くと次のようになります。
main.o: main.c cc -c -I/home/iwashi/include main.c sub1.o: sub1.c cc -c -I/home/iwashi/include sub1.c ...
全部の行に絶対パスで-Iオプションを付けました。これでも動くわけですがあ まり格好いいとは言えません。それにもし違うところのファイルをインクルー ドしなければならなくなったときは全部書き直さなければなりません。これは ちょっと大変です。そこでマクロを使います。マクロは別のところで定義でき るシンボルで、実行時に該当する文字列に置き換えられます。依存関係を書く 前に書いておきます。今の例では次のようになります。
INCLUDEMINE = -I/home/iwashi/include ... main.o: main.c cc -c $(INCLUDEMINE) main.c ...
INCLUDEMINEというマクロを勝手に作りました。定義は=を使ってやります。= の右辺が全部値になります。続けて空白をおいて別のオプションを書いても構 いません。呼び出すときには$(に続けてマクロの名前を書いて最後に)を書き ます。マクロの定義の中に別のマクロの参照を書いても構いません。また環境 変数を書くことも出来ます。例えば通常HOMEという環境変数は自分のホームディ レクトリを表わしています。そのことを使えば、
MYINCLUDE = -I$(HOME)/include
という風にも書けます。特にメイクファイルはプログラムを作る処方箋である わけですからソースプログラムと同じくらい重要です。それを計算機毎に書き 換えたりするのは好ましくありません。大きなプログラムのメイクファイルの 場合別の計算機に持っていっても書き換えなくていいようにマクロを考えましょ う。計算機毎にディレクトリ構造は違っているかも知れません。それは環境変 数として定義してメイクファイルの中では参照するだけにします。例えば、環 境変数で
% setenv PROJECTDIR /home1/exp/project
などと定義してmakefileには
PROJECTINCDIR = $(PROJECTDIR)/include PROJECTLIBDIR = $(PROJECTDIR)/lib CPPFLAGS = -I$(PROJECTINCDIR) LDFLAGS = -L$(PROJECTLIBDIR) -lproj
などとします。この場合もしPROJECTDIR環境変数が定義されていないとその部 分が無視されます。注意してください。例えばCPPFLAGSは-I/includeというこ とになってしまいます。
makeには他にも様々な機能が盛り込まれています。実例を先程のdefault.mkで 見てみましょう。以下はdefault.mkの冒頭の一部分です。
# @(#)default.mk 1.21 SMI Copyright 1986 SUFFIXES = .o .c .c~ .cc .cc~ .s .s~ .S .S~ .ln .f .f~ .l .l~ \ .mod .mod~ .sym .def .def~ .r .r~ .y .y~ .h .h~ .sh .sh~ \ .cps .cps~ .SUFFIXES: $(SUFFIXES) # C language section. CC=cc CFLAGS= CPPFLAGS= LINT=lint LINTFLAGS= COMPILE.c=$(CC) $(CFLAGS) $(CPPFLAGS) \ -target $(TARGET_ARCH:-%=%) -c LINK.c=$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) \ -target $(TARGET_ARCH:-%=%) LINT.c=$(LINT) $(LINTFLAGS) $(CPPFLAGS) $(TARGET_ARCH) .c: $(LINK.c) -o $@ $< $(LDLIBS) .c.ln: $(LINT.c) $(OUTPUT_OPTION) -i $< .c.o: $(COMPILE.c) $(OUTPUT_OPTION) $< .c.a: $(COMPILE.c) -o $% $< $(AR) $(ARFLAGS) $@ $% $(RM) $%
ここで=はマクロ定義に使われています。$はマクロの呼出しです。2文字以上
の名前を持ったマクロの呼び出しは$のあと()でくくる必要があります。.c.o:
という標的がありますが、これが.cファイルから.oファイルを作る暗黙の規則
です。そのコマンドに$<
というマクロが使われています。これは暗黙
の規則の中で使われるマクロで依存ファイルの名前として使われます。同様に
$@
は標的ファイル名、$*
が標的のベース名(.cなどを取った残りの部分)
などです。.SUFFIXES:という標的は特殊なもので依存部分にサフィックスと
して使う文字を宣言します。.oや.cはここで宣言されているので暗黙の規則で
使うことができます。
この中でCFLAGSなどのマクロが空白のままになっています。自分のmakefileの 中で例えば
CFLAGS=-I~/include -L~/lib
などを宣言すれば暗黙の規則の中でもこの値が使われます。自分のmakefileの 中で暗黙の規則を定義することももちろんできます。