実際に目にする機会の多い Makefile は、GNU Make という拡張 Makefile 仕様のものだと思います。そこで、本文では GNU Make に絞ります。とりあえず使えそうな雛型をお探しの場合は、ページ最下部にあるソースをご覧ください。
Makefile の基本的な記述方法は、以下の通りです。
[作りたいファイル(ターゲット)]:[左のファイルを作るのに必要なファイル(依存ファイル)] 実行する命令
具体的に書いてみます。同じ階層に main.c sub.c があり、そこに sample.exe を作る Makefile です。
sample.exe:main.o sub.o gcc -o sample.exe main.o sub.o main.o:main.c gcc -o main.o -c main.c sub.o:sub.c gcc -o sub.o -c sub.c
少し楽してみます。
sample.exe:main.o sub.o gcc -o $@ $< %.o:%.c gcc -o $@ -c $<
もっと楽をします。
SRCS=main.c sub.c OBJS=$(SRCS:.c=.o) sample.exe:$(OBJS) gcc -o $@ $< %.o:%.c gcc -o $@ -c $<
gcc とかもマクロにします。
CC=gcc SRCS=main.c sub.c OBJS=$(SRCS:.c=.o) sample.exe:$(OBJS) $(CC) -o $@ $< %.o:%.c $(CC) -o $@ -c $<
平たいディレクトリではなく、階層化した構造でも使えるようにします。例として、以下のようなディレクトリ構造を考えます。
project/ project/Makefile project/src project/objs
以下のようになります。ちょっと複雑になってきました。
CC=gcc OBJS_DIR=objs SRCS_DIR=src SRCS=main.c sub.c # *.cを*.oに変換して、先頭にobjs/を付けます # つまりOBJS=objs/main.o objs/sub.o になります OBJS=$(addprefix $(OBJS_DIR)/, $(SRCS:.c=.o)) # サーチパスを指定します # .cを持つファイルをSRCS_DIR内で検索します vpath %.c $(SRCS_DIR) # 依存関係1 sample.exe:$(OBJS) $(CC) -o $@ $< # 依存関係2 $(OBJS_DIR)/%.o:%.c $(CC) -o $@ -c $<
sample.exe を作ろうとすると、OBJS=objs/main.o objs/sub.o が必要です(依存関係1)。objs/main.o には main.c が必要です(依存関係2)。vpath により、.c ファイルの検索場所として SRCS_DIR を指定しているので、そこを検索して、src/main.c を見つけます。以上で、main.* について、依存関係を解決できました。sub.* についても、同様に依存関係を解決できます。
※vpath は指定されたディレクトリを検索して、最初に一致したファイルを依存対象として認識します。つまり異なるディレクトリに同じファイル名があると、ややこしいことになりますので、注意が必要です。
後始末用の clean ターゲットも用意しましょう。*.o や *.exe を消すだけです。
clean: # 余談ですが、*.o を一箇所にまとめておくと、こういうとき楽です rm $(OBJS_DIR)/*.o rm sample.exe
以下のように、ヘッダファイルが別ディレクトリにあった場合は、-I で指定する必要があります。同様にライブラリをリンクしたい場合も、-L -l で指定する必要があります。そこで、コンパイラへのオプションもマクロにしておきましょう。後でいじるときに楽です。
project/ project/Makefile project/src project/src/include project/lib project/objs
INCLUDE_DIRS=-I./include LIB_DIRS=-L./lib CFLAGS=$(INCLUDE_DIRS) LDFLAGS=$(LIB_DIRS) -lutil
以上を全部まとめてみます。ついでに sample.exe もターゲット名としてマクロにしておきます。
TARGET=sample.exe # コンパイラ関連 CC=gcc INCLUDE_DIRS=-I./include LIB_DIRS=-L./lib CFLAGS=$(INCLUDE_DIRS) LDFLAGS=$(LIB_DIRS) -lutil # 配置関連 OBJS_DIR=objs SRCS_DIR=src SRCS=main.c sub.c OBJS=$(addprefix $(OBJS_DIR)/, $(SRCS:.c=.o)) vpath %.c $(SRCS_DIR) # 依存関係 $(TARGET):$(OBJS) $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) $(OBJS_DIR)/%.o:%.c $(CC) $(CFLAGS) -o $@ -c $< clean: rm $(OBJS_DIR)/*.o rm sample.exe