複数実行ファイルのマルチバイナリMakefile

foreachとcall関数を使用してDRYなターゲット生成で、別々のソースディレクトリから複数の実行ファイルをビルドするMakefileを作成します。

Build Patterns

詳細な説明

複数バイナリのビルド

複数の実行ファイルを生成するプロジェクト(例:サーバーとCLIクライアント)は、各バイナリのビルドルールを重複させないMakefileが必要です。

foreachの使用

BINARIES = server client worker
BIN_DIR  = bin

all: $(addprefix $(BIN_DIR)/,$(BINARIES))

$(BIN_DIR)/%: cmd/%/main.go
	@mkdir -p $(BIN_DIR)
	go build -o $@ ./cmd/$*/...

addprefix関数は各バイナリ名にbin/を付加します。%パターンは任意のバイナリ名にマッチし、$*はマッチしたステムを返します。この単一のルールが、それぞれのcmd/ディレクトリから3つすべてのバイナリをビルドします。

defineとcallの使用(上級)

define BUILD_BINARY
$(BIN_DIR)/$(1): $$(wildcard cmd/$(1)/*.go)
	@mkdir -p $(BIN_DIR)
	go build -o $$@ ./cmd/$(1)/...
endef

$(foreach bin,$(BINARIES),$(eval $(call BUILD_BINARY,$(bin))))

defineブロックはテンプレートを作成します。call関数は$(1)を各バイナリ名で置換します。eval関数は結果をMakefile構文として扱います。$$エスケープに注意してください。define内でルール実行時(eval時ではなく)に展開されるべき変数にはダブルドルエスケープが必要です。

個別のビルド設定

server: CFLAGS += -DSERVER_MODE
client: CFLAGS += -DCLIENT_MODE

server client: %: src/%.c src/common.c
	$(CC) $(CFLAGS) -o $(BIN_DIR)/$@ $^

ターゲット固有の変数代入により、他に影響を与えずに個々のバイナリにフラグを追加できます。静的パターンルール%: src/%.cはリストされたターゲットにのみ適用されます。

主要なテクニック

  • addprefixaddsuffixはファイル名のリストを操作する
  • 静的パターンルール(targets: pattern: prereqs)はパターンマッチングを制限する
  • ターゲット固有の変数はターゲットごとの設定を提供する
  • foreach/eval/callパターンはルールを動的に生成する

ユースケース

共通のソースコードを共有しながら、異なるビルド設定で別々の実行ファイルが必要なマイクロサービスモノレポをビルドする場合に使用します。

試してみる — Makefile Generator

フルツールを開く