Почему make запускает одно указанное c правило 3 раза в al oop? - PullRequest
0 голосов
/ 01 апреля 2020

Я написал make-файл, который принимает файл Word DOCX и (с помощью сценариев tei-xslt, xslt и saxon) создает представление в файлах TEI- XML, HTML и zip-файл для загрузки в программное обеспечение для публикации. Различные шаги должны go выглядеть следующим образом:

DOCX -> TEI-XML -> HTML -> (manifest.yml) -> ZIP # (Expected)

Проблема состоит в том, что make запускает правило TEI to HTML три раза в al oop перед тем, как перейти к правилу HTML to ZIP:

DOCX -> TEI-XML -> -> -> HTML -> (manifest.yml) -> ZIP # (What happens)
                   3x

Более удивительно, что это происходит только тогда, когда процесс сборки уже был запущен хотя бы один раз, а все другие файлы уже существуют в более раннем состоянии. Если папка содержит только файл DOCX, все работает как положено. Кроме того, нет никакой разницы в использовании make all или просто make. 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

1 Ответ

1 голос
/ 01 апреля 2020

Проблема в том, что эти правила не могут работать:

xhtml/*.html: tei/${MANUSCRIPTNAME}.xml

manifold/${MANUSCRIPTNAME}.zip: xhtml/*.html manifold/manifest.yml

Неправильно использовать подстановочные знаки для поиска target , которые должны быть собраны make, потому что при запуске make в первый раз нет файлов, которые соответствуют этим групповым символам, поэтому они не могут расширяться.

Причина, по которой это работает, заключается в том, что, подобно оболочке, если подстановочный знак не соответствует никакому значению, он возвращает сам подстановочный знак. Итак, если ни один файл не соответствует xhtml/*.html, то результатом будет буквенная строка xhtml/*.html. Если у вас есть три файла, которые соответствуют, то в результате получаются три файла, такие как xhtml/ONE.html xhtml/TWO.html xhtml/THREE.html.

Так что при первом запуске этого файла сборки нет подходящих целей, и поэтому make хочет создать одну цель с именем, буквально, xhtml/*.html и есть правило, которое соответствует этой цели, так что все работает.

Во второй раз, когда вы запускаете этот make-файл, есть три цели, которые 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...

, то есть, он будет запускать рецепт один раз для каждой цели. Мне невозможно понять, что делает эта масса сценариев оболочки, поэтому я не могу сказать, почему она всегда перестраивается: должно быть, либо эти файлы на самом деле не созданы целью, либо время их модификации не установлено должным образом.

Если это правило действительно строит все html файлы одним вызовом, то вам нужно использовать псевдо-цель некоторого вида для отслеживания времени ее модификации, например:

xhtml/.buildhtml: tei/${MANUSCRIPTNAME}.xml
        ... recipe ...
        @touch $@

manifold/${MANUSCRIPTNAME}.zip: xhtml/.buildhtml manifold/manifest.yml

В качестве альтернативы если вы знаете, что можете полагаться на последнюю версию GNU make 4.3, вы можете воспользоваться новой функцией «сгруппированные цели» , &: и написать свой make-файл следующим образом:

ALLHTML = xhtml/ONE.html xhtml/TWO.html xhtml/THREE.html
$(ALLHTML) &: tei/${MANUSCRIPTNAME}.xml
        ...recipe...

manifold/${MANUSCRIPTNAME}.zip: $(ALLHTML) manifold/manifest.yml

(Вы по-прежнему не можете использовать *.html по причинам, указанным выше).

...