
makeはStuart Feldman氏が1976年にベル研究所で開発したUnix用のビルドツールで、ソフトウェアビルドの自動化という発想を業界に持ち込んだ歴史的存在です。Makefileに「ターゲット:依存」の関係を書き、依存ファイルが新しければターゲットを再生成するという単純な仕組みで、C言語のビルドからLaTeX原稿の生成、Webサイトの静的生成、CI/CDの便利ランナーまで現在も幅広く使われています。現在のLinuxディストリビューションに同梱されるのはほぼGNU Makeで、Stuart Feldman氏は1979年のmakeに関する仕事で2003年にACMからソフトウェアシステム賞を受賞しました。
この記事の目次
- Makefileの基本構文と動作原理
- 暗黙ルールと変数で簡潔に
- 現代でのmakeの使われ方
- Ninjaや代替タスクランナーとの違い
- まとめ
Makefileの基本構文と動作原理

Makefileの基本は3行構造で、target: prerequisitesの次行にTab文字始まりのレシピを書く形式です。例えばapp: main.o util.o\n\tgcc -o app main.o util.oと書けば、main.oかutil.oがappより新しい場合だけgcc -o app ...が実行されます。ファイル時刻をベースに依存判定する素朴な仕組みで、レシピそのものはシェルコマンドなのでcp・mkdir・curlなど何でも書けます。
make最大の制約はレシピ先頭が必ずTab文字でなければならないことで、これは設計時にFeldman氏が「変更する勇気がなかった」と後年語ったエピソードでも有名です。またファイル時刻を使うためファイルシステムのclock skewやコンテナ間でのタイムスタンプ問題に弱く、コンテンツハッシュベースのBazelやNinjaに比べると再現性が落ちる場面があります。それでも記述量の少なさと普及度から、ちょっとした自動化や個人プロジェクトの便利ランナーとして根強く生き残っています。
暗黙ルールと変数で簡潔に

GNU Makeにはあらかじめ暗黙ルールが定義されており、%.o: %.cに対するレシピが内部で組み込まれているため、app: main.o util.oだけ書いてもmain.cからmain.oが自動でコンパイルされます。変数もCC = gcc・CFLAGS = -O2 -Wallのように定義でき、暗黙ルールが$(CC) $(CFLAGS) -c $<の形でこれらを参照するため、最小限の記述で標準的なC/C++ビルドが完成します。1970年代の言語仕様にしては驚くほどよくできており、UnixのCコンパイル文化と一体化していました。
ファイルパターン展開の$(wildcard src/*.c)、テキスト置換の$(patsubst %.c,%.o,$(SRCS))、シェルコマンド呼び出しの$(shell git rev-parse HEAD)など、GNU Make固有の組み込み関数で複雑なロジックも書けます。.PHONY: clean testの宣言で「ファイル名と衝突しないターゲット」を明示し、make cleanがディレクトリ内に同名ファイルが存在しても動くようにするのは現代Makefileの基本です。とはいえこれらを駆使し始めるとMakefileは急速に難読化するため、複雑なロジックはシェルスクリプトに外出ししたほうが保守しやすくなります。
現代でのmakeの使われ方

makeは現在も多くの場面で生き残っており、特にLinuxカーネル本体・glibc・GCC・BashなどのGNU/Linux基盤プロジェクトはmakeで管理されています。Cで書かれた小〜中規模ライブラリもconfigure → make → make installというAutotools的フローが今も標準で、./configure && make && sudo make installの手順は1990年代から大きく変わっていません。DockerfileでもCで書かれたツールのインストールにRUN make && make installと書くのは定番の処理です。
一方でC/C++以外の言語プロジェクトでも、make build・make test・make lint・make deployのようなプロジェクト共通の便利コマンドランナーとしてMakefileを使う事例が増えています。言語処理系のビルドはGradleやCargoに任せつつ、その上位でmakeに統一する構成で、READMEの先頭に「make testを叩けばテストが走る」と書ける利点があります。ただしWindowsネイティブで動かすには別途mingw32-makeやWSLが必要で、クロスプラットフォーム重視の現場ではJust(Casey Rodarmor氏作)やTaskといった代替を選ぶ動きもあります。
Ninjaや代替タスクランナーとの違い

Ninja(Evan Martin氏作・2010年)はChromiumのビルドを高速化するために生まれたツールで、人間が手で書くことは前提とせず、CMakeやGN等の上位ツールから自動生成されるbuild.ninjaを高速に処理することに特化しています。ChromiumやLLVMの巨大ビルドが現実的な時間で終わるのはNinjaのおかげと言ってよく、makeの「素朴さ」とNinjaの「速さ」は世代差を象徴しています。現代C++プロジェクトでは「CMake → Ninja」という組み合わせが定番で、makeはNinjaに置き換えられる場面が増えました。
便利コマンドランナー用途では、Casey Rodarmor氏が2016年に公開したJustが「タブ問題から解放された現代版make」として支持を伸ばしています。Taskや、Goで書かれたMake代替のGoTaskなども選択肢に上がり、新規プロジェクトでmakeを選ぶ必然性は薄まりつつあります。それでもmakeは「どのUnix環境にも入っている」という強みがあり、依存ゼロで動く約束された手段として、シンプルな自動化に今も使われ続けます。
まとめ
makeは1976年にStuart Feldman氏が生み出したUnix系ビルドツールの始祖で、ターゲットと依存関係を書くだけで自動ビルドが成立する素朴な仕組みでソフトウェア工学に大きな影響を与えました。現在でもLinuxカーネルやGNUツール群、便利コマンドランナーとして根強く使われ、CMakeやNinja・Justなど後続ツールと棲み分けながら現役で活躍しています。古典として理解しておく価値が極めて高い、業界の共通言語と言える1本です。
※本記事はIT用語辞典の手書きドラフトです。公開前に最新情報・出典を確認のうえ加筆修正してください。

コメント