我正在尝试静态构建HTML文件,该文件需要markdown文件和一个名为“ whatlinkshere”的元文件,以便HTML文件展示其back links。
我认为可以通过Makefile来完成,方法是首先生成所有“ whatlinkshere”文件。我不认为这可以并行完成,因为生成这些文件的程序需要追加到whatlinkshere文件中,并且可能存在我不太确定如何解决的竞争条件。
一旦生成了“ whatlinkshere”文件,则如果编辑了降价文件,则说 foo.mdwn指向bar.mdwn ,仅需要再次对foo.mdwn进行“ whatlinkshere”分析。变化。最后,仅需重新构建foo.html和bar.html。
我在backlinks project中努力做到这一点。
INFILES = $(shell find . -name "*.mdwn")
OUTFILES = $(INFILES:.mdwn=.html)
LINKFILES = $(INFILES:.mdwn=.whatlinkshere)
all: $(OUTFILES)
# These need to be all made before the HTML is processed
$(LINKFILES): $(INFILES)
@echo Creating backlinks $@
@touch $@
@go run backlinks.go $<
%.html: %.mdwn %.whatlinkshere
@echo Deps $^
@cmark $^ > $@
当前的问题是* .whatlinkshere **不在首次运行时生成。我的解决方法是for i in *.mdwn; do go run backlinks.go $i; done
。此外,如上所述,在编辑文件后没有进行所需的重建。发生严重错误。我想念什么?
答案 0 :(得分:2)
我想我终于了解了您的问题。如果我了解得很好:
*.mdwn
源文件。*.whatlinkshere
实用程序从*.mdwn
源文件生成backlinks.go
文件。但是,该实用程序不会从foo.whatlinkshere
产生foo.mdwn
。它分析foo.mdwn
,在其中搜索到其他页面的链接,并为找到的每个指向bar
的链接附加 [foo](foo.html)
}}。从每个bar.whatlinkshere
源文件中,您要使用以下命令构建相应的foo.mdwn
文件:
foo.html
您的规则:
$ cmark foo.mdwn foo.whatlinkshere
包含一个错误,并具有多个缺点。错误是在配方中使用了$(LINKFILES): $(INFILES)
@echo Creating backlinks $@
@touch $@
@go run backlinks.go $<
自动变量。它作为第一个先决条件扩展,在您的情况下,可能总是$<
。不是你想要的。 pageA.mdwn
会扩展为所有先决条件,但这不是正确的解决方案,因为:
$^
或通过向您的Makefile添加make -j1
特殊规则来防止这种情况,但这很可惜)种族条件。重要:以下内容仅适用于平面组织,其中所有源文件和HTML文件都与Makefile位于同一目录中。当然也可以使用其他组织,但是需要进行一些修改。
一种可能性是使用make模式规则的特殊属性:当它们具有多个目标时,make认为一次执行配方会产生所有目标。例如:
.NOTPARALLEL:
告诉人们pageA.w%e pageB.w%e pageC.w%e: pageA.mdwn pageB.mdwn pageC.mdwn
for m in $^; do go run backlinks.go $$m; done
,pageA.whatlinkshere
和pageB.whatlinkshere
都是由以下一次执行生成的:
pageC.whatlinkshere
(make将for m in pageA.mdwn pageB.mdwn pageC.mdwn; do go run backlinks.go $m; done
扩展为所有先决条件,将$^
扩展为$$m
)。当然,我们希望自动化$m
模式目标列表的计算。这应该做到:
pageA.w%e pageB.w%e pageC.w%e
注意:
INFILES := $(shell find . -name "*.mdwn")
OUTFILES := $(INFILES:.mdwn=.html)
LINKFILES := $(INFILES:.mdwn=.whatlinkshere)
LINKPATTERN := $(INFILES:.mdwn=.w%e)
.PHONY: all clean
.PRECIOUS: $(LINKFILES)
all: $(OUTFILES)
# These need to be all made before the HTML is processed
$(LINKPATTERN): $(INFILES)
@echo Creating backlinks
@rm -f $(LINKFILES)
@touch $(LINKFILES)
@for m in $^; do go run backlinks.go $$m; done
%.html: %.mdwn %.whatlinkshere
@echo Deps $^
@cmark $^ > $@
clean:
rm -f $(LINKFILES) $(OUTFILES)
和all
声明为phony,因为...这就是它们。clean
文件声明为precious是因为(其中一些文件)被make视为中间体,如果没有此声明,make会在构建HTML文件后将其删除。whatlinkshere
的{{1}}文件的食谱中,如果执行了食谱,我们将从干净状态重新开始,而不是将新内容连接到旧的(可能是过时的)引用。 / li>
whatlinkshere
中的模式词干可以是任何字符,但必须至少匹配一个字符。我使用了rm -f $(LINKFILES)
,但是$(LINKPATTERN)
也可以使用。使用适合您情况的足够具体的东西。如果您有w%e
文件,则最好使用whatlin%shere
或pageB.where
。此解决方案有一个缺点,但这是由于您的特定设置造成的:每次更改单个whatlin%shere
文件时,都必须重新分析(正常情况),但是必须重新分析任何what%here
文件可能会受到影响。这是无法预料的,它取决于此源文件中已修改的链接。但是更成问题的是,该分析的结果被附加到了受影响的mdwn
文件中。它们没有被“ 编辑”,相对于该源文件的旧内容被新文件替换。因此,如果仅更改源文件中的注释,则其所有链接将再次附加到各自的whatlinkshere
文件中(当它们已经存在时)。这可能不是您想要的。
这就是为什么上述解决方案在每次更改一个源文件时都删除所有whatlinkshere
文件并重新分析所有源文件的原因。另一个负面结果是,所有HTML文件也必须重新生成,因为所有whatlinkshere
文件都已更改(即使它们的内容并没有真正更改,但make不知道这一点)。如果分析速度非常快,并且您的whatlinkshere
文件数量很少,则应该可以。否则,它不是最佳选择,但由于您的特定设置而难以解决。
但是有一种可能性,其中包括:
whatlinkshere
文件分隔所有反向链接引用:mdwn
包含对在whatlinkshere
中找到的foo.backlinks/bar.whatlinkshere
的所有引用,bar
make变量时)使用递归make来更新所有需要的递归foo.mdwn
文件,第二次调用(STEP
设置为2)生成所需的HTML文件,whatlinkshere
个文件:STEP
,foo.mdwn
逃避第一拳的扩张)。但是它可能很难理解(和维护)。
foo.backlinks/.done
即使看起来更复杂,此版本也有一些优点:
$$
文件,INFILES := $(shell find . -name "*.mdwn")
OUTFILES := $(INFILES:.mdwn=.html)
DONEFILES := $(patsubst %.mdwn,%.backlinks/.done,$(INFILES))
.PHONY: all clean
ifeq ($(STEP),)
all $(OUTFILES): $(DONEFILES)
$(MAKE) STEP=2 $@
%.backlinks/.done: %.mdwn
rm -rf $(dir $@)
mkdir -p $(dir $@)
cp $< $(dir $@)
cd $(dir $@); go run ../backlinks.go $<; rm $<
touch $@
else
all: $(OUTFILES)
.SECONDEXPANSION:
%.html: %.mdwn $$(wildcard *.backlinks/$$*.whatlinkshere)
@echo Deps $^
@cmark $^ > $@
endif
clean:
rm -rf *.backlinks $(OUTFILES)
文件可以并行构建,如果您不关心结果不准确的情况,即反向链接从源文件中消失后仍然保留在结果中,或者反向链接被无用复制的情况,我们可以重用先前解决方案中的想法,但将各个字段之间的分离whatlinkshere
个文件。
whatlinkshere
注意:
whatlinkshere
替换了INFILES := $(wildcard *.mdwn)
OUTFILES := $(patsubst %.mdwn,%.html,$(INFILES))
LINKFILES := $(patsubst %.mdwn,%.whatlinkshere,$(INFILES))
DONEFILES := $(patsubst %.mdwn,.%.done,$(INFILES))
.PHONY: all clean
.PRECIOUS: $(LINKFILES)
ifeq ($(STEP),)
.NOTPARALLEL:
all $(OUTFILES): $(DONEFILES)
$(MAKE) STEP=2 $@
.%.done: %.mdwn
go run backlinks.go $<
touch $@
else
all: $(OUTFILES)
%.html: %.mdwn %.whatlinkshere
@echo Deps $^
@cmark $^ > $@
%.whatlinkshere:
touch $@
endif
clean:
rm -f $(OUTFILES) $(LINKFILES) $(DONEFILES)
。$(shell find...)
而不是旧的语法,但这只是一个问题。$(wildcard ...)
规则是用于创建丢失的空patsubst
文件的默认规则。%.whatlinkshere:
特殊目标可防止在构建whatlinkshere
文件时并行执行。