diff --git a/docs/.gitignore b/docs/.gitignore index 3a1fe66a79e..970189a9dd1 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -1,24 +1,10 @@ # All ignores for the documentation tree live here (not in the top-level # .gitignore). Paths are relative to docs/. -# Rendered output: HTML, PDF, and po4a-translated .adoc all land under build/. +# Rendered output: HTML, PDF, po4a-translated .adoc, components_gen.adoc, the +# per-topic .html, and the .dot-rendered SVGs all land under build/ now. build/ -# Intermediate .html asciidoctor writes beside each source .adoc before the -# copy step moves it into build/html/. -src/*/*.html - -# Generated component manpage list (gen_complist.py). -src/hal/components_gen.adoc - -# SVGs rendered from the .dot sources in src/code/ (CMS_buffer.svg is committed). -src/code/homing.svg -src/code/homing_es.svg -src/code/hss.svg -src/code/hss_es.svg -src/code/task-state-transitions.svg -src/code/task-state-transitions_es.svg - # Troff manpages generated from .adoc by the asciidoctor manpage backend. man/man1/ man/man3/ diff --git a/docs/po4a.cfg b/docs/po4a.cfg index 3d9c8a1b29e..5d83aca520c 100644 --- a/docs/po4a.cfg +++ b/docs/po4a.cfg @@ -124,7 +124,7 @@ [type: AsciiDoc_def] src/hal/canonical-devices.adoc $lang:build/adoc/$lang/hal/canonical-devices.adoc [type: AsciiDoc_def] src/hal/comp.adoc $lang:build/adoc/$lang/hal/comp.adoc [type: AsciiDoc_def] src/hal/components.adoc $lang:build/adoc/$lang/hal/components.adoc -[type: AsciiDoc_def] src/hal/components_gen.adoc $lang:build/adoc/$lang/hal/components_gen.adoc +[type: AsciiDoc_def] build/adoc/en/hal/components_gen.adoc $lang:build/adoc/$lang/hal/components_gen.adoc [type: AsciiDoc_def] src/hal/general-ref.adoc $lang:build/adoc/$lang/hal/general-ref.adoc [type: AsciiDoc_def] src/hal/hal-examples.adoc $lang:build/adoc/$lang/hal/hal-examples.adoc [type: AsciiDoc_def] src/hal/halmodule.adoc $lang:build/adoc/$lang/hal/halmodule.adoc diff --git a/docs/src/Submakefile b/docs/src/Submakefile index 7611b346612..9452740b985 100644 --- a/docs/src/Submakefile +++ b/docs/src/Submakefile @@ -274,10 +274,11 @@ endif # hence $(MAN_SRCS) as a real prereq (the script is content-stable via # write_if_changed, so re-running over the same set is a no-op for # mtime, which keeps downstream po4a from re-firing every build). -$(DOC_SRCDIR)/hal/components_gen.adoc: $(DOC_SRCDIR)/gen_complist.py $(DOC_SRCDIR)/hal/components.adoc $(MAN_SRCS) | manpages +$(DOC_OUT_ADOC)/en/hal/components_gen.adoc: $(DOC_SRCDIR)/gen_complist.py $(DOC_SRCDIR)/hal/components.adoc $(MAN_SRCS) | manpages + @mkdir -p $(dir $@) python3 $(DOC_SRCDIR)/gen_complist.py $(DOC_SRCDIR)/hal/components.adoc -$(DOC_DIR)/po/documentation.pot: $(addprefix $(DOC_SRCDIR)/, $(DOC_SRCS_EN)) $(DOC_SRCDIR)/hal/components_gen.adoc +$(DOC_DIR)/po/documentation.pot: $(addprefix $(DOC_SRCDIR)/, $(DOC_SRCS_EN)) $(DOC_OUT_ADOC)/en/hal/components_gen.adoc cd $(DOC_DIR) && ${TIME_CMD} po4a $(PO4A_VERBOSE) --msgmerge-opt='-v' --no-translations po4a.cfg @touch $@ pofiles: $(DOC_DIR)/po/documentation.pot @@ -293,7 +294,7 @@ ifeq ($(BUILD_DOCS_TRANSLATED),yes) # rewriting every docs/po/*.po with a fresh POT-Creation-Date on each build # (dirty tree + mtime cascade). Building needs only `po4a --no-update`; # pot/po extraction stays on the explicit `pofiles` target. -$(DOC_DIR)/.translateddocs-stamp: $(DOC_SRCDIR)/hal/components_gen.adoc $(wildcard $(DOC_DIR)/po/*.po) | manpages +$(DOC_DIR)/.translateddocs-stamp: $(DOC_OUT_ADOC)/en/hal/components_gen.adoc $(wildcard $(DOC_DIR)/po/*.po) | manpages cd $(DOC_DIR) && ${TIME_CMD} po4a $(PO4A_VERBOSE) --msgmerge-opt='-v' --no-update po4a.cfg @touch $@ translateddocs: $(DOC_DIR)/.translateddocs-stamp @@ -425,9 +426,20 @@ clean-manpages: clean-translated: -$(RM) -r $(GENERATED_TRANSLATED) -DOTFILES=$(shell find . -name "*.dot") $(shell find ../docs/src/ -name "*.dot") +# Docs .dot render into build/adoc/en/ so docs/src stays clean. Other +# .dot (e.g. src/emc/motion/homing.dot, not a doc) still render beside source. +DOC_DOTFILES := $(shell find $(DOC_SRCDIR) -name '*.dot') +DOC_DOT_SVGS := $(patsubst $(DOC_SRCDIR)/%.dot,$(DOC_OUT_ADOC)/en/%.svg,$(DOC_DOTFILES)) +OTHER_DOTFILES := $(filter-out $(DOC_DOTFILES),$(shell find . -name '*.dot')) .PHONY: svgs_made_from_dots -svgs_made_from_dots: $(DOTFILES:.dot=.svg) +svgs_made_from_dots: $(DOC_DOT_SVGS) $(OTHER_DOTFILES:.dot=.svg) + +$(DOC_OUT_ADOC)/en/%.svg: $(DOC_SRCDIR)/%.dot + @mkdir -p $(@D) + dot -Tsvg -Gbgcolor=transparent -o$@ $< + +# Pattern-rule outputs; .SECONDARY so the -j build keeps them (see staging rule). +.SECONDARY: $(DOC_DOT_SVGS) ifeq ($(BUILD_DOCS_PDF),yes) docs: pdfdocs @@ -521,7 +533,7 @@ $(DOC_OUT_HTML)/rouge-github.css: $(DOC_SRCDIR)/render-rouge-css.rb # with HTML-existence-dependent content (different miss_in_man set), # bumping mtime past .pot and re-triggering po4a on the next build. # Broken-link validation against generated HTML is checkref's job. -$(DOC_DIR)/.gen_complist-stamp: $(DOC_SRCDIR)/hal/components_gen.adoc $(MAN_HTML_TARGETS) +$(DOC_DIR)/.gen_complist-stamp: $(DOC_OUT_ADOC)/en/hal/components_gen.adoc $(MAN_HTML_TARGETS) mkdir -p $(DOC_OUT_HTML)/en/hal @touch $@ @@ -830,7 +842,7 @@ $(4)/%.pdf: $(1)/%.adoc .adoc-images-stamp $$(DOC_FONTS) | svgs_made_from_dots || (X=$$$$?; rm -f $$@ $$@.raw; exit $$$$X) @test -f $$@ endef -$(eval $(call ASCIIDOCTOR_PDF_RULE,$(DOC_SRCDIR),^($(LANGUAGES_MATCH))/,en,objects)) +$(eval $(call ASCIIDOCTOR_PDF_RULE,$(DOC_OUT_ADOC)/en,^($(LANGUAGES_MATCH))/,en,objects)) $(eval $(call ASCIIDOCTOR_PDF_RULE,$(DOC_OUT_ADOC),,$$(firstword $$(subst /, ,$$*)),$(DOC_OUT_ADOC))) # Manual pages PDF: previously produced from the generated troff files @@ -901,7 +913,7 @@ $(DOC_OUT_HTML)/en/pdf/LinuxCNC_Manual_Pages_en.pdf: objects/LinuxCNC_Manual_Pag || (X=$$?; rm -f $@ $@.raw; exit $$X) @test -f $@ -depends/%.d: $(DOC_SRCDIR)/%.adoc $(DOC_SRCDIR)/asciideps .include-stamp +depends/%.d: $(DOC_OUT_ADOC)/en/%.adoc $(DOC_SRCDIR)/asciideps .include-stamp $(ECHO) Depending $< @mkdir -p $(dir $@) $(Q)$(DOC_SRCDIR)/asciideps $< > $@.tmp @@ -925,7 +937,7 @@ $(foreach L,$(LANGUAGES),$(eval $(call TRANSLATED_DEP_RULE,$(L)))) # to $(DOC_OUT_HTML)///X.html (the asciidoctor pattern rule # emits the .html sibling to the .adoc; no separate copy step needed for # translations). We model both with one static pattern set per lang. -$(DOC_TARGETS_HTML_EN): $(DOC_OUT_HTML)/en/%.html: $(DOC_SRCDIR)/%.html +$(DOC_TARGETS_HTML_EN): $(DOC_OUT_HTML)/en/%.html: $(DOC_OUT_ADOC)/en/%.html @mkdir -p $(dir $@) @cp $< $@ @@ -943,7 +955,8 @@ $(foreach L,$(LANGUAGES),$(eval $(call HTML_COPY_RULE,$(L)))) # live at $(DOC_OUT_HTML)/en//X.html; for translations at # $(DOC_OUT_HTML)///X.html. The source images are in # $(DOC_SRCDIR)// regardless of language (translations are -# image-symlinked to English originals via the sed below). +# image-symlinked to English originals via the sed below). Generated SVGs are +# not in src; fall back to the English build tree where they render. .html-images-stamp: $(DOC_TARGETS_HTML) set -e; for HTML_FILE in $^; do \ HTML_REL=$$(echo $$HTML_FILE | sed 's%^$(DOC_OUT_HTML)/%%'); \ @@ -953,6 +966,9 @@ $(foreach L,$(LANGUAGES),$(eval $(call HTML_COPY_RULE,$(L)))) for IMAGE_FILE in $$(grep -oE 'src="[^"]+"' $$HTML_FILE | sed 's/src="//;s/"$$//' | grep -vE '^https?:|^data:|^/'); do \ IMAGE_DIR=$$(dirname $$IMAGE_FILE); \ IMAGE_PATH=$(DOC_SRCDIR)/$$HTML_DIR/$$IMAGE_FILE; \ + if [ ! -e $$IMAGE_PATH ] ; then \ + IMAGE_PATH=$(DOC_OUT_ADOC)/en/$$HTML_DIR/$$IMAGE_FILE; \ + fi; \ mkdir -p $(DOC_OUT_HTML)/$$LANG/$$HTML_DIR/$$IMAGE_DIR; \ cp -f $$IMAGE_PATH $(DOC_OUT_HTML)/$$LANG/$$HTML_DIR/$$IMAGE_FILE; \ done; \ @@ -996,6 +1012,10 @@ endif for IMAGE_FILE in $$(grep -E ^image:[^[:space:]] $$ADOC_FILE | sed -E "s/image:+([^[]+)\[/\nimage:\1\n/g" | grep image: | cut -d: -f2-); 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 \ + EN_DIR=$$(echo $$ADOC_DIR | sed -E 's%^($(LANGUAGES_MATCH))/%%'); \ + IMAGE_PATH=$(DOC_OUT_ADOC)/en/$$EN_DIR/$$IMAGE_FILE; \ + fi; \ TIMAGE_PATH=$(DOC_OUT_ADOC)/$$ADOC_DIR/$$IMAGE_FILE; \ HIMAGE_PATH=$(DOC_OUT_HTML)/$$ADOC_DIR/$$IMAGE_FILE; \ mkdir -p $(DOC_OUT_ADOC)/$$ADOC_DIR/$$IMAGE_DIR; \ @@ -1046,7 +1066,34 @@ $$(patsubst %.adoc,$2/%.html,$$(DOC_SRCS_$(call toUC,$1)_SMALL)): $2/%.html: $2/ -o $$@ $$< || (X=$$$$?; rm -f $$@; exit $$$$X) endef -$(eval $(call ASCIIDOCTOR_HTML_RULE,en,$(DOC_SRCDIR),$(DOC_SRCDIR),^($(LANGUAGES_MATCH))/)) +# Stage English sources (.adoc, images, code fixtures like +# gui/panelui_handler.py) into build/adoc/en so English renders from the build +# tree like translations: docs/src stays clean and includes resolve relatively. +# components_gen.adoc generates straight into build/adoc/en/hal; svgs_made_from_dots +# runs first. find|tar avoids an rsync dependency. The stamp lives in build/ so +# docclean drops it and the next build re-stages. +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) \)) +$(DOC_BUILD)/.stage-en-stamp: $(EN_STAGE_SRCS) | svgs_made_from_dots + @mkdir -p $(DOC_OUT_ADOC)/en + $(Q)dest=$$(cd $(DOC_OUT_ADOC)/en && pwd); \ + cd $(DOC_SRCDIR) && find . \( $(EN_STAGE_TYPES) \) -print0 \ + | tar --null -cf - -T - | (cd "$$dest" && tar -xpf -) + @touch $@ + +# Staged .adoc come from the stamp. Order-only (|), like the translated rule +# above: staging finishes before any consumer reads. components_gen.adoc keeps +# its own rule above. tar -p preserves mtimes, so consumers still rebuild on +# source change. +$(DOC_OUT_ADOC)/en/%.adoc: | $(DOC_BUILD)/.stage-en-stamp ; + +# Pattern-rule outputs used only as prerequisites: mark .SECONDARY so make does +# not delete them as intermediates mid -j build (like the .SECONDARY above). +EN_STAGED_ADOC := $(patsubst $(DOC_SRCDIR)/%,$(DOC_OUT_ADOC)/en/%,$(filter %.adoc,$(EN_STAGE_SRCS))) +.SECONDARY: $(EN_STAGED_ADOC) + +# English now renders from build/adoc/en, the same model as the translations. +$(eval $(call ASCIIDOCTOR_HTML_RULE,en,$(DOC_OUT_ADOC)/en,$(DOC_OUT_ADOC)/en,^($(LANGUAGES_MATCH))/)) $(foreach lang,$(LANGUAGES), \ $(eval $(call ASCIIDOCTOR_HTML_RULE,$(lang),$(DOC_OUT_ADOC),$(DOC_OUT_ADOC)/$(lang),))) @@ -1083,7 +1130,7 @@ docclean: -rm -f $(DOC_DIR)/.translateddocs-stamp -rm -f $(DOC_DIR)/.gen_complist-stamp -rm -f $(DOC_DIR)/.checkref-*-stamp - -rm -f $(DOTFILES:.dot=.svg) + -rm -f $(OTHER_DOTFILES:.dot=.svg) MAN_DEPS := $(patsubst $(DOC_DIR)/man/%, depends/%.d, $(MAN_SRCS)) diff --git a/docs/src/gen_complist.py b/docs/src/gen_complist.py index 7a7f4df6374..1a1ae2481f5 100644 --- a/docs/src/gen_complist.py +++ b/docs/src/gen_complist.py @@ -18,6 +18,7 @@ def write_if_changed(path, content): return False except FileNotFoundError: pass + os.makedirs(os.path.dirname(path), exist_ok=True) with open(path, 'w') as f: f.write(content) return True @@ -84,7 +85,7 @@ def generate_complist(complist_path): file1.close() miss_in_list = man_files.difference(complist_doc) - gen_filename = '../docs/src/hal/components_gen.adoc' + gen_filename = '../docs/build/adoc/en/hal/components_gen.adoc' parts = [] if len(miss_in_list) > 0: parts.append('\n== Not categorized (auto generated from man pages)\n')