diff --git a/docs/src/Submakefile b/docs/src/Submakefile index cf81738decf..62567b56916 100644 --- a/docs/src/Submakefile +++ b/docs/src/Submakefile @@ -1088,21 +1088,29 @@ $(DOC_OUT_HTML)/en/pdf/LinuxCNC_Manual_Pages_en.pdf: objects/LinuxCNC_Manual_Pag || (X=$$?; rm -f $@ $@.raw; exit $$X) @test -f $@ +# Target a page's include:: and image: prerequisites hang off. A page is +# consumed by its .html; a Master document has no HTML, only the PDF that +# pulls its chapters in, and the English ones render into objects/. Not +# derivable from the source path, so asciideps is told. +EN_DEP_TARGET = $(if $(filter Master_%,$*),objects/$*.pdf,$(DOC_OUT_ADOC)/en/$*.html) + depends/%.d: $(DOC_OUT_ADOC)/en/%.adoc $(DOC_SRCDIR)/asciideps .include-stamp | stage-en $(ECHO) Depending $< @mkdir -p $(dir $@) - $(Q)$(DOC_SRCDIR)/asciideps $< > $@.tmp + $(Q)$(DOC_SRCDIR)/asciideps $< $(EN_DEP_TARGET) > $@.tmp @mv $@.tmp $@ # Translated .adoc lives in $(DOC_OUT_ADOC)//; same recipe, just a # different source dir so the per-language depends//X.d targets # resolve. The pattern only matches paths starting with a known language # tag, so the English depends/%.d above wins for non-translated entries. +# Translated Master PDFs render beside their source, so unlike English the +# target is the sibling .pdf. define TRANSLATED_DEP_RULE depends/$(1)/%.d: $(DOC_OUT_ADOC)/$(1)/%.adoc $(DOC_SRCDIR)/asciideps .include-stamp | stage-en $$(ECHO) Depending $$< @mkdir -p $$(dir $$@) - $$(Q)$$(DOC_SRCDIR)/asciideps $$< > $$@.tmp + $$(Q)$$(DOC_SRCDIR)/asciideps $$< $$(if $$(filter Master_%,$$*),$(DOC_OUT_ADOC)/$(1)/$$*.pdf,$(DOC_OUT_ADOC)/$(1)/$$*.html) > $$@.tmp @mv $$@.tmp $$@ endef $(foreach L,$(LANGUAGES),$(eval $(call TRANSLATED_DEP_RULE,$(L)))) @@ -1191,6 +1199,11 @@ $(foreach L,$(LANGUAGES),$(eval $(call HTML_COPY_RULE,$(L)))) # has no work to do (filter-out yields empty) so we skip the dep too. HTML # image placement is no longer done here: the image_resolver rewrites HTML src # to the shared pool and .html-images-stamp materialises it. +# +# Matched anywhere on the line, like asciideps, so both see the same set. +# Anchored at the start it missed the 39 inline refs, leaving those images +# out of the translated PDFs that embed them from here. Keyed on the macro +# shape, or prose mentioning image:: is taken for a path and the copy fails. ifeq ($(BUILD_DOCS_TRANSLATED),yes) ADOC_IMAGES_STAMP_DEPS := $(DOC_DIR)/.translateddocs-stamp endif @@ -1198,7 +1211,7 @@ endif set -e; for ADOC_FILE in $(addprefix $(DOC_OUT_ADOC)/, $(filter-out $(DOC_SRCS_EN), $(DOC_SRCS))); do \ ADOC_DIR=$$(echo $$(dirname $$ADOC_FILE) | sed s%$(DOC_OUT_ADOC)/%% ); \ echo Processing $$ADOC_FILE, dir $$ADOC_DIR; \ - for IMAGE_FILE in $$(grep -E ^image:[^[:space:]] $$ADOC_FILE | sed -E "s/image:+([^[]+)\[/\nimage:\1\n/g" | grep image: | cut -d: -f2-); do \ + for IMAGE_FILE in $$(grep -v '^[[:space:]]*//' $$ADOC_FILE | grep -oE 'image::?[^[:space:][]+\[' | sed -E 's/^image::?//; s/\[$$//'); do \ IMAGE_DIR=$$(dirname $$IMAGE_FILE); \ IMAGE_PATH=$$(echo $(DOC_SRCDIR)/$$ADOC_DIR/$$IMAGE_FILE | sed -E 's%/src/($(LANGUAGES_MATCH))/%/src/%'); \ if [ ! -e $$IMAGE_PATH ] ; then \ @@ -1214,6 +1227,24 @@ endif done; \ done > $@.new && mv $@.new $@ +# Same staging, one file at a time. The dependency files name these images, +# so a clean -j build reaches one before the bulk pass has written it and +# falls through to the "Required image file" error at the end of this file. +# Source lookup as above: the English original, else the English build tree +# for images generated there, such as the .dot-rendered SVGs. +ifeq ($(BUILD_DOCS_TRANSLATED),yes) +define TRANSLATED_IMAGE_RULE +$(DOC_OUT_ADOC)/$(1)/%.$(2): | $(DOC_DIR)/.translateddocs-stamp + @mkdir -p $$(@D) + $$(Q)S=$(DOC_SRCDIR)/$$*.$(2); \ + [ -e "$$$$S" ] || S=$(DOC_OUT_ADOC)/en/$$*.$(2); \ + cp -f "$$$$S" $$@ +endef +$(foreach L,$(LANGUAGES), \ + $(foreach E,png jpg jpeg gif svg, \ + $(eval $(call TRANSLATED_IMAGE_RULE,$(L),$(E))))) +endif + # Relative path from this html target back to $(DOC_OUT_HTML)/, used to # point the lcnc-overrides.css in docinfo.html at the right place. # Every output now lives under a $(DOC_OUT_HTML)// subtree, so depth @@ -1282,24 +1313,32 @@ endef # components_gen.adoc generates straight into build/adoc/en/hal; svgs_made_from_dots # runs first. # -# One rule per staged file, not a bulk find|tar behind a stamp with the staged copies hanging off it order-only. -# make stats a prerequisite once per run and re-stats it only if it decided to remake it, and an order-only edge never triggers a remake. -# A bulk copy that rewrote the staged .adoc mid-run was therefore invisible to the renderer, which had already compared the .html against the pre-copy mtime, so editing a page took two `make` runs to reach the HTML: the first re-staged, the second rendered. -# With a real recipe per file make knows the staged copy changed and the render fires in the same run. +# One rule per staged file, not a bulk copy behind a stamp with the staged +# copies hanging off it order-only. make stats a prerequisite once per run +# and re-stats it only if it decided to remake it, which an order-only edge +# never triggers, so a bulk copy rewriting the staged .adoc mid-run stayed +# invisible and editing a page took two `make` runs to reach the HTML. EN_STAGE_TYPES := -name '*.adoc' -o -name '*.png' -o -name '*.jpg' -o -name '*.jpeg' -o -name '*.gif' -o -name '*.svg' -o -name '*.py' EN_STAGE_SRCS := $(shell find $(DOC_SRCDIR) \( $(EN_STAGE_TYPES) \)) EN_STAGED := $(patsubst $(DOC_SRCDIR)/%,$(DOC_OUT_ADOC)/en/%,$(EN_STAGE_SRCS)) -# cp -p keeps the source mtime to the nanosecond; tar rounded it down to the whole second, which could leave a staged copy a fraction older than a .html rendered from it in the same second and lose that edit entirely. +# cp -p keeps the source mtime to the nanosecond. tar rounded down to the +# whole second, which could leave a staged copy a shade older than a .html +# rendered from it in that same second and lose the edit. $(EN_STAGED): $(DOC_OUT_ADOC)/en/%: $(DOC_SRCDIR)/% | svgs_made_from_dots @mkdir -p $(@D) $(Q)cp -p $< $@ -# Stage the whole set before anything reads it, the way the bulk copy did. On-demand staging is not enough: asciidoctor resolves include:: and image: against the staged tree at render time, and asciideps recurses into included files there, but only a fraction of those are make prerequisites. Leave it to demand and a partial like hal/halshow.adoc never lands, so the page that includes it renders an "Unresolved directive" placeholder instead of its content. +# Stage the whole set up front, as the bulk copy did. On demand is not +# enough: asciidoctor resolves include:: and image: against this tree at +# render time and asciideps recurses into it, yet few of those files are make +# prerequisites. Left to demand, a partial like hal/halshow.adoc never lands +# and the page including it renders an "Unresolved directive" placeholder. .PHONY: stage-en stage-en: $(EN_STAGED) -# Staged files are used only as prerequisites: mark .SECONDARY so make does not delete them as intermediates mid -j build (like the .SECONDARY above). +# Staged files are used only as prerequisites: mark .SECONDARY so make does +# not delete them as intermediates mid -j build (like the .SECONDARY above). .SECONDARY: $(EN_STAGED) # English now renders from build/adoc/en, the same model as the translations. diff --git a/docs/src/asciideps b/docs/src/asciideps index b1bd54dcd85..0a78a0856cf 100755 --- a/docs/src/asciideps +++ b/docs/src/asciideps @@ -2,8 +2,18 @@ set -e -test -z "$1" && exit 0 -test -f "$1" || exit 1 +# usage: asciideps SOURCE.adoc [TARGET...] +# +# Emit a make rule hanging SOURCE's include:: and image: prerequisites off +# TARGET. The caller names the target because it is not derivable from the +# source path: a Master document has no .html and its English PDF lands in +# objects/. Defaults to the source stem, for a standalone run. +SRC=$1 +[ -z "$SRC" ] && exit 0 +[ -f "$SRC" ] || { echo "asciideps: '$SRC' not a file" >&2; exit 1; } +shift +TARGETS="$*" +[ -n "$TARGETS" ] || TARGETS="${SRC%.adoc}.html" includestack=( ) @@ -31,15 +41,19 @@ includes () { images() { DIR=$(dirname "$1") - sed -ne "s|^.*image:\{1,2\}\([^[]*\)\[.*\].*$|$DIR/\1|p" "$1" | tr '\n' ' ' + # Drop line comments first: the macro is matched anywhere on the line to + # catch inline refs, which otherwise also matches a commented-out one. + # That is no dependency, and requiring it breaks the build once the file + # it names is removed. + grep -v '^[[:space:]]*//' "$1" \ + | sed -ne "s|^.*image:\{1,2\}\([^[]*\)\[.*\].*$|$DIR/\1|p" \ + | tr '\n' ' ' } -INCLUDES=$(includes "$1" | tr '\n' ' ') -IMAGES=$(images "$1") +INCLUDES=$(includes "$SRC" | tr '\n' ' ') +IMAGES=$(images "$SRC") for f in $INCLUDES; do IMAGES="$IMAGES $(images "$f")" done -echo "${1%%.txt}.dep: $INCLUDES" -echo "${1%%.txt}.html: $INCLUDES $IMAGES" -echo "${1%%.txt}.pdf: $INCLUDES $IMAGES" +echo "$TARGETS: $INCLUDES $IMAGES"