Movatterモバイル変換


[0]ホーム

URL:


Make と Makefile の説明

まだ完成途中です

back


ここではおもにmake の使い方 とMakefile の書き方について説明しています。じつはmake の種類にはいろいろあり、ここではGNU make (gmake というコマンド名のこともある) を対象にしています (BSD のpmake でも基本的な部分は同じですが、マクロ定義などは違うところもあるので注意してください)。わかりにくい箇所とか、まちがってる箇所がある場合はメールください。


Contents

  1. make はどんなときに使うか
  2. Makefile を作る
  3. make の実行
  4. Makefile の文法リファレンス
  5. 多段make について (未完成)
  6. Makefile の例 (未完成)
  7. 用語説明

1. make はどんなときに使うか


2. Makefile を作る

例えばつぎのような C のソースファイルがあるとして、これらから最終的に実行可能ファイルa.out を生成するMakefile を書く。

header.hsub1.c, sub2.c にそれぞれ#include されているものとする :

sub1.c :

sub2.c :

a.outsub1.osub2.o(それぞれsub1.c,sub2.c をコンパイルしたオブジェクトファイル) をリンクしてできる実行可能ファイルである。

まずa.out は当然sub1.csub2.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) 愚直バージョン 〜

上の例で、header.hsub1.c,sub2.c 中に#includeされているので、最後のsub1.csub2.c のための規則は、実際には何も行わない。これらの規則はheader.h を修正したときのためにある。こうしておくと、makeheader.h の更新をチェックすることでsub1.csub2.c も更新されたとみなし、sub1.csub2.c を自動的にコンパイルしなおしてくれる。

さて、上のMakefile には似たような部分がいくつもある。このためファイルが増えてくると書くのが大変だ(make は ソースファイルの数が何十というレベルのときに真の効果を発揮する)。そこで「サフィックスルール」を使って、これを短縮してみよう。

〜 Makefile の例 (2) サフィックスルールを使用 〜

sub2.o: header.h

ここで使われているサフィックスルールは、次のようなことを意味している。

「サフィックス.c のファイルに対しては、
cc -c そのファイル
という生成コマンドを使って サフィックス.o のファイルを生成せよ」
これによってmake は「なんとか.o」というファイルが必要で、かつ「なんとか.c」というファイルがあるときは、いつもこの生成コマンドを使う。ここでは先の例と違ってsub1.o,sub2.o がheader.h に依存していると書かれていることに注意。これをsub1.csub2.c のままにしておくと、make はうまく動いてくれない。

この例で、「$<」はマクロの一種である。マクロとはいわゆる変数のようなもので、これをうまく使うと上のMakefile はさらに短縮できる。

〜 Makefile の例 (3) サフィックスルール+マクロ使用 〜

マクロ定義はふつうMakefile の先頭に書く(詳細は、マクロ定義の書き方の項を参照)。この例では、依存ファイルとコンパイラのコマンドをマクロにすることで、変更すべき箇所を少なくしている。make を実行するときはコンパイラやコンパイラオプションをいろいろ変えてみることが多いので、このようにしておくと便利である。生成コマンドの中で使われている「$@」というマクロは、ターゲット名 (この場合はa.out) に展開され、「$<」というマクロは、先の例でも述べたようにサフィックスルール中でコンパイルすべきファイル名のひとつ(たとえば、サフィックスルールがsub1.c → sub1.o に適用されていたらその場合はsub1.c) に展開される。このようなマクロを上手に使うのが、かしこいMakefile を書くコツである。


3. make の実行

make は

     % make
とだけタイプすることで、Makefile を読み込みターゲットの生成を開始する。このように何も指定せずにmake を実行すると、make はその最終目標としてMakefile の一番最初に書かれているターゲットを生成しようとする。例えば先のMakefile では、makea.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 の実行オプション

Make の実行オプションは普通シェルから指定するが、環境変数 MFLAGS でも指定できる。これは多段 make (make がその中でさらに入れ子となった make を実行すること、多段 make参照) で、親 make が実行オプションをその子 make に継承するために使う。

-f ファイル名
“Makefile”の代わりに別のファイル名を使う。“-”は標準入力。 また、Makefile 内から別の Makefile を取り込んだりする場合には、 サーチパスが設定できる。 マクロ VPATH は依存ファイルをサーチするパスのリストである。 「:」 で区切って書く。
-n
実行すべき生成コマンド列の表示のみを行い、実際には実行しない。 これは、ある Makefile がどんなことをするのか、前もって 予想したいときに有効。
-s
make は生成コマンドを実行するときに、それを マクロ展開した状態で逐一表示しながら実行する。 このオプションは、実行するコマンドをいちいち表示させないようにする。
-k
make は、生成コマンドを実行したときに、そこでエラーが発生すれば それ以降の生成を中止し、終了する。このオプションをつけると make は 生成コマンドでエラーが発生しても無視して、最後まで規則をやり通す。
-p
make であらかじめ定義されている規則・マクロをすべて展開し表示する。
-t
生成コマンドを何も実行せず、指定されたターゲットを touch する。
-e
make 内で定義されたマクロよりも環境変数の値を優先する。マクロの展開 の項を参照。

