【问题标题】:makefile: foreach "make -C" call生成文件:foreach“make -C”调用
【发布时间】:2013-03-17 17:12:38
【问题描述】:

这是我的 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))

所以本质上,我想为“impl”目录中的所有目录调用make,而不需要“impl”本身。我知道 make 会记住上次使用 -C 参数调用时所在的最后一个目录,这就是为什么我每次都给出绝对路径的原因。是什么让回声似乎是我想要的:

make -C <projectdir>/impl/thing1 make -C <projectdir>/impl/thing2 make -C <projectdir>/impl/thing3

问题是 make 没有完成命令,只是打印:

make: make: Command not found. 

我可以在 makefile 之外为每个目录单独调用“make -C ”,但它在 foreach 调用中不起作用。我已经尝试过了,但它也不起作用:

$(foreach c,$(ALLMAKES),$(shell make -C $(c)))

有什么想法吗?

【问题讨论】:

  • 致发表评论但将其删除的人...从 makefile 调用与 shell 完全相同的 make 命令是行不通的,所以您很有帮助...
  • 我删除了我的评论,因为我认为我走错了路。我正在寻找更好的答案...

标签: ubuntu makefile gnu-make


【解决方案1】:

那是因为您正在调用单个 make,其中包含许多参数,包括后续的 make 命令。您需要在 make 的调用之间添加一个 shell 命令分隔符。这样的事情会起作用:

all:
        $(foreach c,$(ALLMAKES),$(MAKE) -C $(c) && ) true

再看一遍,您的 makefile 还存在其他问题。您不应设置名为PATH 的make 变量,因为这将覆盖子shell 的$PATH 变量。您可以只使用 make 内置变量 $(CURDIR) 而不是运行 $(shell pwd)。您实际上根本不需要在目录前加上路径前缀,因为运行 $(MAKE) -C ... 不会更改 shell 的 工作目录,只会更改 make 的,并且当 make 退出时它会被设置回来,所以你可以只使用相对路径。

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

all: $(EFFECTS)
$(EFFECTS):
        $(MAKE) -C $@
.PHONY: all $(EFFECTS)

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

impl/thing2: impl/thing1

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

要添加替代规则,例如clean,您可以执行以下操作:

CLEAN_EFFECTS := $(addsuffix .clean,$(EFFECTS))
clean: $(CLEAN_EFFECTS)
$(CLEAN_EFFECTS):
        $(MAKE) -C $(basename $@) clean
.PHONY: clean $(CLEAN_EFFECTS)

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

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

【讨论】:

  • 通常在我的 makefile 中,我不喜欢像这样在 shell 循环中运行子 make,因为 (a) 它减少了与 -j 并行的机会,并且 (b) 这几乎是不可能的使其在 -k 选项方面正常工作。但是,这是一个快速而肮脏的解决方案,可以回答特定问题并且会起作用。我将添加一个“更清洁”的替代方案。
  • 谢谢!最后一个建议成功了。我会注意您对未来 makefile 的其他建议(因为如果我使用相对路径,我将不需要 $(CURDIR))
  • 我还想为此添加一个干净的规则......所以以相同的方式调用每个“效果”,除了在命令末尾添加一个干净,如下所示:“make -C impl/thing1 clean" 有没有办法做到这一点,因为我不能复制相同的目标?
  • 现在,我在 foreach 调用中使用您的第一个建议,并制定一个单独的 all and clean 规则。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-01
  • 1970-01-01
  • 2023-03-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多