包含子目录的 makefile
makefile with subdirectories
我正在写一本书。这些章节将以 Markdown (.md) 编写,然后使用 pandoc 转换为 html 和 pdf(通过 LaTeX)版本。每章都有一些相关联的 Python 脚本,这些脚本会生成一些图像,并且需要 运行 在构建章节之前。我正在尝试编写一个将所有章节编译为这两种格式的 makefile。
目前,项目结构如下:
project
|--- makefile
|--- chapters
| --- chapter1
| --- main.md
| --- genimage.py
| --- genanotherimage.py
| --- chapter2
|--- main.md
|--- otherimage.py
| --- output
| --- html
| --- chapter1.html
| --- chapter2.html
| --- pdf
| --- chapter1.pdf
| --- chapter2.pdf
我想输入“make chapter1”(或类似的)并让它刷新 output/html/chapter1.html 和 output/pdf/chapter1.pdf,重新 运行如果它们已更改,则将相应目录中的所有 .py 脚本。理想情况下,我会有一个规则来并行处理所有章节,而不是每个章节都有一个单独的规则。 (实际生成 html/pdf 的命令是“pandoc -o output/html/chapter1.html chapter1/main.md”等等。)
我对make不是很熟悉,到目前为止我的尝试都没有成功。我无法设法在有多个文件要更新的地方建立目标,而且我还没有设法使用模式来处理具有单个规则的每一章。如果可以让事情变得更简单,我很乐意进行一些重组。
这个工作流程可以用 makefile 实现吗?我很感激任何开始的提示;我不知所措,即使知道在手册中查找正确的内容也会非常有帮助。
以下内容基于您显示的项目树并假定为 GNU make。它还假定您必须 运行 pandoc
和项目顶级目录中的 python 脚本。模式规则可能会有所帮助:
CHAPTERS := $(notdir $(wildcard chapters/chapter*))
.PHONY: all $(CHAPTERS)
all: $(CHAPTERS)
$(CHAPTERS): %: chapters/output/html/%.html chapters/output/pdf/%.pdf
chapters/output/html/%.html chapters/output/pdf/%.pdf: chapters/%/main.md
for python_script in $(wildcard $(<D)/*.py); do ./$$python_script; done
mkdir -p chapters/output/html chapters/output/pdf
pandoc -o chapters/output/html/$*.html <other-options> $<
pandoc -o chapters/output/pdf/$*.pdf <other-options> $<
主要的微妙之处在于,当 GNU make 遇到具有多个目标的模式规则时,它会认为单次执行配方会构建所有目标。在我们的例子中,HTML 和 PDF 输出是由相同的配方执行产生的。
Note: with recent versions of GNU make rules with grouped targets (&:
) do the same.
这不是 100% 完美,因为如果您修改或添加 python 脚本,章节将不会重建。如果您也需要这个,我们将需要更复杂的 GNU make 功能,例如 secondary expansion or eval
.
二次扩展示例:
CHAPTERS := $(notdir $(wildcard chapters/chapter*))
.PHONY: all $(CHAPTERS)
all: $(CHAPTERS)
$(CHAPTERS): %: chapters/output/html/%.html chapters/output/pdf/%.pdf
.SECONDEXPANSION:
chapters/output/html/%.html chapters/output/pdf/%.pdf: chapters/%/main.md $$(wildcard chapters/$$*/*.py)
for python_script in $(wildcard $(<D)/*.py); do ./$$python_script; done
mkdir -p chapters/output/html chapters/output/pdf
pandoc -o chapters/output/html/$*.html $<
pandoc -o chapters/output/pdf/$*.pdf $<
要了解 $$(wildcard chapters/$$*/*.py)
中 $$
的原因,请参阅 the GNU make manual。
示例eval
:
CHAPTERS := $(notdir $(wildcard chapters/chapter*))
.PHONY: all $(CHAPTERS)
all: $(CHAPTERS)
$(CHAPTERS): %: chapters/output/html/%.html chapters/output/pdf/%.pdf
# : chapter
define CHAPTER_RULE
PYTHON_SCRIPTS_ := $$(wildcard chapters//*.py)
chapters/output/html/.html chapters/output/pdf/.pdf: chapters//main.md $$(PYTHON_SCRIPTS_)
for python_script in $$(PYTHON_SCRIPTS_); do ./$$$$python_script; done
mkdir -p chapters/output/html chapters/output/pdf
pandoc -o chapters/output/html/.html $$<
pandoc -o chapters/output/pdf/.pdf $$<
endef
$(foreach c,$(CHAPTERS),$(eval $(call CHAPTER_RULE,$c)))
要了解 $$
或 $$$$
的原因,请参阅 the GNU make manual。
我正在写一本书。这些章节将以 Markdown (.md) 编写,然后使用 pandoc 转换为 html 和 pdf(通过 LaTeX)版本。每章都有一些相关联的 Python 脚本,这些脚本会生成一些图像,并且需要 运行 在构建章节之前。我正在尝试编写一个将所有章节编译为这两种格式的 makefile。
目前,项目结构如下:
project
|--- makefile
|--- chapters
| --- chapter1
| --- main.md
| --- genimage.py
| --- genanotherimage.py
| --- chapter2
|--- main.md
|--- otherimage.py
| --- output
| --- html
| --- chapter1.html
| --- chapter2.html
| --- pdf
| --- chapter1.pdf
| --- chapter2.pdf
我想输入“make chapter1”(或类似的)并让它刷新 output/html/chapter1.html 和 output/pdf/chapter1.pdf,重新 运行如果它们已更改,则将相应目录中的所有 .py 脚本。理想情况下,我会有一个规则来并行处理所有章节,而不是每个章节都有一个单独的规则。 (实际生成 html/pdf 的命令是“pandoc -o output/html/chapter1.html chapter1/main.md”等等。)
我对make不是很熟悉,到目前为止我的尝试都没有成功。我无法设法在有多个文件要更新的地方建立目标,而且我还没有设法使用模式来处理具有单个规则的每一章。如果可以让事情变得更简单,我很乐意进行一些重组。
这个工作流程可以用 makefile 实现吗?我很感激任何开始的提示;我不知所措,即使知道在手册中查找正确的内容也会非常有帮助。
以下内容基于您显示的项目树并假定为 GNU make。它还假定您必须 运行 pandoc
和项目顶级目录中的 python 脚本。模式规则可能会有所帮助:
CHAPTERS := $(notdir $(wildcard chapters/chapter*))
.PHONY: all $(CHAPTERS)
all: $(CHAPTERS)
$(CHAPTERS): %: chapters/output/html/%.html chapters/output/pdf/%.pdf
chapters/output/html/%.html chapters/output/pdf/%.pdf: chapters/%/main.md
for python_script in $(wildcard $(<D)/*.py); do ./$$python_script; done
mkdir -p chapters/output/html chapters/output/pdf
pandoc -o chapters/output/html/$*.html <other-options> $<
pandoc -o chapters/output/pdf/$*.pdf <other-options> $<
主要的微妙之处在于,当 GNU make 遇到具有多个目标的模式规则时,它会认为单次执行配方会构建所有目标。在我们的例子中,HTML 和 PDF 输出是由相同的配方执行产生的。
Note: with recent versions of GNU make rules with grouped targets (
&:
) do the same.
这不是 100% 完美,因为如果您修改或添加 python 脚本,章节将不会重建。如果您也需要这个,我们将需要更复杂的 GNU make 功能,例如 secondary expansion or eval
.
二次扩展示例:
CHAPTERS := $(notdir $(wildcard chapters/chapter*))
.PHONY: all $(CHAPTERS)
all: $(CHAPTERS)
$(CHAPTERS): %: chapters/output/html/%.html chapters/output/pdf/%.pdf
.SECONDEXPANSION:
chapters/output/html/%.html chapters/output/pdf/%.pdf: chapters/%/main.md $$(wildcard chapters/$$*/*.py)
for python_script in $(wildcard $(<D)/*.py); do ./$$python_script; done
mkdir -p chapters/output/html chapters/output/pdf
pandoc -o chapters/output/html/$*.html $<
pandoc -o chapters/output/pdf/$*.pdf $<
要了解 $$(wildcard chapters/$$*/*.py)
中 $$
的原因,请参阅 the GNU make manual。
示例eval
:
CHAPTERS := $(notdir $(wildcard chapters/chapter*))
.PHONY: all $(CHAPTERS)
all: $(CHAPTERS)
$(CHAPTERS): %: chapters/output/html/%.html chapters/output/pdf/%.pdf
# : chapter
define CHAPTER_RULE
PYTHON_SCRIPTS_ := $$(wildcard chapters//*.py)
chapters/output/html/.html chapters/output/pdf/.pdf: chapters//main.md $$(PYTHON_SCRIPTS_)
for python_script in $$(PYTHON_SCRIPTS_); do ./$$$$python_script; done
mkdir -p chapters/output/html chapters/output/pdf
pandoc -o chapters/output/html/.html $$<
pandoc -o chapters/output/pdf/.pdf $$<
endef
$(foreach c,$(CHAPTERS),$(eval $(call CHAPTER_RULE,$c)))
要了解 $$
或 $$$$
的原因,请参阅 the GNU make manual。