如何用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
相关产品推荐
相关产品推荐

