開発者向けMakefile — Bashのスパゲティを避けたタスク自動化
Makeは1977年に開発されたビルドツールですが、プロジェクトタスクランナーとして非常に優れています。1つのMakefile、make test、完了 — Bashスクリプトを維持する必要もなく、インストールする必要もありません。
あなたは、そのような状況を知っています。プロジェクトは最初はきれいです。そして誰かが run.shを追加します。 build.shを追加します。 deploy.sh が、を参照し .env と、最初の二つを特定の順序で呼び出します。そして、誰も触りたがらない6つのシェルファイルと、「スクリプトフォルダを参照してください」というREADMEが現れます。
修正を実行します。一つ Makefile プロジェクトのルートに、 make test、完了。
これはCのビルドシステムについてではありません。MakeはLinux以前に存在し、依存関係ベースのコンパイルに設計されたが、その核心メカニズム(名前を付けたターゲットがシェルコマンドを実行する)により、どんなスタックにも適したタスクランナーになります。Node、Python、Go、Rust、Docker、あるいは何を構築しているかに関わらず。
Makeが実際にどのように機能するか
Makefileはターゲットのリストです。各ターゲットには名前、オプションの依存関係、およびシェルコマンドブロックがあります:
.PHONY: build test lint clean
build:
npm run build
test:
npm test
初めに遭遇する二つの問題:
- インデントは実際のタブ文字でなければなりません、スペースではありません。すべてのエディタがタブを自動変換するものであれば、あなたのMakefileが無意識に壊れてしまうまで、設定を変更する必要があります。これは1977年からずっと真実であり、Makeはスペースを使用した場合を決して許容しません。
- デフォルトで、Makeはターゲット名をファイル名と見なします。 プロジェクトルートに
buildというファイルが存在する場合、make buildは何もしません、なぜならMakeはそのターゲットがすでに「構築済み」と見なしているからです。解決策は.PHONY.
すべてのファイル名ではないターゲットを .PHONYとして宣言することです。実際のタスクランナーMakefileでは、すべてのターゲットを宣言します。なぜなら、それらのターゲットはファイルを生成しないからです。あなたの .PHONY 行は、下記のテンプレートの最初の行に見えます。
変数とコマンドラインオーバーライド
Makeは独自の変数構文を持っています — シェルに似ていますが、動作は異なります:
DOCKER_IMAGE = myapp
TAG = latest
build:
docker build -t $(DOCKER_IMAGE):$(TAG) .
コマンドラインからオーバーライド: make build TAG=v1.2.3。バージョンごとのビルドや環境ごとのデプロイにファイル編集を必要とせず、シェル環境変数も自動的に利用可能 — $(HOME), $(PATH)、実行時に環境にあるもの。
使用可能なMakefileテンプレート
これをコピーし、適用しないものを削除し、あなたのスタックに合わせてコマンドを調整します:
.PHONY: install build test lint clean run docker-up docker-down help
# --- Config -------------------------------------------------------------------
DOCKER_COMPOSE = docker compose
APP_NAME = myapp
# --- Default target -----------------------------------------------------------
help:
@echo "Available targets:"
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf " %-15s %s\n", $$1, $$2}'
# --- Dev ----------------------------------------------------------------------
install: ## Install dependencies
npm ci
run: ## Start the dev server
npm run dev
build: ## Build for production
npm run build
# --- Quality ------------------------------------------------------------------
lint: ## Run the linter
npm run lint
test: ## Run the test suite
npm test
test-watch: ## Run tests in watch mode
npm run test:watch
# --- Docker -------------------------------------------------------------------
docker-up: ## Start services via docker compose
$(DOCKER_COMPOSE) up -d
docker-down: ## Stop and remove containers
$(DOCKER_COMPOSE) down
docker-logs: ## Tail container logs
$(DOCKER_COMPOSE) logs -f
# --- Cleanup ------------------------------------------------------------------
clean: ## Remove build artifacts and caches
rm -rf dist node_modules/.cache .next
の help ターゲットはgrep + awkパターンを使って、インラインコメントをフォーマットされたドキュメントに取り込みます。実行 ## を実行すると、すべてのターゲットとその説明の並べ替えされたリストが得られます — その他のドキュメントを維持する必要がありません。これはMakefile歴史上最も盗まれたスニペットであり、その理由があります。 make help そして、各ターゲットの説明付きの並べ替えられたリストが得られます——別々のドキュメントを維持する必要がありません。これは、Makefileの歴史で最も盗まれたスニペットであり、その理由があります。
CI用のターゲット連携
Makeは依存関係をネイティブに処理します。ターゲットを依存関係としてリストすることで、順番に実行できます:
ci: lint test build ## Full CI check (lint -> test -> build)
make ci は、lintを実行し、その後テスト、その後ビルドを実行します。どのステップも非ゼロ終了コードを返すと、Makeは停止します。これは正しいCI行動です — 明確に失敗し、壊れたステップを無視しないでください。
エコとマルチラインコマンドの抑制
デフォルトでは、Makeは各コマンドを実行する前に表示します。前に @ を付けることで抑制できます:
setup:
@echo "Setting up project..."
@cp .env.example .env
@npm ci
@echo "Done."
複数行を横断するコマンドには、 && — ファイルが失敗した場合に停止し、セミコロンは無視して次のコマンドに進みます:
migrate:
npm run db:migrate && \
npm run db:seed && \
echo "Migration complete"
Makeが不適切なツールである場合
MakeはmacOS(Xcode Command Line Toolsを通じて)およびすべてのLinuxディストリビューションに標準搭載されています。インストール手順は不要で、バージョンの衝突もありません。ほとんどの開発チームにとって摩擦がありません。
欠点:
- 窓 — WSLは問題ありませんが、ネイティブなWindowsではChocolatey、Scoop、またはGnuWin32ポートを使用しなければmakeは存在しません。チームがWindowsネイティブである場合、 だけ はこのギャップに特化した近い代替です。
- 複雑な論理 — Makeはプログラミング言語ではありません。条件分岐やループは存在しますが、非常に醜いです。構築論理に本格的な分岐が必要な場合は、適切なスクリプトを書くべきです。
- クロスプラットフォームシェルコマンド —
rm -rf,cp、およびその他のUnixの標準ツールはネイティブなWindowsでは存在しません。 タスク (Goベース)は、クロスプラットフォームコマンドを組み込みでサポートしています。
MacまたはLinux上で動作するバックエンドおよびフルスタックチームにとって、Makeは実用的なデフォルトです。それは、何もインストールせず、何も更新せず、依存関係の更新で壊れない、最も良い方法です。
Makefileを清潔に保つ
Makefileが複数の貢献者とマージを経て成長すると、インデントとスペースがずれていきます。Makeはスペースに敏感であるため、タブではなくスペースが1つだけ混入すると、ターゲットが無意識に壊れ、助けとなるエラーメッセージが表示されません。 IO Tools’ Makefile formatter インデントとスペースを標準化し、論理部分に影響を与えずに、白文字を整理する — これは、プレコミットの健全性チェックとして有用です。
恵 スコアボードが到着しました!
スコアボード ゲームを追跡する楽しい方法です。すべてのデータはブラウザに保存されます。さらに多くの機能がまもなく登場します!
