Makefile 带make的静态模式和条件句
我对GNU Make 4.2.1有问题。似乎有一些互动 和之间的语法,我不太明白 上下文:我有一个由一组标记文件记录的项目,并且 我想将这些文件呈现为HTML,以便检查它们 在当地。目录结构最终应如下所示:Makefile 带make的静态模式和条件句,makefile,gnu-make,Makefile,Gnu Make,我对GNU Make 4.2.1有问题。似乎有一些互动 和之间的语法,我不太明白 上下文:我有一个由一组标记文件记录的项目,并且 我想将这些文件呈现为HTML,以便检查它们 在当地。目录结构最终应如下所示: some_project/ ├── README.md # entry page of documentation ├── doc/ # extra docs │ ├── foo.md │ ├── bar.md │ └── ...
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.
source = $(info 1=$(1)) $(if $(findstring index.html,$(1)), \
../README.md, \
$(patsubst %.html,../doc/%.md,$(1)) \
)
$(TARGETS): %.html: ../doc/%.md
@echo some list of commands $< $@
如果没有index.html的特殊情况,我可以编写如下内容:
%.html: ../doc/%.md
some list of commands $< $@
但是,它在静态规则中的行为不正常
$ make
make: *** No rule to make target '../doc/index.md', needed by 'index.html'. Stop.
请注意,如果我从$TARGETS中删除index.html,则该规则确实有效
知道我做错了什么吗?这一行:
$(TARGETS): %.html: $(call source,%.html)
无法工作,因为您正在使用文本字符串%.html的参数展开源宏。不能在先决条件列表中的宏中使用模式或自动变量:首先展开宏,然后再解析或展开模式
然而,在我看来,你让这条路变得比需要的更复杂了。如果您的大多数目标是以一种方式构建的,但也有一些是以不同的方式构建的,那么只需为大多数目标创建一个模式规则,并为某些目标编写明确的规则:
%.html: ../doc/%.md
some list of commands $< $@
index.html : ../README.md
commands to build index.html
您将看到它只打印一次,因为该规则仅扩展一次1=%.html
接下来会发生什么?这意味着您的宏将扩展为:
$(if $(findstring index.html,%.html), ../README.md, $(patsubst %.html,../doc/%.md,%.html))
再次使用文本字符串%.html。findstring始终返回空,因为在字符串%.html中找不到index.html,因此展开else子句:
$(patsubst %.html,../doc/%.md,%.html)
显然%.html与带有%词干的%.html匹配,因此进行替换并返回../doc/%.md。因此,在所有这些之后,您的规则如下所示:
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.
source = $(info 1=$(1)) $(if $(findstring index.html,$(1)), \
../README.md, \
$(patsubst %.html,../doc/%.md,$(1)) \
)
$(TARGETS): %.html: ../doc/%.md
@echo some list of commands $< $@
这与您以前使用简单模式规则时所做的完全相同。这一行:
$(TARGETS): %.html: $(call source,%.html)
无法工作,因为您正在使用文本字符串%.html的参数展开源宏。不能在先决条件列表中的宏中使用模式或自动变量:首先展开宏,然后再解析或展开模式
然而,在我看来,你让这条路变得比需要的更复杂了。如果您的大多数目标是以一种方式构建的,但也有一些是以不同的方式构建的,那么只需为大多数目标创建一个模式规则,并为某些目标编写明确的规则:
%.html: ../doc/%.md
some list of commands $< $@
index.html : ../README.md
commands to build index.html
您将看到它只打印一次,因为该规则仅扩展一次1=%.html
接下来会发生什么?这意味着您的宏将扩展为:
$(if $(findstring index.html,%.html), ../README.md, $(patsubst %.html,../doc/%.md,%.html))
再次使用文本字符串%.html。findstring始终返回空,因为在字符串%.html中找不到index.html,因此展开else子句:
$(patsubst %.html,../doc/%.md,%.html)
显然%.html与带有%词干的%.html匹配,因此进行替换并返回../doc/%.md。因此,在所有这些之后,您的规则如下所示:
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.
source = $(info 1=$(1)) $(if $(findstring index.html,$(1)), \
../README.md, \
$(patsubst %.html,../doc/%.md,$(1)) \
)
$(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)
index.html通过模式规则查找../doc/index.md,导致配方复制../README.md
当make完成时,将删除.INTERMEDIATE特殊目标的先决条件。可选。这似乎是一个解决方案:
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)
index.html通过模式规则查找../doc/index.md,导致配方复制../README.md
当make完成时,将删除.INTERMEDIATE特殊目标的先决条件。可选。谢谢,但我不太理解“解析前展开”的问题“:如果目标不包含index.html,则该规则会按预期工作。至于create_html变量,如果没有其他选择,我可能会退回到此解决方案,但如果有许多命令,我会发现它很笨拙。我将在回答中解释谢谢,但我不太理解“解析前展开”的问题“:如果目标不包含index.html,则规则会按预期工作。至于create_html变量,如果没有其他选择,我可能会回退到此解决方案,但如果有许多命令,我会发现它很笨拙。我将在回答中解释,特别感谢人们指出我以前回答中的错误。Encore!我担心这个intermediate copy会搞乱make是否需要重新呈现文件,但事实证明它处理得相当巧妙。采用了解决方案,将cp替换为ln-s。特别感谢人们指出了我之前回答中的错误。Encore!我担心这个中间副本会搞乱make Figulating whet她说,文件必须重新渲染,但事实证明它处理得相当巧妙。采用了解决方案,将cp替换为ln-s。