Как я могу построить HTML с Makefile с обратными ссылками? - PullRequest
0 голосов
/ 16 декабря 2018

Я пытаюсь статически создать HTML-файлы, для которых требуется файл уценки и метафайл «whatlinkshere» для HTML-файла, чтобы продемонстрировать его обратные ссылки .

Я полагаю, что это можетбыть эффективно сделан Makefile, сначала сгенерировав все файлы "whatlinkshere".Я не думаю, что это может быть сделано параллельно, потому что программа, которая генерирует эти файлы, должна добавить файлы whatlinkshere, и могут быть условия гонки, которые я не совсем уверен, как решить.

Однаждыфайлы «whatlinkshere» генерируются тогда, если файл уценки редактируется, скажем, foo.mdwn, чтобы указывать на bar.mdwn , только анализ foo.mdwn необходимо снова проанализировать на предмет изменений «whatlinkshere».И, наконец, нужно перестраивать только foo.html и bar.html.

Я изо всех сил пытаюсь достичь этого в моем проекте обратных ссылок .

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.Кроме того, после редактирования файла, как описано ранее, не происходит перестройка.Что-то ужасно неправильно.Чего мне не хватает?

1 Ответ

0 голосов
/ 16 декабря 2018

Мне кажется, я наконец понял вашу проблему.Если я правильно понял:

  1. У вас есть куча *.mdwn исходных файлов.
  2. Вы генерируете *.whatlinkshere файлов из ваших *.mdwn исходных файлов, используя утилиту backlinks.go,Но эта утилита не выдает foo.whatlinkshere из foo.mdwn.Он анализирует foo.mdwn, ищет в нем ссылки на другие страницы и для каждой найденной ссылки на bar добавляет a [foo](foo.html) ссылку на bar.whatlinkshere.
  3. Из каждого foo.mdwn исходного файла, который вы хотите создать соответствующий foo.html файл с:

    $ cmark foo.mdwn foo.whatlinkshere
    

Ваше правило:

$(LINKFILES): $(INFILES)
    @echo Creating backlinks $@
    @touch $@
    @go run backlinks.go $<

содержитодна ошибка и имеет несколько недостатков.Ошибка заключается в использовании автоматической переменной $< в рецепте.Это расширяется как первая предпосылка, которая, вероятно, всегда pageA.mdwn в вашем случае.Не то, что вы хотите.$^ расширяется как все предпосылки, но это не правильное решение, потому что:

  1. ваша утилита go берет только одно имя исходного файла, но даже если она принимает несколько ...
  2. ... make запустит рецепт несколько раз, по одному на файл ссылок, что является пустой тратой, и ...
  3. ... поскольку ваша утилита go добавляет файлы ссылок, это будет даже хуже, чемпустая трата: обратные ссылки будут подсчитываться несколько раз, и ...
  4. ... если make работает в параллельном режиме (учтите, что вы можете предотвратить это с помощью make -j1 или добавив специальный .NOTPARALLEL:правила для вашего Makefile, но это жаль) есть риск возникновения гонки.

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

Первый вариант с использованием шаблонных правил с несколькими целями

Одна возможность - использовать специальное свойство правил make pattern: когда ониесть несколько целей make считает, что одно выполнение рецепта производит все цели.Например:

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

указывает make, что pageA.whatlinkshere, pageB.whatlinkshere и pageC.whatlinkshere все генерируются одним выполнением:

for m in pageA.mdwn pageB.mdwn pageC.mdwn; do go run backlinks.go $m; done

