Makefile は簡潔に書きましょう

仕組みが判ってしまえば Makefile は簡潔に書けます.$(CC) とか $@ とか $< なんて変数は使ったら負けです.

基本(その1)

ソースコード hoge.c から 実行形式のバイナリ hoge を生成するMakefileは,以下のように書きましょう

all: hoge

これだけです.これで

 $ make all

とすると hoge が生成されます

重要な点は,間違っても

all: hoge
hoge: hoge.c
    $(CC) hoge.c -o hoge

のようなMakefileを書かないことです.このようなMakefileでは

#!/bin/sh
CC=gcc
$CC  hoge.c -o hoge

というようなシェルスクリプトと同程度の使い勝手しかありません.

基本(その2)

ここで例えば-O3 を付けてコンパイルしたい場合や,-lm を付けてリンクしたい場合は以下のようにします.

CFLAGS += -O3
LDFLAGS += -lm
all: hoge

基本(その3)

ソースコードhoge.c と fuga.c に分割している場合,つまり

場合は Makefile は以下のようになります

all: hoge
hoge: hoge.o fuga.o

基本(その4)

一時的に -Wall を付けてコンパイルしたい場合などは, Makefile を書き換えずに

 $ make CFLAGS=-Wall

とすることも出来ます.同様にたとえばコンパイラgcc から gcc-3.1 に替えたい時も

 $ make CC=gcc-3.1

と出来ます.

毎回引数を与えるのが面倒な場合は,環境変数で設定することも出来ます.

 $ export CC=gcc-3.1
 $ make

なぜこのような簡潔なmakefileで ビルドできるのか?それを理解するためには make の動作原理を理解する必要があります.動作原理については次のアーティクルをご覧下さいhttp://d.hatena.ne.jp/pyopyopyo/20070218/p2

また以下の本を読むこともおすすめします.

GNU Make
GNU Make
posted with amazlet at 09.01.10
ロバート メクレンバーグ
オライリージャパン
売り上げランキング: 91882
おすすめ度の平均: 5.0
5 どのファイルをコンパイルするかを指定する道具

make 改訂版
make 改訂版
posted with amazlet at 09.01.10
アンドリュー オラム スティーブ タルボット
オライリー・ジャパン
売り上げランキング: 130044
おすすめ度の平均: 4.5
5 プログラマーのお友達Make
4 makeファイルを独学で学んできた人にもお勧め

make の仕組みを理解する

前述*1のように Makefile は非常に簡潔に記述できます.ただし,簡潔なMakefileを記述するためには make の仕組みを理解する必要があります.

結論から言うと, make は 簡潔な生成ルールのみを記述したMakefileから, 実際に必要となる詳細な生成ルールを自動的に生成します.

自動的に生成されたルールを確認するには

 $ make -p

と "-p" オプションを付けて make を実行します.

以下,

  • hoge.c から hoge を生成する場合
  • hoge.c と fuga.c から hoge を生成する場合

の二つの具体例を挙げて,説明します.

前準備

Makefilehoge.c を用意します.

all: hoge
int main()
{
  return 0;
}

make -p の実行

  $ make -p > log

大量の情報が 標準出力に出力されるので,一旦 log というファイルに出力を保存します.

make -p の結果を眺める(その1)

ここからが,本題です.

まず,make は makefile に記述された”生成ルール”にしたがってビルドを進めます.生成ルールは以下のように記述されます.

ターゲット:  ソース
    コマンド

これで,"ソース"から "コマンド"をつかって"ターゲット"を生成する,という意味になります.

また,ここからが重要なのですが,make にはデフォルトでいくつかのルールが登録されています.たとえば

hoge: hoge.c

とコマンドを省略したMakefileが与えられても,make は hoge.c から hoge を作るためのコマンドを自動的に補ったルールを生成します.

make コマンドを実行する際に”-p” オプションは,この自動的に生成したルールをみるためのオプションです.

それでは,"-p"オプションの結果を保存した log ファイルの中を眺めてみましょう.hoge をキーワードに検索を書けてみると見易いです.

hoge を検索すると以下のような部分が二つ見つかると思います.一つ目は all: hoge と,Makefile で与えたルールそのものです.

all: hoge
#  Implicit rule search has been done.
#  File does not exist.
#  File has been updated.
#  Successfully updated.

二つ目は,make が自動生成したルールです.

hoge: hoge.c
#  Implicit rule search has been done.
#  Implicit/static pattern stem: `hoge'
#  Last modified 2007-02-18 14:27:19
#  File has been updated.
#  Successfully updated.
#  commands to execute (built-in):
        $(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@

これが

ターゲット:  ソース
   コマンド

の形式で,コマンドの部分が

        $(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@

と自動的に補われたかたちになっています

ここで,$^と$@はmakeが使う特別な変数で,この場合はそれぞれ $^が hoge.c $@ が hoge に展開されます.

一方, $(LINK.c) は LINK.c をキーワードに log ファイルを検索すると

LINK.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)

と定義されています.CC は,検索すると

CC = gcc

と定義されているはずです.また,他の変数$(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)は未定義なので,

LINK.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)

LINK.c = gcc

と展開されることになります.

同様の手順で make -p を眺めていくと最終的に

hoge: hoge.c
        $(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@

は,

hoge: hoge.c
        gcc hoge.c -o hoge

という生成ルールに展開できることが判ると思います.

このような make が自動的に補ってくれるコマンドと,その内部で使われる変数達を把握できるようになると, Makefile は非常に簡潔に記述できるようになります.

make -p の結果を眺める(その2)

同じ手順で,次にhoge.c とfuga.c から hoge を生成するmakefileについてmake -p の結果を眺めてみます.

Makefile は以下のものを使います

all: hoge
hoge: hoge.o  fuga.o

make -p の結果から関連するところを抜き出すと

all: hoge

hoge: hoge.o fuga.o
      $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@

hoge.o: hoge.c
      $(COMPILE.c) $(OUTPUT_OPTION) $<
fuga.o: fuga.c
      $(COMPILE.c) $(OUTPUT_OPTION) $<

となります.LINK.o COMPILE.c はそれぞれ

COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
LINK.o = $(CC) $(LDFLAGS) $(TARGET_ARCH)

と定義されています.最終的にどのようなコマンドが実行されるのかは,冗長になるのでここでは割愛します.

まとめ

make -p の結果を読むことで,make がMakefileを元に内部でルールを自動生成していることを説明しました.

また,内部で生成しているルールを読むことで,

  • コンパイラは CC で設定できる
  • コンパイルオプションは CFLAGS か CPPFLAGS で指定できる
  • リンクオプションは LDFLAGS で指定できる

ことが理解できたかと思います.

このようなmakeが自動的に補うルール,コマンドを意識すると makefile は非常に簡潔に書くことができます.是非一度 make に オプション"-p"を付けて実行してみることをおすすめします.

また以下の本を読むこともおすすめします.

GNU Make
GNU Make
posted with amazlet at 09.01.10
ロバート メクレンバーグ
オライリージャパン
売り上げランキング: 91882
おすすめ度の平均: 5.0
5 どのファイルをコンパイルするかを指定する道具

make 改訂版
make 改訂版
posted with amazlet at 09.01.10
アンドリュー オラム スティーブ タルボット
オライリー・ジャパン
売り上げランキング: 130044
おすすめ度の平均: 4.5
5 プログラマーのお友達Make
4 makeファイルを独学で学んできた人にもお勧め