Makefile 什么';在所有子目录中递归构建相同目标的最简单方法是什么?

Makefile 什么';在所有子目录中递归构建相同目标的最简单方法是什么?,makefile,gnu-make,Makefile,Gnu Make,我有一个包含多个组件和子组件的项目。我希望在顶部目录中有一个make命令,以转到子目录并为给定目标运行子make。我知道我可以编写很多单独的sh命令,每个命令都由cd和make调用组成,但我觉得必须有一种更简单甚至更自动的方法 如何实现这一点?下面的代码将找到包含名为Makefile的文件的所有子目录,并使用相同的目标运行make SubMakefiles只是一个文件查找,将返回类似于/Makefile foo/Makefile bar/Makefile的内容。从那以后,dir命令给我们留下了/

我有一个包含多个组件和子组件的项目。我希望在顶部目录中有一个
make
命令,以转到子目录并为给定目标运行子
make
。我知道我可以编写很多单独的
sh
命令,每个命令都由
cd
make
调用组成,但我觉得必须有一种更简单甚至更自动的方法


如何实现这一点?

下面的代码将找到包含名为
Makefile
的文件的所有子目录,并使用相同的目标运行
make

SubMakefiles
只是一个文件查找,将返回类似于
/Makefile foo/Makefile bar/Makefile
的内容。从那以后,
dir
命令给我们留下了
/foo/bar/
,而
过滤掉了
/
。这为我们提供了一个列表,我们可以使用解释
make
命令的
sh
处理器轻松地进行迭代。最后一个细节是,如果它返回一个错误,我们自己将返回相同的错误,并使用
| | exit$$?

注意:由于所有子品牌都是从单个配方调用的,因此这将无法与
-k
-j
品牌选项一起正常工作

# Make the same target in all subdirectories with a Makefile.
SubMakefiles    = $(shell find -L . -maxdepth 2 -type f -name Makefile)
SubMakeDirs     = $(filter-out ./,$(dir $(SubMakefiles)))

clean depend all::
        @for dir in $(SubMakeDirs); do \
            $(MAKE) -C $$dir $@ || exit $$?; \
        done

下面的代码将找到包含名为
Makefile
的文件的所有子目录,并使用相同的目标运行
make

SubMakefiles
只是一个文件查找,将返回类似于
/Makefile foo/Makefile bar/Makefile
的内容。从那以后,
dir
命令给我们留下了
/foo/bar/
,而
过滤掉了
/
。这为我们提供了一个列表,我们可以使用解释
make
命令的
sh
处理器轻松地进行迭代。最后一个细节是,如果它返回一个错误,我们自己将返回相同的错误,并使用
| | exit$$?

注意:由于所有子品牌都是从单个配方调用的,因此这将无法与
-k
-j
品牌选项一起正常工作

# Make the same target in all subdirectories with a Makefile.
SubMakefiles    = $(shell find -L . -maxdepth 2 -type f -name Makefile)
SubMakeDirs     = $(filter-out ./,$(dir $(SubMakefiles)))

clean depend all::
        @for dir in $(SubMakeDirs); do \
            $(MAKE) -C $$dir $@ || exit $$?; \
        done

更好的解决方案是使用make的自然能力来运行大量命令,而不是使用shell循环

如果您不想在makefile中直接列出子目录(我个人总是手工列出它们:这样更安全,也没什么大不了的,因为新目录不会一直出现),那么要查找包含makefiles的所有直接子目录,您可以:

SUBDIRS := $(patsubst %/Makefile,%,$(wildcard */Makefile))
现在找出用户要求的目标。如果他们没有要求,我们将使用
all
作为默认目标(当然,如果您愿意,您可以更改此目标):

然后创建依赖于所有子目录的目标,对于每个子目录,运行命令行中给出的相同目标:

.PHONY: $(GOALS) $(SUBDIRS)
$(GOALS): $(SUBDIRS)
$(SUBDIRS):
        $(MAKE) -C $@ $(MAKECMDGOALS)

注意,这显然只适用于GNU make。

更好的解决方案是使用make运行大量命令的自然能力,而不是使用shell循环

如果您不想在makefile中直接列出子目录(我个人总是手工列出它们:这样更安全,也没什么大不了的,因为新目录不会一直出现),那么要查找包含makefiles的所有直接子目录,您可以:

SUBDIRS := $(patsubst %/Makefile,%,$(wildcard */Makefile))
现在找出用户要求的目标。如果他们没有要求,我们将使用
all
作为默认目标(当然,如果您愿意,您可以更改此目标):

然后创建依赖于所有子目录的目标,对于每个子目录,运行命令行中给出的相同目标:

.PHONY: $(GOALS) $(SUBDIRS)
$(GOALS): $(SUBDIRS)
$(SUBDIRS):
        $(MAKE) -C $@ $(MAKECMDGOALS)

注意,这显然只适用于GNU make。

这里有几个问题:首先,在调用子make时,您不应该使用
make
。您应该始终使用变量
$(MAKE)
(或者
${MAKE}
,如果您愿意的话)。其次,您不需要在子shell中运行子make(您不需要
参数)。第三,无论是
-k
还是
-j
make选项,这都不能正常工作,因为所有子make都是从一个配方调用的。这里有几个问题:首先,在调用子make时,绝不能使用
make
。您应该始终使用变量
$(MAKE)
(或者
${MAKE}
,如果您愿意的话)。其次,您不需要在子shell中运行子make(您不需要
参数)。第三,无论是
-k
还是
-j
make选项,这都不能正常工作,因为所有子make都是从一个配方调用的。我更喜欢你的通配符,而不是我的通配符,测试后会偷取。我认为没有必要并行生成子make,因为任何给定的make都将尝试使用多个作业,不是吗?例如,如果我想要十个并行作业,并给出-j10,我不想模拟生成四个孩子,所有的孩子都试图做-j10。只是将控制传递给另一个-j10品牌,等待它完成,然后运行另一个应该可以吗?我的意思是,我自己正在运行多达9个其他作业,所以即使我写的内容也太多了,除非你看到解决方案?GNU make提供了一个“jobserver”工具,其中所有递归调用的make实例共享一组作业令牌。因此,如果您运行
-j10
,那么无论使用多少个make递归调用,在所有这些实例上同时运行的作业都不会超过10个。对不起,我打错了。现在修好了。我更喜欢你的通配符而不是我的,测试后会偷。我认为没有必要并行生成子make,因为任何给定的make都将尝试使用多个作业,不是吗?例如,如果我想要十个并行作业,并给出-j10,我不想模拟生成四个孩子,所有的孩子都试图做-j10。只是将控制权传递给另一个-j10品牌,等待它完成