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

如何用Make生成镜像目录结构?修改Makefile后子目录文件生成失败原因

问题说明

我有一个名为markdown的目录,其中包含.md文件及子目录,希望为每个md文件生成对应的html文件。

原Makefile可实现需求但需要单独的build目录:

SOURCES = $(shell find ./markdown -name "*.md")
HTML = $(patsubst ./markdown/%.md,./build/%.html,$(SOURCES))

all: $(HTML)

build/%.html: markdown/%.md
    @echo -e "Convert markdown file [$<] to html [$@]."

我希望在markdown目录的父目录(项目根目录)生成文件,即最终目录结构如下:

./index.html
./foo/bar/hum/another.html
./markdown/index.md
./markdown/foo/bar/hum/another.md

我尝试移除两处build/,修改后的代码如下:

HTML = $(patsubst ./markdown/%.md,./%.html,$(SOURCES))

和

%.html: markdown/%.md
    @echo -e "Convert markdown file [$<] to html [$@]."

但这仅能成功生成顶层文件(如./markdown/index.md对应的./index.html),子目录中的文件(如./markdown/foo/bar/hum/another.md)无法生成对应html文件,请问这是为什么?

原因分析

问题核心是目标文件的父目录不存在:

  • 生成顶层文件./index.html时,根目录本身就存在,所以能正常输出。
  • 生成子目录下的./foo/bar/hum/another.html时,foo/bar/hum这个嵌套路径在根目录下并未创建,而Make不会自动为目标文件创建缺失的父目录,因此无法写入html文件,导致生成失败。

原Makefile的build/%.html模式能正常工作,是因为通常会提前创建build目录,或者实际转换命令中隐含了创建子目录的逻辑(示例仅保留了echo步骤)。

解决方案

需要在生成html文件前,确保目标文件的父目录已存在,以下两种方式均可实现:

方式一:在规则中直接创建目录

修改模式规则,用mkdir -p创建目标文件的父目录:

SOURCES = $(shell find ./markdown -name "*.md")
HTML = $(patsubst ./markdown/%.md,./%.html,$(SOURCES))

all: $(HTML)

%.html: markdown/%.md
    @mkdir -p $(@D)  # $(@D)是Make自动变量,代表目标文件的目录部分
    @echo -e "Convert markdown file [$<] to html [$@]."

方式二:单独定义目录创建依赖

先提取所有需要的目录,确保目录先于html文件创建:

SOURCES = $(shell find ./markdown -name "*.md")
HTML = $(patsubst ./markdown/%.md,./%.html,$(SOURCES))
# 提取所有html文件的父目录并去重
HTML_DIRS = $(sort $(dir $(HTML)))

all: $(HTML)

# 先创建所有需要的目录
$(HTML_DIRS):
    @mkdir -p $@

# 用|标记顺序依赖,确保目录先创建再生成文件
%.html: markdown/%.md | $(HTML_DIRS)
    @echo -e "Convert markdown file [$<] to html [$@]."

内容的提问来源于stack exchange,提问作者Bobby Jack

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 17:30:05