次の例のメークファイルは、アセンブリ言語のルーチンとリンクした C プログラムを管理します。アセンブリのソースファイルには、cpp プリプロセッサ指令を含むものと含まないものの 2 種類あります。
慣例として、プリプロセッサ指令を含まないアセンブリのソースファイルには .s という接尾辞が付きます。プリプロセッサ処理が必要なアセンブリのソースには、.S という接尾辞が付きます。
ASFLAGS は、.s.o および .S.o の暗黙の規則に関するオプションを渡します。
アセンブリのソースは、C ソースをコンパイルするのと同様の方法でアセンブルされてオブジェクトファイルを形成します。そのオブジェクトファイルは、C プログラムにリンクできます。make には、.s および .S のファイルをオブジェクトファイルに変換するための暗黙の規則があるため、アセンブリのルーチンを持つ C プログラムのターゲットエントリでは、オブジェクトファイルのリンク方法を指定するだけです。アセンブラによって生成されたオブジェクトファイルをリンクするには、cc コマンドを使用できます。
表 4-18 アセンブルソースファイルから C プログラムを生成するメークファイル
CFLAGS= -O ASFLAGS= -O .KEEP_STATE: driver: c_driver.o s_routines.o S_routines.o cc -o driver c_driver.o s_routines.o S_routines.o |
.S ファイルは、cc コマンドを使用して処理されます。cc コマンドは、C のプリプロセッサ cpp およびアセンブラを呼び出します。
lex および yacc は、C ソースファイルを出力します。lex および yacc のソースファイルは、接尾辞がそれぞれ .l、.y になります。lex および yacc のソースファイルを別々にコンパイルする場合のコンパイル処理は、C ソースだけからプログラムを生成する場合と同様です。
lex または yacc のソースを .c ファイルにコンパイルする暗黙の規則があります。.c ファイルは、C ソースからオブジェクトファイルをコンパイルする暗黙の規則を使用してさらに処理されます。ソースファイルに #include 文が含まれていない場合は、.c ファイルは中間ファイルとして使用されるため、保存しておく必要はありません。この場合は、.l.o の規則または .y.o の規則を使用してオブジェクトファイルを生成し、(派生した) .c ファイルを削除できます。
以下にメークファイルの例を示します。
CFLAGS= -O .KEEP_STATE: all: scanner parser scanner: scanner.o parser: parser.o
このメークファイルの結果は、以下のようになります。
$ make -n rm -f scanner.c lex -t scanner.l > scanner.c cc -O -c -o scanner.o scanner.c rm -f scanner.c yacc parser.y cc -O -c -o parser.o y.tab.c rm -f y.tab.c
lex と yacc を組み合わせて使用する場合は、より複雑になります。オブジェクトファイルが正しく機能するには、lex の C コードに yacc が生成したヘッダーが含まれている必要があります。yacc のソースファイルが変更されたときは、lex が生成した C ソースファイルを再コンパイルする必要があります。この場合は、yacc のソースが変更されるごとに lex を実行しなくてもよいように、lex が生成した中間 (.c) ファイルと、yacc が生成した .h ファイルを保存しておきます。
yacc は、y.tab.c と y.tab.h という名前の出力ファイルを生成します。出力ファイルのベース名をソースファイルと同じにしたい場合には、出力ファイルの名前を変更してください。
以下のメークファイルは、lex のソース、yacc のソース、C ソースファイルから構築したプログラムを管理します。
CFLAGS= -O .KEEP_STATE: a2z: c_functions.o scanner.o parser.o cc -o $@ c_functions.o scanner.o parser.o scanner.c: parser.c + parser.h: parser.y yacc -d parser.y mv y.tab.c parser.c mv y.tab.h parser.h
前述のように、複数の暗黙の規則の橋渡しをする規則は生成されないので、scanner.c のターゲットエントリを指定する必要があります。このエントリは、.l.c と .c.o の暗黙の規則の橋渡しをして scanner.o の依存関係リストから scanner.l を生成します。ターゲットエントリには規則がないため、暗黙の規則 .l.c を使用して scanner.c が構築されます。
次のターゲットエントリは、yacc の中間ファイルを生成する方法を指定しています。yacc -d を使用してヘッダーと C ソースファイルの両方を生成する暗黙の規則はないため、これを行う規則を指定するターゲットを記述する必要があります。
parser.c と parser.h のターゲットエントリにおいて、ターゲット名を区切る + 記号は、そのエントリがターゲットグループのエントリであることを示します。ターゲットグループとは複数のファイルの集まりで、それらすべてのファイルは規則の実行時に生成されます。 1 つのターゲットを構成している複数のファイルを、 1 つのグループとして扱います。+ 記号がない場合は、リスト中の各項目は独立したターゲットになります。ターゲットグループを使用すると、make は各ターゲットファイルについて別々に変更日時を調べ、ターゲットの規則は、make の実行 1 回につき必要な場合に 1 度だけ実行されます。