makefile 配方中的 Foreach 模板

Mir*_*ral 3 linux foreach makefile gnu-make

给出以下 Makefile 片段:

TOOLS=foo bar

define TOOL_install
install -c $(1) $$(prefix)/bin/$(1)
endef

.PHONY: install
install: all
        $(foreach tool,$(TOOLS),$(eval $(call TOOL_install,$(tool))))
Run Code Online (Sandbox Code Playgroud)

为什么make install打印“对‘安装’无需执行任何操作。” 而不是执行 foreach 指定的命令?(foreach 之前有一个选项卡,我尝试在 TOOL_install 定义中放置一个选项卡;但没有帮助。)

根据make -p安装目标没有命令,这显然不符合预期。

在同一个 makefile 的其他地方,我成功地使用相同的技术来创建整个规则,包括命令配方;我怎样才能在现有规则内实现这项工作?

(如果我替换eval为,info那么它会打印我期望它运行的命令。)

在这个简单的情况下,我可以通过内联命令让它工作:

install: all
        @$(foreach tool,$(TOOLS),install -c $(tool) $(prefix)/bin/$(tool) ; )
Run Code Online (Sandbox Code Playgroud)

但我想知道如何让第一个表单按预期工作,以防我将来需要更复杂的东西。

jml*_*jml 6

您不应该eval在此处使用,因为您不想创建动态构造,而是创建恒定的规则。因此,只需删除并在定义末尾eval添加一个:;TOOL_install

TOOLS := foo bar

define TOOL_install
echo $(1);
endef

.PHONY: install
install:
    $(foreach tool,$(TOOLS),$(call TOOL_install,$(tool)))
Run Code Online (Sandbox Code Playgroud)

扩展后,您Makefile将如下所示:

.PHONY: install
install:
    echo foo; echo bar;
Run Code Online (Sandbox Code Playgroud)

另一个答案:

我们正在使用一些临时目标install_fooinstall_bar。这两个目标被添加到install依赖项中并在之后声明。此外,在每个临时目标中,我们添加有关要安装的文件的依赖项(foobar)。这样您就可以根据需要添加规则,而且它是“并行兼容”的。

prefix := foobar
TOOLS := foo bar

install: $(addprefix install_,$(TOOLS))

$(addprefix install_,$(TOOLS)): install_%: %
    install -c $< $(prefix)/bin/$<

.PHONY: install $(addprefix install_,$(TOOLS))
Run Code Online (Sandbox Code Playgroud)

编辑:

对于卸载目标(没有依赖项),您可以使用patsubst如下函数:

prefix := foobar
TOOLS := foo bar

uninstall: $(addprefix uninstall_,$(TOOLS))

$(addprefix uninstall_,$(TOOLS)):
    install -c $(patsubst uninstall_%,%,$@) $(prefix)/bin/$(patsubst uninstall_%,%,$@)

.PHONY: uninstall $(addprefix uninstall_,$(TOOLS))
Run Code Online (Sandbox Code Playgroud)


Mir*_*ral 5

我最终采用了我最初的问题和jml的答案的混合方法(感谢您的灵感!)。

TOOLS:=foo bar

.PHONY: all
all : $(TOOLS)

.PHONY: install $(addprefix install_,$(TOOLS))
install : $(addprefix install_,$(TOOLS))

.PHONY: uninstall $(addprefix uninstall_,$(TOOLS))
uninstall : $(addprefix uninstall_,$(TOOLS))

define TOOL_template
$(1): $$($(1)_OBJS)
        #commands to build it

install_$(1): $(1)
        install -c $(1) $$(prefix)/bin/$(1)

uninstall_$(1):
        rm $$(prefix)/bin/$(1)
endef

$(foreach tool,$(TOOLS),$(eval $(call TOOL_template,$(tool))))
Run Code Online (Sandbox Code Playgroud)

似乎可以做到这一点。