Makefile 目标作为两个列表的叉积
Makefile targets as cross product of two lists
我花了一天的大部分时间来弄清楚这个问题。我想使用 make 构建具有不同 os 目标和多个二进制文件的 golang 项目。我想我想使用 gnu make
我精简的 Makefile 看起来像:
main= mailworker websocket worker init
os= linux freebsd darwin
all: $(main)
$(main): ensure_build_path
@echo "Build $@ Version: $(GIT_REV)"
@rm -rf $(BUILD_PREFIX)/$@
GO111MODULE=on GOARCH=amd64 $(GO) build -o $(BUILD_PREFIX)/$@ ./bin/$@/$@.go
现在我想将 GOOS=$(os)
添加到构建命令/为每个主要 X os 组合生成一个目标。我的测试/学习 Makefile 看起来像:
os=linux freebsd darwin
main=mailworker websocket worker init
define build_template =
t:=$(addprefix $(1), $(2))
$(info $(t))
$(t):
@echo $(1) $(2) $$@
endef
$(foreach P, $(main), $(foreach O, $(os), $(eval $$(call build_template, $O, $P))) )
我尝试了至少十几种变体。我认为我的主要问题是如何在模板中声明 t
。我尝试了很多 "concat" 我发现的关于 make 的方法。还有 :=
或 =
代表 t。我认为 :=
是正确的。但我对任何事都不确定了 ;)
明确地说,我想 "generate" 目标看起来像:
mailworker_linux:
GO111MODULE=on GOOS=linux GOARCH=amd64 $(GO) build mailworker
mailworker_darwin:
GO111MODULE=on GOOS=darwin GOARCH=amd64 $(GO) build mailworker
这样做好吗?如果是这样,我的误解在哪里。
非常感谢
你这里有一些问题。首先,您对 call
的调用是不正确的:您正在转义它,这意味着它在被赋予 eval 之前不会被扩展;这是不正确的,必须先扩展。你想要:
..., $(eval $(call build_template,$P,$O))..
(call
之前只有一个$
.
其次,您定义的与 eval/call 对一起使用的变量的规则是,您希望 eval 看到的该变量内的每个宏扩展都必须转义。在您的情况下,您确实将 $@
转义为 $$@
,这很好,但您需要转义的另一件事是使用 $(t)
,因为该变量直到 [=19] =] 设置它。所以你需要这样写你的变量:
define build_template =
t := $(addprefix $(1)_,$(2))
$$(info $$(t))
$$(t):
@echo $(1) $(2) $$@
endef
(我将缺少的 _
添加到您的 addprefix
中)。这里使用 =
或 :=
都没有关系;它们的工作原理相同,因为您总是在立即扩展上下文中使用此变量。
顺便说一句,似乎每个人都直接跑到 eval 和 call 上,它们非常强大,但也很难使用和理解。使用更直接的 make 构造的替代方案可能是这样的:
getmain = $(word 1,$(subst _, ,$@))
getos = $(word 2,$(subst _, ,$@))
TARGETS := $(foreach P,$(main),$(addprefix $P_,$(os)))
all: $(TARGETS)
$(TARGETS): %:
@echo $(getmain) $(getos) $@
我花了一天的大部分时间来弄清楚这个问题。我想使用 make 构建具有不同 os 目标和多个二进制文件的 golang 项目。我想我想使用 gnu make
我精简的 Makefile 看起来像:
main= mailworker websocket worker init
os= linux freebsd darwin
all: $(main)
$(main): ensure_build_path
@echo "Build $@ Version: $(GIT_REV)"
@rm -rf $(BUILD_PREFIX)/$@
GO111MODULE=on GOARCH=amd64 $(GO) build -o $(BUILD_PREFIX)/$@ ./bin/$@/$@.go
现在我想将 GOOS=$(os)
添加到构建命令/为每个主要 X os 组合生成一个目标。我的测试/学习 Makefile 看起来像:
os=linux freebsd darwin
main=mailworker websocket worker init
define build_template =
t:=$(addprefix $(1), $(2))
$(info $(t))
$(t):
@echo $(1) $(2) $$@
endef
$(foreach P, $(main), $(foreach O, $(os), $(eval $$(call build_template, $O, $P))) )
我尝试了至少十几种变体。我认为我的主要问题是如何在模板中声明 t
。我尝试了很多 "concat" 我发现的关于 make 的方法。还有 :=
或 =
代表 t。我认为 :=
是正确的。但我对任何事都不确定了 ;)
明确地说,我想 "generate" 目标看起来像:
mailworker_linux:
GO111MODULE=on GOOS=linux GOARCH=amd64 $(GO) build mailworker
mailworker_darwin:
GO111MODULE=on GOOS=darwin GOARCH=amd64 $(GO) build mailworker
这样做好吗?如果是这样,我的误解在哪里。
非常感谢
你这里有一些问题。首先,您对 call
的调用是不正确的:您正在转义它,这意味着它在被赋予 eval 之前不会被扩展;这是不正确的,必须先扩展。你想要:
..., $(eval $(call build_template,$P,$O))..
(call
之前只有一个$
.
其次,您定义的与 eval/call 对一起使用的变量的规则是,您希望 eval 看到的该变量内的每个宏扩展都必须转义。在您的情况下,您确实将 $@
转义为 $$@
,这很好,但您需要转义的另一件事是使用 $(t)
,因为该变量直到 [=19] =] 设置它。所以你需要这样写你的变量:
define build_template =
t := $(addprefix $(1)_,$(2))
$$(info $$(t))
$$(t):
@echo $(1) $(2) $$@
endef
(我将缺少的 _
添加到您的 addprefix
中)。这里使用 =
或 :=
都没有关系;它们的工作原理相同,因为您总是在立即扩展上下文中使用此变量。
顺便说一句,似乎每个人都直接跑到 eval 和 call 上,它们非常强大,但也很难使用和理解。使用更直接的 make 构造的替代方案可能是这样的:
getmain = $(word 1,$(subst _, ,$@))
getos = $(word 2,$(subst _, ,$@))
TARGETS := $(foreach P,$(main),$(addprefix $P_,$(os)))
all: $(TARGETS)
$(TARGETS): %:
@echo $(getmain) $(getos) $@