From 5b578656c851bc4683c92309c105dd81933f1af7 Mon Sep 17 00:00:00 2001 From: Luca Toniolo <10792599+grandixximo@users.noreply.github.com> Date: Mon, 1 Jun 2026 10:17:31 +0800 Subject: [PATCH 1/2] docs(build): render English from build/adoc/en, keep docs/src clean Per review (BsAtHome): generated files should not live in the source tree. The English docs now render from build/adoc/en, the same model the translations already use, instead of from docs/src. - Stage the English .adoc + images + code fixtures (e.g. panelui_handler.py) into build/adoc/en via a find|tar copy (no rsync dependency). - Generate components_gen.adoc straight into build/adoc/en/hal and point its po4a master there (po4a.cfg only; msgids unchanged, so no pot/po churn). - Repoint the English HTML and PDF rules, the html-copy step, and the dependency extractor at build/adoc/en. docs/src no longer accumulates components_gen.adoc or per-topic .html; docs/.gitignore drops those entries. The .dot-rendered SVGs are still generated in src/code and staged across (a follow-on moves their generation into build too). Validated with a full English htmldocs build (585 pages, no include errors). PDF and translated builds still to be verified. --- docs/.gitignore | 10 +++------ docs/po4a.cfg | 2 +- docs/src/Submakefile | 44 ++++++++++++++++++++++++++++++++-------- docs/src/gen_complist.py | 3 ++- 4 files changed, 42 insertions(+), 17 deletions(-) diff --git a/docs/.gitignore b/docs/.gitignore index 3a1fe66a79e..b5bde227179 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -2,15 +2,11 @@ # .gitignore). Paths are relative to docs/. # Rendered output: HTML, PDF, and po4a-translated .adoc all land under build/. +# The English docs now render from build/adoc/en too, so nothing is generated +# beside the sources anymore (components_gen.adoc and the per-topic .html used +# to live in src/). 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 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..de9143d3bf9 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 @@ -521,7 +522,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 +831,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 +902,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 +926,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 $< $@ @@ -1046,7 +1047,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),))) 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') From c99d73c61fdee720cc52d89ea45eba8cd428df4d Mon Sep 17 00:00:00 2001 From: Luca Toniolo <10792599+grandixximo@users.noreply.github.com> Date: Mon, 1 Jun 2026 11:12:14 +0800 Subject: [PATCH 2/2] docs(build): render .dot SVGs into build/, drop them from src The .dot diagrams under docs/src/code/ rendered their SVGs beside the sources; route them into build/adoc/en/ instead, so docs/src holds no generated artifacts. The translated image-copy steps source images from src, so fall back to the English build tree for the generated SVGs. Drops the six src/code/*.svg entries from docs/.gitignore. --- docs/.gitignore | 14 ++------------ docs/src/Submakefile | 27 +++++++++++++++++++++++---- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/docs/.gitignore b/docs/.gitignore index b5bde227179..970189a9dd1 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -1,20 +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/. -# The English docs now render from build/adoc/en too, so nothing is generated -# beside the sources anymore (components_gen.adoc and the per-topic .html used -# to live in src/). +# 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/ -# 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/src/Submakefile b/docs/src/Submakefile index de9143d3bf9..9452740b985 100644 --- a/docs/src/Submakefile +++ b/docs/src/Submakefile @@ -426,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 @@ -944,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)/%%'); \ @@ -954,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; \ @@ -997,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; \ @@ -1111,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))