我试图将make用作静态站点生成器(类似于Jekyll)。源位于文件夹中,并运行make
以将输出生成到单独的目录“ build”中。
源具有以下结构:
src
├── about.md
├── css
│ └── style.css
├── index.md
└─── posts
├── 2019-07-30-a-blog-post.md
├── 2019-07-08-another-post.md
└── 2019-08-01-something-else.md
我正在尝试获得这样的输出:
build
├── 2019
│ ├── 07
│ │ ├── a-blog-post
│ │ │ └── index.html
│ │ ├── another-post
│ │ │ └── index.html
│ └── 08
│ └── something-else
│ └── index.html
├── about
│ └── index.html
├── css
│ └── style.min.css
└── index.html
这是我当前的文件...
define generateHTML
mkdir -p $(dir $1)
pandoc -f markdown -t html5 -o $1 $2 -s
endef
SRC = src
DST = build
MARKDOWNFILES := $(filter-out $(SRC)/index.md, $(wildcard $(SRC)/*.md))
HTMLTARGETS := $(MARKDOWNFILES:src/%.md=build/%/index.html)
BLOG_MARKDOWNFILES := $(wildcard $(SRC)/posts/*.md)
### [WARNING] Hacky section here ###
# Replace '-' with ' ' for all parts of file basename
FINDREPLACE = $(subst -, ,$(basename $(notdir $(mdf))))
# Get the first 3 words of the space-separated list (YYYY MM DD)
# & format as YYYY/MM/DD-
# & replace all '/' characters with '-'
FINDREPLACE1A = $(subst /,-,$(word 1, $(FINDREPLACE))/$(word 2, $(FINDREPLACE))/$(word 3,$(FINDREPLACE)))-
# Replace the full path string, with the above.
# Get the filename, minus 'YYYY-MM-DD-' prefix.
FINDREPLACE1B = $(subst $(FINDREPLACE1A),$e,$(basename $(notdir $(mdf))))
# Build the full string required for HTMLTARGET variable
# & format into 'build/YY/MM/<string>/index.html'
findReplace2 = build/$(word 1, $(FINDREPLACE))/$(word 2, $(FINDREPLACE))/$(FINDREPLACE1B)/index.html
BLOG_HTMLTARGETS := $(foreach mdf, $(BLOG_MARKDOWNFILES),$(findReplace2))
all: build/index.html $(HTMLTARGETS) $(BLOG_HTMLTARGETS)
# This generates the root index.html
build/index.html: src/index.md
$(call generateHTML, $@, $<)
# This generates the about/index.html pages, etc.
build/%/index.html: src/%.md
$(call generateHTML, $@, $<)
### [WARNING] Hacky section here ###
build/%/index.html: $(BLOG_MARKDOWNFILES)
$(eval WORDLIST = $(filter-out build,$(subst /,$e ,$(subst -,$e ,$(@D)))))
$(eval QUERY = $(SRC)/posts/$(word 1,$(WORDLIST))-$(word 2,$(WORDLIST))%$(word $(words $(WORDLIST)),$(WORDLIST)).md)
$(eval FUZZY_FILE = $(filter $(QUERY),$(BLOG_MARKDOWNFILES)))
$(call generateHTML, $@, $(FUZZY_FILE))
# Tidy-up
.PHONY: clean
clean:
rm -Rf $(DST)
我已经设法将某些东西凑在一起-使用内置函数subst
/ word
/ words
/ filter
进行查找/替换和匹配-这样做成功生成了我想要的输出,但是每次更新一个文件时,它都会重新生成 all 个文件,这似乎很不理想。
是否有一种直接的方法来操纵Makefile的目标/依赖关系字符串,以执行类似的操作?
src/posts/YYYY-MM-DD-post.md => build/YYYY/MM/post/index.html
答案 0 :(得分:0)
这可能是foreach-eval-call
的任务:
SUBDIRS :=
POSTS := $(notdir $(wildcard $(SRC)/posts/*.md))
.PHONY: all
.DEFAULT_GOAL := all
define MY_rule
$1.split := $$(subst -, ,$1)
$1.year := $$(word 1,$$($1.split))
$1.month := $$(word 2,$$($1.split))
$1.day := $$(word 3,$$($1.split))
$1.name := $$(patsubst $$($1.year)-$$($1.month)-$$($1.day)-%.md,%,$1)
$1.dir := $$(DST)/$$($1.year)/$$($1.month)/$$($1.name)
$$($1.dir)/index.html: $$(SRC)/posts/$1 | $$($1.dir)
$$(call generateHTML,$$<,$$@)
all: $$($1.dir)/index.html
SUBDIRS += $$($1.dir)
endef
$(foreach p,$(POSTS),$(eval $(call MY_rule,$(p))))
SUBDIRS := $(sort $(SUBDIRS))
$(SUBDIRS):
mkdir -p $@
演示:
$ make
mkdir -p build/2019/08/something-else
pandoc -f markdown -t html5 -o src/posts/2019-08-01-something-else.md build/2019/08/something-else/index.html -s
mkdir -p build/2019/07/another-post
pandoc -f markdown -t html5 -o src/posts/2019-07-08-another-post.md build/2019/07/another-post/index.html -s
mkdir -p build/2019/07/a-blog-post
pandoc -f markdown -t html5 -o src/posts/2019-07-30-a-blog-post.md build/2019/07/a-blog-post/index.html -s
答案 1 :(得分:0)
有多种方法可以实现,但是没有一种方法特别干净。
第一个问题是将源名称转换为目标名称,例如
src/posts/2019-07-08-another-post.md => build/2019/07/another-post/index.html
一个聪明的受虐狂可以使用Make函数来做到这一点,但我可能只是调用sed:
SRC := src/posts/2019-07-08-another-post.md
TARG = $(shell echo $(SRC) | sed 's|src/posts/\(....\)-\(..\)-..-\(.*\)\.md|build/\1/\2/\3/index.html|')
有了SRC
和TARG
之后,编写规则就很容易了。让Make自动编写规则会有点困难,但是我们可以使用模板来做到这一点:
define template
SRC := $(1)
$$(TARG): $(1)
@echo building $$@ from $$^
$(call generateHTML, $$@, $$<)
endef
$(eval $(call template,$(SOME_SOURCE)))
现在我们要做的就是遍历源文件,为每个文件创建一条规则:
$(foreach MF,$(BLOG_MARKDOWNFILES),$(eval $(call template,$(MF))))