4. Makefile の文法リファレンス

Makefile は慣習として、つぎのような構造におおまかに分けられている。

  1. マクロ定義部
  2. 生成規則定義部
  3. 他の Makefile を include する (必要に応じて)

これらをファイルの先頭からだらだらと書いていけばよい。セミコロン ; などの特別な行末の印は必要ない (ただし生成コマンドだけは行頭にタブ文字を使う必要があるので注意、詳しくは生成規則定義部 を参照)。コメントは「#」を書くことで始まり、以下行末までがコメントとみなされる。


マクロ定義部

マクロ定義の書き方

行頭から、

マクロ名 =
のように書く。値の中で、さらに別のマクロを参照してもよい。

例:

       CC     = gcc       OBJ1   = sub1.c       OBJS   = $(OBJ1) sub2.c
ただし、自分自身を参照してはいけない(例:OBJS = $(OBJS) sub.c はダメ)。また、以下の項にも書いてあるように、マクロの値はこれだけで決定されるとは限らず、シェル引数や環境変数の内容によっても影響を受ける。

マクロの展開

マクロに入っている値を展開するいちばん基本的なやり方は$(CC) のようにする方法である。こうすれば、その部分がマクロCC で定義された文字列 (上の例ではgcc)に展開される。make はいくつかのマクロ展開方法をサポートしている :

${マクロ名} あるいは $(マクロ名)
マクロを展開するときの、もっとも一般的な使い方。ただふつうに マクロをその定義で置き換えるだけ。
例:$(CC) → gcc
展開する内容は次のような順序で決められる。
  1. そのマクロが make のシェル引数で指定されていれば、 まずそれ真っ先に使用される。シェル引数からのマクロ定義 参照。
  2. それがない場合、makefile 内で何か値が代入されていれば、 それが使用される。
  3. それもない場合、環境変数に同じ名前のものがあれば、 それがマクロとして使用される。 Makefile の中で別の make を実行する場合、 現在実行中の make はそのマクロに入っている値をすべて 環境変数によって次の make に渡す。そのためにこの機能が 必要となる。多段 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
に展開される。

あまり使われないが、以下のようなマクロもある。

$($(マクロ名))
マクロを 2段階に展開する。 例:
       VAR = CC       CC = gcc       ここで、       $($(VAR)) → $(CC) → gcc
$(マクロ名:文字列1=文字列2)
文字列置換つきマクロ。 マクロを展開するとき、文字列1文字列2 に置換する。 これはよく以下のように用いられる :
       OBJS = sub1.o sub2.o sub3.o       ここで、       $(OBJS:.o=.c) → sub1.c sub2.c sub3.c
