* Makefile [#yaf1853d]
実際に目にする機会の多い Makefile は、GNU Make という拡張 Makefile 仕様のものだと思います。そこで、本文では GNU Make に絞ります。とりあえず使えそうな雛型をお探しの場合は、ページ最下部にあるソースをご覧ください。
** 基本 [#fb8e4a4d]
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 $<
** 階層化したディレクトリ構成で使う [#f4ec3fa9]
平たいディレクトリではなく、階層化した構造でも使えるようにします。例として、以下のようなディレクトリ構造を考えます。
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
** ヘッダファイルディレクトリやライブラリがある場合 [#f92f2b3f]
以下のように、ヘッダファイルが別ディレクトリにあった場合は、-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
** まとめ [#q8b3ef35]
以上を全部まとめてみます。ついでに 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