makefile:foreach"make -C"调用

Oli*_*han 2 ubuntu makefile gnu-make

这是我的makefile的一部分:

PATH := $(shell pwd)
EDIR := impl
EFFECTS := $(filter-out $(EDIR), $(shell find $(EDIR) -maxdepth 1 -type d))
ALLMAKES := $(patsubst %, $(PATH)/%, $(EFFECTS))


all:
      $(foreach c,$(ALLMAKES),$(MAKE) -C $(c))
Run Code Online (Sandbox Code Playgroud)

基本上,我想为"impl"目录中的所有目录调用make而不使用"impl"本身.我知道make会记住上次使用-C参数调用时的最后一个目录,这就是我每次都给出绝对路径的原因.是什么让回声看起来像我想要的:

make -C <projectdir>/impl/thing1 make -C <projectdir>/impl/thing2 make -C <projectdir>/impl/thing3
Run Code Online (Sandbox Code Playgroud)

问题是make不能完成命令并只是打印:

make: make: Command not found. 
Run Code Online (Sandbox Code Playgroud)

我可以在makefile之外单独调用每个目录的"make -C <path>",但它在foreach调用中不起作用.我试过这个,但它也不起作用:

$(foreach c,$(ALLMAKES),$(shell make -C $(c)))
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?

Mad*_*ist 9

那是因为你正在调用一个make包含后续make命令的大量参数.您需要在make的调用之间添加一个shell命令分隔符.这样的东西会起作用:

all:
        $(foreach c,$(ALLMAKES),$(MAKE) -C $(c) && ) true
Run Code Online (Sandbox Code Playgroud)

第二,你的makefile还有其他问题.您不应该设置一个名为make的变量PATH,因为这将覆盖subshel​​l的$PATH变量.您可以使用make内置变量$(CURDIR)而不是运行$(shell pwd).实际上你根本不需要在目录前面添加路径,因为运行$(MAKE) -C ...不会改变shell的工作目录,只是make,而当make退出时它会被设置回来,所以你可以使用相对路径.

在循环中调用子make也有一些问题.首先,您可以减少可以获得的并行化数量.其次,-k无法正确支持该选项(没有很多不愉快的努力).处理此问题的更好方法是利用make已经知道如何构建大量目标的事实:

all: $(EFFECTS)
$(EFFECTS):
        $(MAKE) -C $@
.PHONY: all $(EFFECTS)
Run Code Online (Sandbox Code Playgroud)

如果不同子目录之间存在特定的排序问题,您也可以定义它们:

impl/thing2: impl/thing1
Run Code Online (Sandbox Code Playgroud)

这确保了最大的并行化机会,同时仍然保留了重要的排序.

要添加替代规则,比方说clean,您可以执行以下操作:

CLEAN_EFFECTS := $(addsuffix .clean,$(EFFECTS))
clean: $(CLEAN_EFFECTS)
$(CLEAN_EFFECTS):
        $(MAKE) -C $(basename $@) clean
.PHONY: clean $(CLEAN_EFFECTS)
Run Code Online (Sandbox Code Playgroud)

这很好,因为您还可以通过运行make impl/thing1来构建单个子目录(及其所有先决条件).或者通过跑步清洁它们make impl/thing1.clean

如果您有更多这些,您也可以使用模式规则等,以避免对每种类型的目标重复此操作.它变得更加繁琐.

  • 通常在我的makefile中,我不喜欢在这样的shell循环中运行子make,因为(a)它减少了与`-j`的并行机会,并且(b)几乎不可能使它在方面正常工作到`-k`选项.但是,它是一个快速而肮脏的解决方案,可以回答特定问题并且可以正常运行.我会添加一个"更干净"的替代品. (2认同)