$(マクロ名/*/文字列1&文字列2)
文字列追加つきマクロ。 マクロを展開するとき、その展開結果に文字列1文字列2を追加する :
       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
$(マクロ名?文字列1:文字列2)
条件分岐マクロ。 指定したマクロがすでに定義されていれば文字列1 を、 未定義ならば文字列 2 を展開する。

生成規則定義部

ひとつの生成規則はさらに 2つの部分に分かれる。これらは

make は、依存関係を書いた行と生成コマンドを書いた行を行頭にタブがあるかないかで区別している。したがって、

  1. 依存関係は必ず行頭から書かねばならない。
  2. 生成コマンドは必ず行頭にタブ文字 (ASCII コードで 9番の文字、 スペースではダメ) を入れなければならない。
この 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依存ファイル名2
「:」の左辺に書かれたターゲットは、 右辺に書かれたファイルに依存していることを表す。 依存ファイル名がさらに別のターゲットになっていてもよいし、 依存ファイルをひとつも書かなくてもよい。

例 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 の例 を参照。

.サフィックス1.サフィックス2:
サフィックスルールを使う際の、 依存関係の書き方。これは
サフィックス2 のついたファイルから、
 サフィックス1 のついたファイルを生成できる」
ことを表す。つまり、
              生成元 → 生成先       .サフィックス1.サフィックス2:
の関係である。これを左右逆に書いてしまうミスに注意。

注意1: サフィックスルールに期待しすぎないこと。 サフィックスルールは、あくまで 「生成コマンドが省略されたときにこのルールを使用せよ」 というものであり、依存関係の代用にはならない。 つまり、.c.o のサフィックスルールを書いたからといって、

「.o のついたファイルは必ず、
.c のついたファイルに依存している」
と宣言したことにはならない。 サフィックスルールが規定するのは あくまで省略時の生成コマンドだけなのだ。
たとえば以下のような規則では、header.h が更新されても make は sub1.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 オプションをつけるか、以下のような書式を使えばよい :

その他の書式 :

[タブ文字]- 生成コマンド
make はこの生成コマンドがエラー終了しても中断しない。

例 :

       clean:               -rm a.out *.o# 失敗しても make は中断しない       ↑↑↑↑       (この空きは TAB キーを押して作ること、スペースを並べてはダメ)
[タブ文字]@ 生成コマンド
make はこの生成コマンドは標準出力に表示せず実行する。

例 :

       clean:               @rm a.out *.o    # このコマンドを表示せずに実行       ↑↑↑↑       (この空きは TAB キーを押して作ること、スペースを並べてはダメ)

生成コマンドを書く際の注意点 :


他のファイルの内容をとり込む

ある Makefile 中で、他のファイルの内容を取り込みたいときはinclude コマンドを使う。

include ファイル名
で、そのinclude がある位置にファイルがとり込まれる。C のプリプロセッサにおける #include などとまったく同じ。

例 :

include subdir/Makefile.macro

5. 多段 make について

(未完成)

Makefile のなかには、その中でさらに他の make を実行するようになっているものがある。これらはおもにソースツリーのサブディレクトリ中の Makefile を実行するものが多く、これによってプログラムの生成は何回かの make に分けて行われる。このメリットとしては、サブディレクトリ中のファイルはサブディレクトリのMakefile によって分散化され、Makefile の見通しがすっきりすることがあげられる。ただしこれはあくまできちんとサブディレクトリごとにわかりやすい Makefile を書いたときの話で、書き方がへただと自分自身をまた make で呼び出したりなど、たいへん読みにくいものになってしまうこともある。


6. Makefile の例 (新山が書いたもの)

(C で書かれた gserver というプログラムをコンパイルする)

# 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

(Hoge という Java Applet をコンパイルする)

# 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 $<

(図入りの LaTeX ソースをコンパイルし印刷する)

# 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)

7. 用語説明

この文書では make のふるまいを説明するのに以下のような用語を使っています。

Makefile
make の動作を決定するファイル。依存関係が記されており、 make はこのファイルの内容を読んで動作する。この書きようによって、 make にさまざまな動作をさせることができる。なお、ファイル名は ふつう慣例的に「Makefile」とすることに決められている。
依存
「あるファイルをコンパイル(生成)するには、材料となる別の ファイルがなければならない」 といった状況を「ファイルが他のファイルに依存している」という。
依存関係
「どのファイルがどのファイルに依存しているか」を書き出したもの。 Makefile ではこれに加えて、そのファイルを実際に生成するための コマンド (生成コマンド) を書く。

Makefile における依存関係の例 :

       sub1.o: sub1.c    ← 依存関係: 「sub1.o が sub1.c に依存している」               cc -c sub1.c ← 生成コマンド: sub1.c から sub1.o を生成する

詳しくは依存関係の書き方参照。

ターゲット
「あるファイル」を生成したい。このとき、生成の目的であるその 「あるファイル」を「ターゲット」と呼ぶ。

Makefile におけるターゲットの例 :

       sub1.o: sub1.c       ^^^^^^     ターゲット
依存ファイル
「あるファイル」を生成したい。このターゲットを生成するために 必要なファイルのことをそのターゲットの依存ファイルと 呼ぶ。make はこのあるターゲットを生成しようとするとき それらの依存ファイルがないと、まずそれを生成しようとする。

Makefile における依存ファイルの例 :

       sub1.o: sub1.c               ^^^^^^            依存ファイル
生成コマンド
あるターゲットを生成したくて、そのための依存ファイルも 揃っているとする。このとき、それらの依存ファイルから実際に ターゲットをコンパイルなり生成するためのコマンド。

Makefile における生成コマンドの例 :

       sub1.o: sub1.c    ← 依存関係: 「sub1.o が sub1.c に依存している」               cc -c sub1.c ← 生成コマンド: sub1.c から sub1.o を生成する

詳しくは依存関係の書き方参照。

サフィックスルール
生成コマンドを書く際に、いちいち何度も同じようなものを書くのは 面倒くさい。たとえば C のソースファイル「.c」からは必ずいつも オブジェクトファイル「.o」を作るので、依存ファイルのサフィックスが 「.c」で、ターゲットのサフィックスが「.o」だったら自動的にある 生成コマンドを適用してほしい。この 「あるサフィックスに反応して、自動的に生成コマンドを適用するルール」 がサフィックスルールである。このサフィックスルールを一度書いておけば、 あとはそれが適用される依存関係には生成コマンドを省略できる。 しかし、これは依存関係そのものを代用するものではない。 依存関係自体は省略できない。

Makefile におけるサフィックスルールの例 :

       .c.o:               ← 「〜.c」から「〜.o」を生成するときには、               $(CC) -c $<    いつでもこのコマンドを使うこと
更新日時
「あるファイルの更新日時」とは、そのファイルが最後に修正された 日時をいう。
マクロ
Makefile を楽に記述するために使う変数のような機能。

Last Modified: Fri Mar 21 19:59:29 JST 2008Yusuke Shinyama
[8]
ページ先頭

©2009-2025 Movatter.jp