GNU Make

GNU Make 第3版

GNU Make 第3版

↑を読んでるんですが、これはかなり意外にオモシロイ。まだ読み切れていないけど、最後の章はかなり変なことやってておもしろそう。
GNU Makeは、もとのMakeからなんか機能がすごい拡張されてる。何年もmake代替物に取って代わられずに生き残れるわけだ。

eval

とくにイケてるのが、3.80(2002年リリース)で追加された $(eval )関数。
渡された文字列が、もともとそこにあったかのように展開してくれる。
以下のように、tmp_from_from, tmp_bar_from の各ディレクトリをコピーするのに便利かな。

#
# copy macro
#
#$(call copy-recurs, from, to)
define copy-recurs
$1_FILES := $$(shell find $$($1_DIR) -name "*" -type f)
$2_FILES := $$(patsubst $$($1_DIR)/%,$$($2_DIR)/%,$$($1_FILES))
 
$2_DIR_ALL := $$(sort $$(dir $$($2_FILES)))

$$($2_DIR_ALL):
	mkdir -p $$@

$$($2_FILES): $$($2_DIR)/%: $$($1_DIR)/% $$($2_DIR_ALL)
	@cp $$< $$@
endef

#
# tmp_bar_from -> tmp_bar_to
#
BAR_FROM_DIR := ./tmp_bar_from
BAR_TO_DIR   := ./tmp_bar_to
$(eval $(call copy-recurs,BAR_FROM,BAR_TO))


#
# tmp_foo_from -> tmp_foo_to
#
FOO_FROM_DIR := ./tmp_foo_from
FOO_TO_DIR   := ./tmp_foo_to
$(eval $(call copy-recurs,FOO_FROM,FOO_TO))

.DEFAULT_GOAL := all

.PHONY: all
all: $(FOO_TO_FILES) $(BAR_TO_FILES)

# callとevalで evalとmakeで変数が2回展開されるので、$の数に注意。

条件関数

そのほかにも、3.81(2006/04 リリース)では $(and) とか $(or) とか条件分岐に使えそうな関数が追加されてる。
いままでは、 変数 A と変数 B の両方が定義されている場合に有効にする処理は

ifdef A
ifdef B
 #AとBが有効なときの処理
endif
endif

と、かなーり見づらい表記にする必要がありましたが、$(and) と $(if) を使えば

ifeq ($(if $(and $(A),$(B)),1),1)
 #AとBが有効なときの処理
endif

と一行にまとめられる。
$(or)はもっと使いでがありそうで、以前のMakeだとAかBが有効なときの処理が

ifdef A
  C := 1
endif
ifdef B
  C := 1
endif
ifdef C
  #AかBが有効なときの処理
endif

と、かなりいやな感じなのが

ifeq ($(if $(or $(A),$(B)),1),1)
 #AかBが有効なときの処理
endif

と、かなりすっきりする。

特殊変数

.DEFAULT_GOAL という特殊変数も追加されてる。デフォルトのゴールがファイル中のどこにあっても

.DEFAULT_GOAL := goal_name

と指定するだけで、goal_name がデフォルトのゴールになる。へ〜。