makeはMakefileで動作を指定する

前回、複数のCのソースコードファイルをビルドするためにmakeを使う方法を説明した。makeはファイルの依存関係などに基づいて処理を行うためのツールで、複数のファイルをビルドする必要がある場合なんかに便利なツールだ。

makeがどのように振舞えばよいかは、Makefileというファイルに記述することになっている。前回は次のようなMakefileを用意して使用した(今回の説明に合わせたいので、ちょっとだけ変更してある)。

前回用意したMakefile

OBJS=   csv2tsv.o util.o
CMD=    csv2tsv.exe

CFLAGS+=-g

CC= clang

build: $(CMD)

$(CMD): $(OBJS)
    $(CC) $(CFLAGS) -o $(CMD) $(OBJS)

csv2tsv.o: csv2tsv.c
    $(CC) $(CFLAGS) -c csv2tsv.c -o csv2tsv.o

util.o: util.c
    $(CC) $(CFLAGS) -c util.c -o util.o

clean:
    rm -f "$(CMD)"
    rm -f *.o
    rm -f *.ilk
    rm -f *.pdb
  • makeコマンドの実行サンプル

    makeコマンドの実行サンプル

Makefileの書き方は基本的には「GNU make」の内容に従ってもらえればよい。しかし、このドキュメントはかなり長く、makeを使い始めの段階で全部読むのは困難だろう。そこで、今回はMakefile (GNU make向け)を使うための基本的な方法をピックアップして説明する。最低限、これくらいは把握しておけば、初めのうちは問題なく使えはずだ。

Makefile:変数

まずは変数を覚えよう。Makefileではファイルであるとかコマンドであるとか、開発中に数が増えたりプラットフォームが変わると指定が変わるものなんかを、直接書くのではなく変数に書くといった使い方をすることが多い。

次の行を見てみよう。

変数の使用サンプルその1

CC= clang

上記のような書き方をすると、$(CC)という書き方でclangが展開され使われるようになる。コンパイラはプラットフォームごとに異なる。clangではなくccかもしれないし、gccかもしれない。Makefileの中に直接clangやccと書くのではなく、コンパイラコマンドを$(CC)でアクセスできるようにしておけば、「CC= clang」と書いてある行を「CC= cc」とか「CC= gcc」とかに書き換えれば対応できるのだ。

変数は次のように複数のファイルを書いておく場合なんかもよく使われる。

変数の使用サンプルその2

OBJS=   csv2tsv.o util.o

開発中にファイルが増えた場合、変数にファイルを追加すれば、そのファイルも同じように処理が行われるというわけだ。

「CFLAGS+=-g」はコンパイラに指定するオプションを指定しているわけだが、コンパイラオプションを変数に指定しておくのもよくやる書き方だ。

どこまで変数にまとめるかは人によると思うが、なるべく見やすく、あとから見たときに何をしようとしていたのかその意図がわかるように整理するために変数を使えるようになったら素晴らしい。

Makefile:依存関係

次は、依存関係を知っておこう。次のように書いてある行を見てみよう。

依存関係が記述された行

csv2tsv.o: csv2tsv.c

この行は、「csv2tsv.oというファイルがcsv2tsv.cに依存している」ということを述べている。csv2tsv.oはcsv2tsv.cをコンパイルして得られるオブジェクトファイルなので、この依存関係は当然というか、C言語の場合にはよくある依存関係ということになる。

この場合、csv2tsv.oが必要になるとcsv2tsv.cをチェックする。csv2tsv.oとcsv2tsv.cのタイムスタンプをチェックし、csv2tsv.oがcsv2tsv.cよりも新しければなにもしない。逆に、csv2tsv.oがcsv2tsv.cよりも古ければ、この行に続く行を実行する。csv2tsv.oがcsv2tsv.cよりも古いということは、csv2tsv.oを生成したあとでcsv2tsv.cが更新されたことを意味しているからだ。

依存関係が記述された行と、その実行内容

csv2tsv.o: csv2tsv.c
    $(CC) $(CFLAGS) -c csv2tsv.c -o csv2tsv.o

依存関係に続く行は、どれもタブから始まらなければならないという決まりがある。タブから始まった連続する行が、処理に必要となる一連のコマンドとして認識される仕組みになっている。

先ほどのMakefileの記述は変数を元の値に書き換えれば次のようになる。

依存関係が記述された行と、その実行内容

csv2tsv.o: csv2tsv.c
    clang -g -c csv2tsv.c -o csv2tsv.o

この書き方で、「csv2tsv.cが更新されたら、clang -g -c csv2tsv.c -o csv2tsv.oを実行よせ」という指定になるわけだ。