为什么在一个循环中 make 运行 一个特定规则 3 次?
Why does make run one specific rule 3 times in a loop?
我编写了一个 makefile,它采用 Word DOCX 文件并(在 tei-xslt、xslt 脚本和 saxon 的帮助下)在 TEI-XML、HTML 文件中生成表示,并且用于摄取到发布软件中的 zip 文件。不同的步骤应该是这样的:
DOCX -> TEI-XML -> HTML -> (manifest.yml) -> ZIP # (Expected)
问题是在进入 HTML 到 ZIP 规则之前,在循环中使 运行s TEI 到 HTML 规则:
DOCX -> TEI-XML -> -> -> HTML -> (manifest.yml) -> ZIP # (What happens)
3x
更令人惊讶的是,只有当构建过程之前已经 运行 至少一次并且所有其他文件已经存在于某个更早的状态时,才会发生这种情况。如果该文件夹仅包含 DOCX 文件,则一切正常。此外,使用 make all
或仅使用 make
没有区别。始终 运行 整个构建过程,即使没有文件更改。
make 文件如下:
SELF_DIR := $(dir $(lastword $(MAKEFILE_LIST)))
include ${SELF_DIR}config.mk
MANUSCRIPTFILE:=$(shell ls *.docx)
MANUSCRIPTNAME:=$(shell basename ${MANUSCRIPTFILE} .docx)
SERIES:=$(shell echo "${MANUSCRIPTNAME}" | cut -d _ -f 1)
.PHONY : all tei clean
all: manifold/${MANUSCRIPTNAME}.zip
tei: tei/${MANUSCRIPTNAME}.xml
tei/${MANUSCRIPTNAME}.xml: ${MANUSCRIPTNAME}.docx
@echo -e "\n[BUILD] Convert Word DOCX to TEI-XML via docxtotei and melusina scripts\n"
# Make available relevant XSL stylesheets to the master styleshet
@mkdir -p ${TRANSFORMDIR}/melusina/docx/current
# BUG hier findet er das vorhandene Dokument nicht
@cp ${TRANSFORMDIR}/melusina/docx/specific/${SERIES}.xsl ${TRANSFORMDIR}/melusina/docx/current/series.xsl
@if [ -e ${TRANSFORMDIR}/melusina/docx/specific/${SERIES}/${MANUSCRIPTNAME}.xsl ]; then\
cp ${TRANSFORMDIR}/melusina/docx/specific/${SERIES}/${MANUSCRIPTNAME}.xsl ${TRANSFORMDIR}/melusina/docx/current/publication.xsl;\
else\
cp ${TRANSFORMDIR}/melusina/empty.xsl ${TRANSFORMDIR}/melusina/docx/current/publication.xsl;\
fi
@mkdir -p tei/media
@${BINDIR}/docxtotei --profiledir=${PROFDIR} --profile=melusina $< $@
@cp ../../assets/*.png tei/media/
@cp -r assets/* tei/media/
@rm -rf ${TRANSFORMDIR}/melusina/docx/current
xhtml/*.html: tei/${MANUSCRIPTNAME}.xml
@echo -e "\n[BUILD] Convert Word TEI-XML to HTML via teitohtml and melusina scripts\n"
# Make available relevant XSL stylesheets to the master styleshet
@mkdir -p ${TRANSFORMDIR}/melusina/html/current
@cp ${TRANSFORMDIR}/melusina/html/specific/${SERIES}.xsl ${TRANSFORMDIR}/melusina/html/current/series.xsl
@if [ -e ${TRANSFORMDIR}/melusina/html/specific/${SERIES}/${MANUSCRIPTNAME}.xsl ]; then\
cp ${TRANSFORMDIR}/melusina/html/specific/${SERIES}/${MANUSCRIPTNAME}.xsl ${TRANSFORMDIR}/melusina/html/current/publication.xsl;\
else\
cp ${TRANSFORMDIR}/melusina/empty.xsl ${TRANSFORMDIR}/melusina/html/current/publication.xsl;\
fi
@mkdir -p xhtml
# generate front matter
@java -jar ${SAXON}/saxon9he.jar -o:xhtml/front.html $< ${TRANSFORMDIR}/other/html_front_matter.xsl series=${SERIES}
# copy assets from tei folder
@if [ -e tei/media ]; then\
cp -r tei/media xhtml/;\
else\
mkdir -p xhtml/media;\
fi
# copy stylesheets
@cp ${TRANSFORMDIR}/css/melusina.css xhtml/
@cp ${TRANSFORMDIR}/css/specific/${SERIES}.css xhtml/publication.css
# transform tei xml to html
@${BINDIR}/teitohtml --profiledir=${PROFDIR} --profile=melusina $< xhtml/${MANUSCRIPTNAME}.html
@rm -rf ${TRANSFORMDIR}/melusina/html/current
manifold/manifest.yml: tei/${MANUSCRIPTNAME}.xml
@echo -e "\n[BUILD] Generate manifest.yml from TEI-XML via Saxon and melusina scripts\n"
@mkdir -p manifold
@java -jar ${SAXON}/saxon9he.jar -o:manifold/manifest.yml $< ${TRANSFORMDIR}/other/manifold_manifest.xsl
manifold/${MANUSCRIPTNAME}.zip: xhtml/*.html manifold/manifest.yml
@echo -e "\n[BUILD] Generate Manifold package by collecting manifest.yml and HTML files\n"
@if [ -e tei/media ]; then\
cp -r tei/media manifold/;\
else\
mkdir -p manifold/media;\
fi
@cd xhtml && cp -r cover.html second_cover.html editorial.html *.css ../manifold/
# generate chapter html
@java -jar ${SAXON}/saxon9he.jar -o:xhtml/sections.html xhtml/${MANUSCRIPTNAME}.html ${TRANSFORMDIR}/other/split_html_sections.xsl
@cd manifold && zip -r ${MANUSCRIPTNAME}.zip manifest.yml media *.html *.css
# rm -rf manifold/media manifold/${MANUSCRIPTNAME}.html manifest.yml
clean:
@echo "[BUILD] Delete everything but the Word DOCX manuscript"
@rm -rf tei xhtml manifold pdf
问题是这些规则不起作用:
xhtml/*.html: tei/${MANUSCRIPTNAME}.xml
manifold/${MANUSCRIPTNAME}.zip: xhtml/*.html manifold/manifest.yml
使用通配符来查找需要由 make 构建的 target 是不正确的,因为当你 运行 make 第一次没有匹配的文件存在那些通配符,所以它们不能展开。
它似乎起作用的原因是,就像 shell 一样,如果通配符不匹配任何值,它 returns 通配符本身。因此,如果没有文件与 xhtml/*.html
匹配,则结果为文字字符串 xhtml/*.html
。如果你有三个匹配的文件,那么结果就是像 xhtml/ONE.html xhtml/TWO.html xhtml/THREE.html
.
这样的三个文件
所以第一次 运行 这个 makefile 没有匹配的目标,所以 make 想要构建一个目标,字面意思是 xhtml/*.html
并且有一个匹配该目标的规则,所以一切正常。
你第二次 运行 这个 makefile 有三个目标 make 想要构建并且有这样的规则:
xhtml/ONE.html xhtml/TWO.html xhtml/THREE.html: tei/${MANUSCRIPTNAME}.xml
...recipe...
这是什么意思?您可能认为这意味着 recipe 的一次调用将构建所有三个目标,但这不是它的意思。制作,这和写这个完全一样:
xhtml/ONE.html: tei/${MANUSCRIPTNAME}.xml
...recipe...
xhtml/TWO.html: tei/${MANUSCRIPTNAME}.xml
...recipe...
xhtml/THREE.html: tei/${MANUSCRIPTNAME}.xml
...recipe...
即每个目标运行配方一次。我无法理解大量 shell 脚本的作用,所以我不能说为什么它总是重建:一定是这些文件不是由目标实际创建的,或者它们的修改时间未设置正确。
如果这条规则真的用一次调用构建了所有 html 个文件,那么你需要使用某种伪目标来跟踪它的修改时间,像这样:
xhtml/.buildhtml: tei/${MANUSCRIPTNAME}.xml
... recipe ...
@touch $@
manifold/${MANUSCRIPTNAME}.zip: xhtml/.buildhtml manifold/manifest.yml
或者,如果您知道您可以依赖最新的 GNU make 4.3 版本,您可以利用新的 "grouped targets" feature、&:
,并像这样编写您的 makefile:
ALLHTML = xhtml/ONE.html xhtml/TWO.html xhtml/THREE.html
$(ALLHTML) &: tei/${MANUSCRIPTNAME}.xml
...recipe...
manifold/${MANUSCRIPTNAME}.zip: $(ALLHTML) manifold/manifest.yml
(由于上述原因,您仍然不能使用 *.html
)。
我编写了一个 makefile,它采用 Word DOCX 文件并(在 tei-xslt、xslt 脚本和 saxon 的帮助下)在 TEI-XML、HTML 文件中生成表示,并且用于摄取到发布软件中的 zip 文件。不同的步骤应该是这样的:
DOCX -> TEI-XML -> HTML -> (manifest.yml) -> ZIP # (Expected)
问题是在进入 HTML 到 ZIP 规则之前,在循环中使 运行s TEI 到 HTML 规则:
DOCX -> TEI-XML -> -> -> HTML -> (manifest.yml) -> ZIP # (What happens)
3x
更令人惊讶的是,只有当构建过程之前已经 运行 至少一次并且所有其他文件已经存在于某个更早的状态时,才会发生这种情况。如果该文件夹仅包含 DOCX 文件,则一切正常。此外,使用 make all
或仅使用 make
没有区别。始终 运行 整个构建过程,即使没有文件更改。
make 文件如下:
SELF_DIR := $(dir $(lastword $(MAKEFILE_LIST)))
include ${SELF_DIR}config.mk
MANUSCRIPTFILE:=$(shell ls *.docx)
MANUSCRIPTNAME:=$(shell basename ${MANUSCRIPTFILE} .docx)
SERIES:=$(shell echo "${MANUSCRIPTNAME}" | cut -d _ -f 1)
.PHONY : all tei clean
all: manifold/${MANUSCRIPTNAME}.zip
tei: tei/${MANUSCRIPTNAME}.xml
tei/${MANUSCRIPTNAME}.xml: ${MANUSCRIPTNAME}.docx
@echo -e "\n[BUILD] Convert Word DOCX to TEI-XML via docxtotei and melusina scripts\n"
# Make available relevant XSL stylesheets to the master styleshet
@mkdir -p ${TRANSFORMDIR}/melusina/docx/current
# BUG hier findet er das vorhandene Dokument nicht
@cp ${TRANSFORMDIR}/melusina/docx/specific/${SERIES}.xsl ${TRANSFORMDIR}/melusina/docx/current/series.xsl
@if [ -e ${TRANSFORMDIR}/melusina/docx/specific/${SERIES}/${MANUSCRIPTNAME}.xsl ]; then\
cp ${TRANSFORMDIR}/melusina/docx/specific/${SERIES}/${MANUSCRIPTNAME}.xsl ${TRANSFORMDIR}/melusina/docx/current/publication.xsl;\
else\
cp ${TRANSFORMDIR}/melusina/empty.xsl ${TRANSFORMDIR}/melusina/docx/current/publication.xsl;\
fi
@mkdir -p tei/media
@${BINDIR}/docxtotei --profiledir=${PROFDIR} --profile=melusina $< $@
@cp ../../assets/*.png tei/media/
@cp -r assets/* tei/media/
@rm -rf ${TRANSFORMDIR}/melusina/docx/current
xhtml/*.html: tei/${MANUSCRIPTNAME}.xml
@echo -e "\n[BUILD] Convert Word TEI-XML to HTML via teitohtml and melusina scripts\n"
# Make available relevant XSL stylesheets to the master styleshet
@mkdir -p ${TRANSFORMDIR}/melusina/html/current
@cp ${TRANSFORMDIR}/melusina/html/specific/${SERIES}.xsl ${TRANSFORMDIR}/melusina/html/current/series.xsl
@if [ -e ${TRANSFORMDIR}/melusina/html/specific/${SERIES}/${MANUSCRIPTNAME}.xsl ]; then\
cp ${TRANSFORMDIR}/melusina/html/specific/${SERIES}/${MANUSCRIPTNAME}.xsl ${TRANSFORMDIR}/melusina/html/current/publication.xsl;\
else\
cp ${TRANSFORMDIR}/melusina/empty.xsl ${TRANSFORMDIR}/melusina/html/current/publication.xsl;\
fi
@mkdir -p xhtml
# generate front matter
@java -jar ${SAXON}/saxon9he.jar -o:xhtml/front.html $< ${TRANSFORMDIR}/other/html_front_matter.xsl series=${SERIES}
# copy assets from tei folder
@if [ -e tei/media ]; then\
cp -r tei/media xhtml/;\
else\
mkdir -p xhtml/media;\
fi
# copy stylesheets
@cp ${TRANSFORMDIR}/css/melusina.css xhtml/
@cp ${TRANSFORMDIR}/css/specific/${SERIES}.css xhtml/publication.css
# transform tei xml to html
@${BINDIR}/teitohtml --profiledir=${PROFDIR} --profile=melusina $< xhtml/${MANUSCRIPTNAME}.html
@rm -rf ${TRANSFORMDIR}/melusina/html/current
manifold/manifest.yml: tei/${MANUSCRIPTNAME}.xml
@echo -e "\n[BUILD] Generate manifest.yml from TEI-XML via Saxon and melusina scripts\n"
@mkdir -p manifold
@java -jar ${SAXON}/saxon9he.jar -o:manifold/manifest.yml $< ${TRANSFORMDIR}/other/manifold_manifest.xsl
manifold/${MANUSCRIPTNAME}.zip: xhtml/*.html manifold/manifest.yml
@echo -e "\n[BUILD] Generate Manifold package by collecting manifest.yml and HTML files\n"
@if [ -e tei/media ]; then\
cp -r tei/media manifold/;\
else\
mkdir -p manifold/media;\
fi
@cd xhtml && cp -r cover.html second_cover.html editorial.html *.css ../manifold/
# generate chapter html
@java -jar ${SAXON}/saxon9he.jar -o:xhtml/sections.html xhtml/${MANUSCRIPTNAME}.html ${TRANSFORMDIR}/other/split_html_sections.xsl
@cd manifold && zip -r ${MANUSCRIPTNAME}.zip manifest.yml media *.html *.css
# rm -rf manifold/media manifold/${MANUSCRIPTNAME}.html manifest.yml
clean:
@echo "[BUILD] Delete everything but the Word DOCX manuscript"
@rm -rf tei xhtml manifold pdf
问题是这些规则不起作用:
xhtml/*.html: tei/${MANUSCRIPTNAME}.xml
manifold/${MANUSCRIPTNAME}.zip: xhtml/*.html manifold/manifest.yml
使用通配符来查找需要由 make 构建的 target 是不正确的,因为当你 运行 make 第一次没有匹配的文件存在那些通配符,所以它们不能展开。
它似乎起作用的原因是,就像 shell 一样,如果通配符不匹配任何值,它 returns 通配符本身。因此,如果没有文件与 xhtml/*.html
匹配,则结果为文字字符串 xhtml/*.html
。如果你有三个匹配的文件,那么结果就是像 xhtml/ONE.html xhtml/TWO.html xhtml/THREE.html
.
所以第一次 运行 这个 makefile 没有匹配的目标,所以 make 想要构建一个目标,字面意思是 xhtml/*.html
并且有一个匹配该目标的规则,所以一切正常。
你第二次 运行 这个 makefile 有三个目标 make 想要构建并且有这样的规则:
xhtml/ONE.html xhtml/TWO.html xhtml/THREE.html: tei/${MANUSCRIPTNAME}.xml
...recipe...
这是什么意思?您可能认为这意味着 recipe 的一次调用将构建所有三个目标,但这不是它的意思。制作,这和写这个完全一样:
xhtml/ONE.html: tei/${MANUSCRIPTNAME}.xml
...recipe...
xhtml/TWO.html: tei/${MANUSCRIPTNAME}.xml
...recipe...
xhtml/THREE.html: tei/${MANUSCRIPTNAME}.xml
...recipe...
即每个目标运行配方一次。我无法理解大量 shell 脚本的作用,所以我不能说为什么它总是重建:一定是这些文件不是由目标实际创建的,或者它们的修改时间未设置正确。
如果这条规则真的用一次调用构建了所有 html 个文件,那么你需要使用某种伪目标来跟踪它的修改时间,像这样:
xhtml/.buildhtml: tei/${MANUSCRIPTNAME}.xml
... recipe ...
@touch $@
manifold/${MANUSCRIPTNAME}.zip: xhtml/.buildhtml manifold/manifest.yml
或者,如果您知道您可以依赖最新的 GNU make 4.3 版本,您可以利用新的 "grouped targets" feature、&:
,并像这样编写您的 makefile:
ALLHTML = xhtml/ONE.html xhtml/TWO.html xhtml/THREE.html
$(ALLHTML) &: tei/${MANUSCRIPTNAME}.xml
...recipe...
manifold/${MANUSCRIPTNAME}.zip: $(ALLHTML) manifold/manifest.yml
(由于上述原因,您仍然不能使用 *.html
)。