(make расширяет $^ каквсе предпосылки и $$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 и clean как фальшивые , потому что ... это то, что ониявляются.
  • Я объявил whatlinkshere файлы драгоценными , потому что (некоторые из них) рассматриваются make как промежуточные, и без этого объявления make удаляла бы их после сборки HTML-файлов.
  • В рецепт для файлов whatlinkshere я добавил rm -f $(LINKFILES), чтобы при выполнении рецепта мы перезапускались из чистого состояния вместо того, чтобы объединять новые данные со старыми (возможно, устаревшими) ссылками.
  • Ствол шаблона в $(LINKPATTERN) может быть любым, но должен соответствовать хотя бы одному символу.Я использовал w%e, но whatlin%shere тоже подойдет.Используйте то, что достаточно конкретно в вашем случае.Если у вас есть файл pageB.where, предпочтите whatlin%shere или what%here.

У этого решения есть недостаток, но он связан с вашей конкретной настройкой: каждый раз по одному mdwn файл изменяется, его необходимо повторно проанализировать (что нормально), но это может повлиять на любой файл whatlinkshere.Это не предсказуемо, это зависит от ссылок, которые были изменены в этом исходном файле.Но более проблематичным является тот факт, что результатом этого анализа является добавленный к затронутым whatlinkshere файлам.Они не " отредактированы " со старым содержимым относительно этого исходного файла, замененным новым.Таким образом, если вы измените только комментарий в исходном файле, все его ссылки будут снова добавлены к соответствующим whatlinkshere файлам (пока они уже есть).Это, вероятно, не то, что вы хотите.

Именно поэтому решение, приведенное выше, удаляет все файлы whatlinkshere и повторно анализирует все исходные файлы каждый раз, когда изменяется один единственный исходный файл.И еще одно негативное последствие заключается в том, что все файлы HTML также должны быть сгенерированы повторно, поскольку все файлы whatlinkshere изменились (даже если их содержимое на самом деле не изменилось, но make этого не знает).Если анализ очень быстрый и у вас есть небольшое количество mdwn файлов, все должно быть в порядке.Иначе, это неоптимально, но не легко решить из-за вашей конкретной установки.

Второй вариант с использованием рекурсивного make, отдельных файлов обратных ссылок и файлов маркеров

Однако существует возможность, которая заключается в:

  1. разделении ссылок на все обратные ссылкис одним файлом whatlinkshere для каждой пары from / to: foo.backlinks/bar.whatlinkshere содержит все ссылки на bar, найденные в foo.mdwn,
  2. с использованием рекурсивного make с одним первым вызовом (когда переменная STEP make равнаunset) обновить все файлы whatlinkshere, которые должны быть, и второй вызов (STEP установлен на 2) для генерации файлов HTML, которые должны быть,
  3. с использованием пустых фиктивных файлов, чтобы отметить, что *Файл 1128 * был проанализирован: foo.backlinks/.done,
  4. с использованием вторичного расширения , чтобы иметь возможность сослаться на основание правила шаблона в его списке предпосылок (и с использованием $$чтобы избежать расширения кулак).

Но, вероятно, это немного сложнее понять (и поддерживать).

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)

Даже если это выглядит сложнее, есть несколькоПреимущества этой версии:

  1. перестраиваются только устаревшие цели и только один раз,
  2. все whatlinkshere файлы обновляются (при необходимости) перед обновлением любого HTML-файла (при необходимости),
  3. файлы whatlinkshere могут быть построены параллельно,
  4. файлы HTML могут быть построены параллельно.

Третий вариант - использование только рекурсивных файлов марки и маркера

Если вас не интересуют неточные результаты, в которых обратные ссылки сохраняются в результатах после того, как они исчезли из исходных файлов, или когда обратные ссылки бесполезно реплицируются, мы можем повторно использовать идеи из предыдущего решения, но отбросить разделение по отдельным от / до whatlinkshere files.

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)

Примечания:

  1. Поскольку это работает только для плоской организации, я заменил $(shell find...) на встроенную * make 1165 *.
  2. Я использовал patsubst вместо старого синтаксиса, но это просто дело вкуса.
  3. Правило %.whatlinkshere: является правилом по умолчанию для создания пропущенных пустых whatlinkshere файлов.
  4. Специальная цель NOTPARALLEL:параллельное выполнение при построении файлов whatlinkshere.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...