You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何以更符合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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 03:14:52