Makefile入門|ビルド自動化の基本構文からパターンルールまで実践解説
シリーズ この記事は「コンパイル・リンク・ビルド(組み込み基礎)」の一部です。 シリーズ目次を見る
(2026年5月時点)Makefile は、ソースと生成物の 依存関係 と コマンド を書いたビルド用のファイルです(GNU Make が典型的)。CMake や Ninja と混同しないように:Make は「レシピ+ファイルの新しさ」でコマンドを走らせる道具、CMake は Makefile 等を生成するメタツールです。本記事は基本構文、変数、パターンルール、自動変数、.PHONY、小さいテンプレに絞ってメモしています。
make とは?
makeは、ファイル間の依存関係を解析し、更新が必要なファイルだけを再ビルドするツールです。ソースファイルが100個あるプロジェクトで1ファイルだけ変更した場合、makeは変更されたファイルとその影響範囲のみを再コンパイルします。 参考:GNU Make マニュアル
Makefile の基本構文とは?
Makefileは「ルール」の集合で構成されます。各ルールは、ターゲット(生成物)、依存関係(必要なファイル)、レシピ(実行するコマンド)の3要素で構成されます。
# Makefileの基本構文
ターゲット: 依存ファイル1 依存ファイル2
レシピ(実行するコマンド)
# 具体例
myapp: main.o utils.o
gcc main.o utils.o -o myapp
main.o: main.c main.h
gcc -c main.c -o main.o
utils.o: utils.c utils.h
gcc -c utils.c -o utils.o Makefile で変数を使う方法は?
Makefileでは変数を定義して、コンパイラやフラグを一元管理できます。変更時は CC/CFLAGS/SRCS など 1箇所の変数を直すだけで再ビルド条件が揃います。
# 変数定義
CC = gcc
CFLAGS = -Wall -Wextra -O2
LDFLAGS = -lm
SRCS = main.c utils.c math_lib.c
OBJS = $(SRCS:.c=.o) # .c → .o に置換
TARGET = myapp
# ルール
$(TARGET): $(OBJS)
$(CC) $(OBJS) $(LDFLAGS) -o $(TARGET)
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -f $(OBJS) $(TARGET) 自動変数($@ $< $^)とは?
make は、適用されているルールの文脈で展開される特殊変数があります(GNU Make で一般的)。
- $@:そのルールのターゲット名(例:main.o)
- $<:先頭の依存ファイル(例:main.c)
- $^:依存ファイル一覧(重複は除く)
- $?:ターゲットより新しい依存だけ
パターンルールの書き方は?
同じ変換パターンを個別に書く代わりに、%(ワイルドカード)を使って一般化できます。
# パターンルール: 任意の.cから.oへの変換ルール
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
# これにより、main.c → main.o, utils.c → utils.o 等が
# 自動的にこのルールに従ってビルドされる
.PHONY ターゲットとは?
cleanのように実ファイルを生成しないターゲットは、.PHONYで宣言します。同名のファイルが存在した場合の誤動作を防ぎます。
.PHONY: clean all rebuild
clean:
rm -f $(OBJS) $(TARGET)
all: $(TARGET)
rebuild: clean all 並列ビルドは make -j$(nproc) のようにすると試しやすいです。-j は「依存宣言が実際の生成物と一致している」ことが暗黙の契約で、欠けるとたまにだけ壊れた成果物や変な再ビルドが出ます(再現性のためには依存を先に整える)。規模が大きくなると CMake、Ninja などへ移る選択肢もあります。
実践的な Makefile テンプレート例は?
# 汎用的なC言語プロジェクト用Makefile
CC = gcc
CFLAGS = -Wall -Wextra -std=c11 -O2
LDFLAGS =
INCDIR = include
SRCDIR = src
OBJDIR = obj
SRCS = $(wildcard $(SRCDIR)/*.c)
OBJS = $(patsubst $(SRCDIR)/%.c, $(OBJDIR)/%.o, $(SRCS))
TARGET = myapp
.PHONY: all clean
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(OBJS) $(LDFLAGS) -o $@
$(OBJDIR)/%.o: $(SRCDIR)/%.c | $(OBJDIR)
$(CC) $(CFLAGS) -I$(INCDIR) -c $< -o $@
$(OBJDIR):
mkdir -p $(OBJDIR)
clean:
rm -rf $(OBJDIR) $(TARGET) まとめ:Make を使うときの要点は?
- Make は「ファイルの新しさと依存」だけで実行するものを増やせるようにするツール
- レシピ先頭は タブ。ここだけスペース禁止、が最初の転びポイントになりがちです
- %.o: %.c と自動変数で重複記述を減らし、clean は .PHONY で明示