如何以更符合Make风格的方式实现递归gmake并补全子目录Makefile
问题
需求是让gmake在所有子目录中递归执行编译,但需先检查子目录是否存在Makefile,若不存在则从../somewhere/Makefile.default复制到该子目录。现有实现可正常运行,但希望采用更符合Make规范的写法。
尝试过两种方案:
- 如下写法无法生效(
$@为空):
# $@ evaluates to "" $(SUBDIRS)::$@/Makefile
- 如下写法功能可行,但会一次性创建所有子目录的Makefile,不符合预期依赖关系:
SUBDIRMAKEFILES = ${patsubst %,%/Makefile,${SUBDIRS}} $(SUBDIRS)::$(SUBDIRMAKEFILES) @echo;echo;echo;echo;echo $(MAKE) --no-print-directory -C $@ $(MAKECMDGOALS) $(SUBDIRMAKEFILES): cp ../somewhere/Makefile.default $@/Makefile
当前可用的实现代码:
SUBDIRS = ${sort ${patsubst %/,%,${dir ${wildcard */}}}} all $(MAKECMDGOALS):: $(SUBDIRS) .PHONY: $(SUBDIRS) $(SUBDIRS):: @echo;echo;echo;echo;echo [ -f $@/Makefile] || cp ../somewhere/Makefile.default $@/Makefile $(MAKE) --no-print-directory -C $@ $(MAKECMDGOALS)
请问是否有更简洁、符合Make规范的实现方式?
符合Make规范的优化实现
可以通过为每个子目录的Makefile建立独立依赖的方式实现,既符合Make的依赖管理逻辑,又能保证仅在需要时才创建缺失的Makefile:
# 自动获取所有子目录(过滤路径末尾斜杠并去重) SUBDIRS := $(sort $(patsubst %/,%,$(dir $(wildcard */)))) # 定义子目录规则模板 define SUBDIR_RULE $(1): $(1)/Makefile @echo "==== 编译子目录: $(1) ====" $(MAKE) --no-print-directory -C $(1) $(MAKECMDGOALS) $(1)/Makefile: @[ -f $$@ ] || cp ../somewhere/Makefile.default $$@ endef # 批量生成所有子目录的规则 $(foreach DIR,$(SUBDIRS),$(eval $(call SUBDIR_RULE,$(DIR)))) # 将所有目标绑定到子目录编译任务 all $(MAKECMDGOALS):: $(SUBDIRS) # 显式声明伪目标,避免与同名文件冲突 .PHONY: $(SUBDIRS) all $(MAKECMDGOALS)
核心优势
- 精准依赖触发:每个子目录的编译任务仅依赖自身的Makefile,不会一次性生成所有子目录的Makefile,完全遵循Make的依赖驱动执行逻辑。
- 代码可维护性高:通过模板批量生成规则,避免重复代码,后续修改子目录逻辑只需调整模板即可。
- 兼容手动修改:保留了
[ -f $$@ ] ||的检查逻辑,不会覆盖子目录中已存在的自定义Makefile。
替代简化写法(若无需保留手动修改的Makefile)
如果确定不需要保留子目录中已有的Makefile,可简化$(1)/Makefile的规则,直接强制复制:
$(1)/Makefile: cp ../somewhere/Makefile.default $$@
内容的提问来源于stack exchange,提问作者Swiss Frank
相关产品推荐
相关产品推荐

