make 的静态模式和条件
Static patterns and conditionals with make
我对 GNU Make 4.2.1 有疑问。好像有一些互动
static pattern rules 和 条件语法之间
功能我不太明白。
上下文:我有一个由一组 Markdown 文件记录的项目,并且
我想将这些文件渲染到 HTML 以检查它们
本地。目录结构最终应如下所示:
some_project/
├── README.md # entry page of documentation
├── doc/ # extra docs
│ ├── foo.md
│ ├── bar.md
│ └── ... # and some more
└── doc_html/ # HTML rendering of the docs
├── Makefile # the Makefile I am trying to write
├── index.html # rendered from README.md
├── foo.html # ............. doc/foo.md
├── bar.html # ............. doc/bar.md
└── ... # etc.
如果没有 index.html 的特殊情况,我可以这样写:
%.html: ../doc/%.md
some list of commands $< $@
问题是index.html的前提(即../README.md)
与模式不匹配。我想处理这个特殊情况
无需重复整个命令列表。这就是我所拥有的
到目前为止:
DOC_PAGES = $(wildcard ../doc/*.md)
TARGETS = index.html $(patsubst %.md,%.html,$(notdir $(DOC_PAGES)))
# Function to find the source for page $(1)
source = $(if $(findstring index.html,$(1)), \
../README.md, \
$(patsubst %.html,../doc/%.md,$(1)) \
)
all: $(TARGETS)
$(TARGETS): %.html: $(call source,%.html)
@echo some list of commands $< $@
# Check the TARGETS variable and the `source' function
test:
@echo TARGETS = $(TARGETS)
@echo "source(index.html)" = $(call source,index.html)
@echo "source(foo.html)" = $(call source,foo.html)
我的 source
功能似乎有效:
$ make test
TARGETS = index.html bar.html foo.html
source(index.html) = ../README.md
source(foo.html) = ../doc/foo.md
但是,它在静态规则中表现不正常
$ make
make: *** No rule to make target '../doc/index.md', needed by 'index.html'. Stop.
请注意,如果我从 $(TARGETS)
中删除 index.html,该规则会起作用。
知道我做错了什么吗?
这一行:
$(TARGETS): %.html: $(call source,%.html)
无法工作,因为您正在使用文字字符串 %.html
的参数扩展 source
宏。您不能在先决条件列表中的宏中使用模式或自动变量:在解析或扩展模式之前先扩展宏。
但是,在我看来,您使这种方式变得比需要的更复杂。如果你的大部分目标都是以一种方式构建的,但有一些是用不同的方式构建的,那么只需为 "most" 创建一个模式规则并为 "some":
编写明确的规则
%.html: ../doc/%.md
some list of commands $< $@
index.html : ../README.md
commands to build index.html
如果命令集相同并且您不想重复它们,请将它们放在一个变量中:
create_html = some list of commands $< $@
%.html: ../doc/%.md
$(create_html)
index.html : ../README.md
$(create_html)
(如果要在脚本中包含 $<
和 $@
,请务必使用 =
而不是 :=
创建变量)。
ETA 您询问了为什么事情似乎有效:当 make 扩展它时,它将替换文字字符串 %.html
。您可以通过添加如下所示的 $(info...)
调用来向自己证明这一点:
source = $(info 1=$(1)) $(if $(findstring index.html,$(1)), \
../README.md, \
$(patsubst %.html,../doc/%.md,$(1)) \
)
你会看到它会打印(只打印一次,因为规则只展开一次)1=%.html
.
接下来会发生什么?那么这意味着您的宏扩展为:
$(if $(findstring index.html,%.html), ../README.md, $(patsubst %.html,../doc/%.md,%.html))
(再次使用文字字符串 %.html
)。 findstring
始终 returns 为空,因为在字符串 %.html
中找不到 index.html
,因此您展开 else 子句:
$(patsubst %.html,../doc/%.md,%.html)
显然 %.html
将 %.html
与词干 %
匹配,因此进行了替换 returns ../doc/%.md
。所以毕竟你的规则是这样的:
$(TARGETS): %.html: ../doc/%.md
@echo some list of commands $< $@
这完全与您之前的简单模式规则相同。
这似乎是一个解决方案:
DOC_PAGES := $(wildcard ../doc/*.md)
TARGETS := index.html $(patsubst %.md,%.html,$(notdir $(DOC_PAGES)))
all: $(TARGETS)
.INTERMEDIATE: ../doc/index.md
../doc/index.md: ../README.md
cp $< $@
%.html: ../doc/%.md
@echo some list of commands $< $@
test:
@echo $(TARGETS)
输出:
$ make
cp ../README.md ../doc/index.md
some list of commands ../doc/index.md index.html
some list of commands ../doc/bar.md bar.html
some list of commands ../doc/foo.md foo.html
rm ../doc/index.md
index.html通过pattern规则查找../doc/index.md,导致配方复制../README.md.
.INTERMEDIATE 特殊目标的先决条件在 make 完成时被移除。可选。
我对 GNU Make 4.2.1 有疑问。好像有一些互动 static pattern rules 和 条件语法之间 功能我不太明白。
上下文:我有一个由一组 Markdown 文件记录的项目,并且 我想将这些文件渲染到 HTML 以检查它们 本地。目录结构最终应如下所示:
some_project/
├── README.md # entry page of documentation
├── doc/ # extra docs
│ ├── foo.md
│ ├── bar.md
│ └── ... # and some more
└── doc_html/ # HTML rendering of the docs
├── Makefile # the Makefile I am trying to write
├── index.html # rendered from README.md
├── foo.html # ............. doc/foo.md
├── bar.html # ............. doc/bar.md
└── ... # etc.
如果没有 index.html 的特殊情况,我可以这样写:
%.html: ../doc/%.md
some list of commands $< $@
问题是index.html的前提(即../README.md) 与模式不匹配。我想处理这个特殊情况 无需重复整个命令列表。这就是我所拥有的 到目前为止:
DOC_PAGES = $(wildcard ../doc/*.md)
TARGETS = index.html $(patsubst %.md,%.html,$(notdir $(DOC_PAGES)))
# Function to find the source for page $(1)
source = $(if $(findstring index.html,$(1)), \
../README.md, \
$(patsubst %.html,../doc/%.md,$(1)) \
)
all: $(TARGETS)
$(TARGETS): %.html: $(call source,%.html)
@echo some list of commands $< $@
# Check the TARGETS variable and the `source' function
test:
@echo TARGETS = $(TARGETS)
@echo "source(index.html)" = $(call source,index.html)
@echo "source(foo.html)" = $(call source,foo.html)
我的 source
功能似乎有效:
$ make test
TARGETS = index.html bar.html foo.html
source(index.html) = ../README.md
source(foo.html) = ../doc/foo.md
但是,它在静态规则中表现不正常
$ make
make: *** No rule to make target '../doc/index.md', needed by 'index.html'. Stop.
请注意,如果我从 $(TARGETS)
中删除 index.html,该规则会起作用。
知道我做错了什么吗?
这一行:
$(TARGETS): %.html: $(call source,%.html)
无法工作,因为您正在使用文字字符串 %.html
的参数扩展 source
宏。您不能在先决条件列表中的宏中使用模式或自动变量:在解析或扩展模式之前先扩展宏。
但是,在我看来,您使这种方式变得比需要的更复杂。如果你的大部分目标都是以一种方式构建的,但有一些是用不同的方式构建的,那么只需为 "most" 创建一个模式规则并为 "some":
编写明确的规则%.html: ../doc/%.md
some list of commands $< $@
index.html : ../README.md
commands to build index.html
如果命令集相同并且您不想重复它们,请将它们放在一个变量中:
create_html = some list of commands $< $@
%.html: ../doc/%.md
$(create_html)
index.html : ../README.md
$(create_html)
(如果要在脚本中包含 $<
和 $@
,请务必使用 =
而不是 :=
创建变量)。
ETA 您询问了为什么事情似乎有效:当 make 扩展它时,它将替换文字字符串 %.html
。您可以通过添加如下所示的 $(info...)
调用来向自己证明这一点:
source = $(info 1=$(1)) $(if $(findstring index.html,$(1)), \
../README.md, \
$(patsubst %.html,../doc/%.md,$(1)) \
)
你会看到它会打印(只打印一次,因为规则只展开一次)1=%.html
.
接下来会发生什么?那么这意味着您的宏扩展为:
$(if $(findstring index.html,%.html), ../README.md, $(patsubst %.html,../doc/%.md,%.html))
(再次使用文字字符串 %.html
)。 findstring
始终 returns 为空,因为在字符串 %.html
中找不到 index.html
,因此您展开 else 子句:
$(patsubst %.html,../doc/%.md,%.html)
显然 %.html
将 %.html
与词干 %
匹配,因此进行了替换 returns ../doc/%.md
。所以毕竟你的规则是这样的:
$(TARGETS): %.html: ../doc/%.md
@echo some list of commands $< $@
这完全与您之前的简单模式规则相同。
这似乎是一个解决方案:
DOC_PAGES := $(wildcard ../doc/*.md)
TARGETS := index.html $(patsubst %.md,%.html,$(notdir $(DOC_PAGES)))
all: $(TARGETS)
.INTERMEDIATE: ../doc/index.md
../doc/index.md: ../README.md
cp $< $@
%.html: ../doc/%.md
@echo some list of commands $< $@
test:
@echo $(TARGETS)
输出:
$ make
cp ../README.md ../doc/index.md
some list of commands ../doc/index.md index.html
some list of commands ../doc/bar.md bar.html
some list of commands ../doc/foo.md foo.html
rm ../doc/index.md
index.html通过pattern规则查找../doc/index.md,导致配方复制../README.md.
.INTERMEDIATE 特殊目标的先决条件在 make 完成时被移除。可选。