プログラミングユーティリティ

基本的な機能

make の基本的な処理は、ターゲットファイルが依存するすべてのファイルが存在しており、それらのファイルが最新であることを確認して、ターゲットファイルを更新することです。依存関係の修正後にターゲットファイルが修正されていない場合、ターゲットファイルが再生成されます。make は、依存関係のグラフを検索します。ファイルが最後に修正された日時によって、make が実行する処理が決まります。

make は、以下の情報を使用して処理を実行します。

例として、C 言語のファイルの x.cy.cz.c を数学ライブラリの libm とコンパイルして読み込むことにより作成した、prog という名前のプログラムを説明します。C 言語の規約によって、C 言語のコンパイル出力は、x.oy.oz.o という名前のファイルになります。x.c および y.cdefs.h というファイル中の宣言のいくつかを共有していて、z.c は共有していないとします。この場合は、x.c および y.c に次の行が含まれます。

#include "defs.h"

以下は、ファイルの関係と処理を記述しています。

prog : x.o y.o z.o 
      	cc x.o y.o z.o -lm -o prog 
x.o y.o : defs.h

この情報が makefile という名前のファイルに保存されている場合は、次のコマンドは、x.cy.cz.cdefs.h のいずれかが変更された後に prog を再生成するために必要な処理を実行します。

$ make

前述の例では、最初の行は prog が 3 つの .o ファイルに依存することを示しています。2 行目は、これらのオブジェクトが最新になった後に、それらのオブジェクトを読み込んで prog を作成する方法を示しています。3 番目の行は、x.o および y.o がファイル defs.h に依存することを示しています。make は、ファイルシステムを調べて、必要な .o ファイルに対応する 3 つの .c ファイルがあり、それらの .c ソースファイルからオブジェクトを生成する際に組み込み規則を使用する (つまり cc -c コマンドを実行する) ことを特定します。

このように必要な処理を自動的に特定する make 機能がないとすると、以下のような長い記述ファイルが必要です。

prog : x.o y.o z.o 
      	cc x.o y.o z.o -lm -o prog 
x.o : x.c defs.h 
      	cc -c x.c 
y.o : y.c defs.h 
      	cc -c y.c 
z.o : z.c 
      	cc -c z.c

最後に prog を作成した後に変更されたソースファイルまたはオブジェクトファイルがなく、すべてのファイルが最新である場合は、make コマンドはその旨を表示して停止します。ただし、defs.h ファイルが編集されている場合は、x.c および y.c (z.c を除く) が再コンパイルされ、新しい x.o および y.o と既存の z.o から prog が作成されます。y.c だけが変更されている場合は、y.c だけが再コンパイルされますが、この場合も prog をもう一度読み込む必要があります。make コマンド行でターゲット名が指定されていない場合は、記述ファイルで最初に記述されているターゲットが作成されます。指定されている場合は、そのターゲットが作成されます。以下のコマンドは、x.c または defs.h が変更された場合に、x.o を再生成します。

$ make x.o

プログラミングの際には、ニーモニック名を付けた規則と、そのニーモニック名とは異なる名前のファイルを生成するコマンドを記述し、それらをインクルードするという方法でプログラムを作成しておくと、make のファイル生成とマクロ置換の機能を利用することができます。 (マクロについての詳細は、「記述ファイルと置換」を参照してください)。たとえば、ファイルをコピーするには save エントリ、不要な中間ファイルを削除するには clean などのエントリを記述します。

前述のコマンドを実行した後にファイルが存在している場合は、ファイルの最終変更時間によって先の処理が決定されます。コマンドを実行した後にファイルが存在していない場合は、現在時間によって先の処理が決定されます。

動作が実行された時間を記録するために、長さがゼロのファイルを使用することができます。この方法は、遠隔のアーカイブおよびリストを管理する際に便利です。

依存関係の行とコマンド文字列での置換を行う際には、make のマクロが使用されます。マクロは、コマンド行の引数として定義するか、記述ファイルに記述できます。いずれの場合も、マクロ名の後に = 記号を記述し、その後にマクロが表す内容を続けて記述します。マクロは、$ という記号を名前の最初に付けて呼び出します。1 文字以上の長さのマクロ名は、括弧で囲みます。以下に、有効なマクロ呼び出しの書式を示します。

$(CFLAGS) 
$2 
$(xy) 
$Z 
$(Z)

最後の 2 つは、同一の結果になります。

$*$@$?$< という特殊なマクロは、コマンドの実行中に値を変更します (これらの 4 つのマクロについては、「記述ファイルと置換」で説明しています)。以下の例は、マクロの割り当ておよび使用方法を示しています。

OBJECTS = x.o y.o z.o 
LIBES = -lm 
prog: $(OBJECTS) 
        	cc $(OBJECTS) $(LIBES) -o prog 
...
$ make LIBES="-ll -lm"

このコマンドは、lex (-ll) ライブラリと math (-lm)

ライブラリとともに 3 つのオブジェクトを読み取ります。これは、コマンド行でのマクロ定義が、記述ファイル中の定義を無効にするためです (オペレーティングシステムのコマンドでは、空白文字を含む引数は引用符で囲む必要があります)。

make の使用例として、make コマンドそのものを管理するために使用する記述ファイルを示します。make のコードは、複数の C 言語のソースファイルに対して実行され、yacc の文法を使用します。記述ファイルの内容は、以下のとおりです。

# make コマンドの処理を定義している記述ファイル 

FILES = Makefile defs.h main.c doname.c misc.c ¥ 
        	files.c dosys.c gram.y 
OBJECTS = main.o doname.o misc.o files.o dosys.o gram.o 
LIBES = 
LINT = lint -p 
CFLAGS = -O 
LP = lp 

make: $(OBJECTS) 
        	$(CC) $(CFLAGS) -o make $(OBJECTS) $(LIBES) 
        	@size make 

$(OBJECTS): defs.h 

cleanup: 
        	-rm *.o gram.c 
        	-du 

install: 
        	make 
        	@size make /usr/bin/make 
        	cp make /usr/bin/make && rm make 

lint: dosys.c doname.c files.c main.c misc.c gram.c 
        	$(LINT) dosys.c doname.c files.c main.c misc.c gram.c 

        	# print files that are out-of-date 
        	# with respect to "print" file.  

print: $(FILES) 
        	pr $? | $(LP) 
        	touch print

make プログラムは、各コマンドを実行する前にコマンドを表示します。

ソースファイルと記述ファイルだけが含まれるディレクトリで make コマンドを実行すると、以下のように出力されます。

cc -O -c main.c 
cc -O -c doname.c 
cc -O -c misc.c 
cc -O -c files.c 
cc -O -c dosys.c 
yacc gram.y 
mv y.tab.c gram.c 
cc -O -c gram.c 
cc -o make main.o doname.o misc.o files.o dosys.o gram.o ¥
 13188 + 3348 + 3044 = 19580

最後の行は、size make コマンドの結果表示されたものです。コマンド行そのものの出力は、記述ファイル中で記号 @ が記述されているため、表示されません。