Hi Brendan,

G. Branden Robinson wrote:
> > I would argue that if a file is *not* under version control and is
> > needed by other targets, its rule should be enabled, regardless of
> > --enable-maintainer-mode or not.
> 
> Here's the problem.  Maybe you know of a better solution.
> 
> We include these PNG files in our Texinfo manual.
> 
> $ git grep @image doc/groff.texi.in
> doc/groff.texi.in:@center @image{line-layout,4in,,line layout diagram,.png}
> doc/groff.texi.in:@center @image{gnu,1in,,A wildebeest happily regards a 
> Gutenberg press.,.png}
> 
> The rendered forms of our Texinfo manual are in our distribution
> archive (EXTRA_DIST).
> 
> We also include these PNG files in various groff-generated documents
> that _aren't_ in our distribution archive.
> 
> And we support both in-tree and out-of-tree builds.
> 
> Upon making these seemingly small changes to our Texinfo manual, I ran
> into the same difficulties Dimitris Papavasiliou reported today on the
> help-texinfo list.
>
> ...
> 
> Does GNU Automake support a better method of satisfying our
> requirements?

Yes, it does. Find attached a proposed patch that updates the rules for
doc/gnu.{eps,png} and doc/line-layout.{eps,png}, so that
  * --enable-maintainer-mode is no longer necessary for building from a git
    checkout,
  * a "make" run does no longer update doc/groff.dvi and doc/groff.pdf when
    nothing has changed among the sources,

Tested by
  - running "make" and "make distcheck" in in-tree builds and VPATH builds
    of the git checkout,
  - verifying that the resulting tarball (from "make distcheck") has the same
    contents in both cases,
  - running "make" and "make distcheck" in in-tree builds and VPATH builds
    from that tarball,
  - building this tarball with VPATH builds on FreeBSD, NetBSD (with the
    native 'make') and OpenBSD (with GNU make, because the OpenBSD 'make'
    is known for not supporting VPATH builds well [1]),
  - making small changes to doc/groff.texi.in and doing a VPATH build then,
    then viewing the generated doc/groff.pdf pages 131 and 277.

How does it work?

The main ingredient in the solution is to follow this advice from the GNU
Coding Standards [2]:

  "GNU distributions usually contain some files which are not source files
   —for example, Info files, and the output from Autoconf, Automake, Bison
   or Flex. Since these files normally appear in the source directory, they
   should always appear in the source directory, not in the build directory.
   So Makefile rules to update them should put the updated files in the
   source directory."

I remember that before I implemented this advice in my packages many years
ago, the alternate use of VPATH builds and in-tree builds brought problems:

  - Sometimes a build step in a VPATH build picked up an outdated artifact
    from a previous in-tree build, instead of the newer artifact in the
    build directory. (Probably due to #include handling; I don't remember
    the details.)

  - Some Makefile rules had to be written in such a way that they search for
    a file, first in the build directory, then in the source directory.

This advice thus
  - makes the build more reliable and
  - simplifies the Makefile rules.

So, the main change is to generate doc/line-layout.{eps,png} in the source
directory *and not in the build directory*.

While doing this, the final "mv" in such a rule has to be avoided if the
file has not changed. Otherwise, one of the Automake "make distcheck"
checks, which
  1. unpacks the tarball and makes the source dir read-only,
  2. then does a VPATH build,
would attempt to overwrite a file in the read-only source dir and fail.

Even with this in place, I noticed that "make" in a VPATH build would
still regenerate doc/line-layout.eps and, accordingly, also
  doc/line-layout.png
  doc/groff.dvi
  doc/groff.pdf
The reason is that the 'gs' command stores a "CreationDate" time stamp
in the doc/line-layout.eps file. Once I changed the rule to eliminate
the CreationDate line, the 4 files are no longer rebuilt without need.

Then I did the same changes for doc/gnu.{eps,png}. Not because it's
needed to fix an actual build problem, but in order to keep doc/doc.am
consistent.

Next steps after this patch:
  - You could apply said rule also to doc/groff.dvi and doc/groff.pdf,
    as an exercise. Not that it would fix an actual build problem,
    because no other build artifact depends on these two.
  - You could un-recommend the use of --enable-maintainer-mode.

Bruno

[1] see gnulib/modules/parse-datetime
[2] https://www.gnu.org/prep/standards/html_node/Makefile-Basics.html
>From 48fef1944f0e5c188f2bcd2a66acf3a7de3d91e0 Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Thu, 6 Aug 2026 22:54:14 +0200
Subject: [PATCH] build: Avoid remaking groff.{dvi,pdf}, without the need for
 "maintainer mode".

The files doc/gnu.{eps,png} and doc/line-layout.{eps,png} are listed in
EXTRA_DIST (because they are intermediate files for groff.pdf, also
distributed, and they need special programs to build them).
By the GNU Coding Standards
<https://www.gnu.org/prep/standards/html_node/Makefile-Basics.html>
these files should be generated in the source directory.

* doc/doc.am: Make doc/gnu.{eps,png} and doc/line-layout.{eps,png} reside
in the source directory only.
(install_doc_gnu_eps, install_doc_gnu_png, $(GROFF_HTML)): Simplify
accordingly.
($(DOC_GNU_EPS), $(DOC_GNU_PNG)): Adjust accordingly. Define also outside
MAINTAINER_MODE.
($(DOC_LINE_LAYOUT_EPS), $(DOC_LINE_LAYOUT_PNG)): Adjust accordingly.
Overwrite the file in the source directory only if it has actually changed;
needed for Automake's "make distcheck". Remove the %%CreationDate line
from the generated PostScript. Define also outside MAINTAINER_MODE.
---
 doc/doc.am | 111 +++++++++++++++++++++++++++--------------------------
 1 file changed, 56 insertions(+), 55 deletions(-)

diff --git a/doc/doc.am b/doc/doc.am
index 33290d229..e699cbf9c 100644
--- a/doc/doc.am
+++ b/doc/doc.am
@@ -405,12 +405,13 @@ doc/pic.pdf: $(doc_srcdir)/pic.ms $(TMAC_PACKAGE_MS) eqn pic tbl
 
 doc/groff-pdf-features.pdf: $(doc_srcdir)/groff-pdf-features.ms \
   contrib/sboxes/sboxes.tmac \
-  $(TMAC_PACKAGE_MS) eqn pic tbl pdfmom $(DOC_GNU_PNG) font/devpdf/stamp
+  $(TMAC_PACKAGE_MS) eqn pic tbl pdfmom $(top_srcdir)/$(DOC_GNU_PNG) \
+  font/devpdf/stamp
 	$(GROFF_V)$(MKDIR_P) `dirname $@` \
 	&& $(DOC_PDFMOM) --roff -tU -P-pa4 -rPDFFEAT=1 -ms -msboxes \
 	-I $(doc_builddir) -I $(doc_srcdir) $(doc_srcdir)/groff-pdf-features.ms >$@
 
-doc/webpage.ps: $(DOC_GNU_EPS) tmac/pspic.tmac tmac/www.tmac tbl
+doc/webpage.ps: $(top_srcdir)/$(DOC_GNU_EPS) tmac/pspic.tmac tmac/www.tmac tbl
 doc/webpage.ps: $(doc_srcdir)/webpage.ms $(TMAC_PACKAGE_MS)
 	$(GROFF_V)$(MKDIR_P) `dirname $@` \
 	&& $(DOC_GROFF) -I $(doc_srcdir) -I $(doc_builddir) -t -Tps \
@@ -437,11 +438,12 @@ doc/pic.html: $(doc_srcdir)/pic.ms $(TMAC_PACKAGE_MS)
 
 # XXX: See XXX comment before "pic.html" target above.
 #
-# Note: we depend on `$(DOC_GNU_EPS)` because the document uses the
-# `PSPIC` macro to inline the image, and `PSPIC` insists on getting an
-# EPS version of the image to compute its bounding box even if that
-# image format does not itself end up in the document.
-doc/webpage.html: $(DOC_GNU_EPS) $(DOC_GNU_PNG) tmac/www.tmac tbl
+# Note: we depend on `$(top_srcdir)/$(DOC_GNU_EPS)` because the document
+# uses the `PSPIC` macro to inline the image, and `PSPIC` insists on
+# getting an EPS version of the image to compute its bounding box even
+# if that image format does not itself end up in the document.
+doc/webpage.html: $(top_srcdir)/$(DOC_GNU_EPS) $(top_srcdir)/$(DOC_GNU_PNG)
+doc/webpage.html: tmac/www.tmac tbl
 doc/webpage.html: $(doc_srcdir)/groff.css
 doc/webpage.html: $(doc_srcdir)/webpage.ms $(TMAC_PACKAGE_MS)
 	$(GROFF_V)$(MKDIR_P) $(doc_builddir) \
@@ -527,27 +529,17 @@ endif # USE_GROHTML
 install-data-hook: \
   install_doc_gnu_eps install_doc_gnu_png install_doc_examples
 
-install_doc_gnu_eps: $(DOC_GNU_EPS)
-	for d in $(doc_builddir) $(doc_srcdir); do \
-	  if test -f "$$d/gnu.eps"; then \
-	    $(RM) $(DESTDIR)$(exampledir)/gnu.eps; \
-	    $(INSTALL_DATA) \
-	      $$d/gnu.eps $(DESTDIR)$(exampledir)/gnu.eps; \
-	    break; \
-	  fi; \
-	done
+install_doc_gnu_eps: $(top_srcdir)/$(DOC_GNU_EPS)
+	$(RM) $(DESTDIR)$(exampledir)/gnu.eps; \
+	$(INSTALL_DATA) \
+	  $(doc_srcdir)/gnu.eps $(DESTDIR)$(exampledir)/gnu.eps
 
-install_doc_gnu_png: $(DOC_GNU_PNG)
-	for d in $(doc_builddir) $(doc_srcdir); do \
-	  if test -f "$$d/gnu.png"; then \
-	    $(RM) $(DESTDIR)$(exampledir)/gnu.png; \
-	    $(INSTALL_DATA) \
-	      $$d/gnu.png $(DESTDIR)$(exampledir)/gnu.png; \
-	    break; \
-	  fi; \
-	done
+install_doc_gnu_png: $(top_srcdir)/$(DOC_GNU_PNG)
+	$(RM) $(DESTDIR)$(exampledir)/gnu.png; \
+	$(INSTALL_DATA) \
+	  $(doc_srcdir)/gnu.png $(DESTDIR)$(exampledir)/gnu.png
 
-install_doc_examples: $(DOC_GNU_EPS) $(DOC_GNU_PNG)
+install_doc_examples: $(top_srcdir)/$(DOC_GNU_EPS) $(top_srcdir)/$(DOC_GNU_PNG)
 if USE_GROHTML
 	cd $(doc_builddir) \
 	&& for f in `ls $(HTMLEXAMPLEFILESALL)`; do \
@@ -628,8 +620,8 @@ GROFF_DVI = doc/groff.dvi
 GROFF_PDF = doc/groff.pdf
 endif # USE_TEX
 
-$(GROFF_DVI): $(DOC_GNU_EPS) $(DOC_LINE_LAYOUT_EPS)
-$(GROFF_PDF): $(DOC_GNU_PNG) $(DOC_LINE_LAYOUT_PNG)
+$(GROFF_DVI): $(top_srcdir)/$(DOC_GNU_EPS) $(top_srcdir)/$(DOC_LINE_LAYOUT_EPS)
+$(GROFF_PDF): $(top_srcdir)/$(DOC_GNU_PNG) $(top_srcdir)/$(DOC_LINE_LAYOUT_PNG)
 
 # pdfTeX can find resources in a VPATH build when generating PDF (with
 # pdfetex), but not when generating DVI (with etex).  Steer the latter's
@@ -640,19 +632,15 @@ TEXINPUTS="$(doc_srcdir)$(PATH_SEPARATOR)$$TEXINPUTS"
 # HTML from Texinfo to include our embedded images.
 #
 # TODO: Maybe split this into `GROFF_HTML_MONO` and `GROFF_HTML_NODE`?
-$(GROFF_HTML): doc/groff.texi $(DOC_GNU_PNG) $(DOC_LINE_LAYOUT_PNG)
+$(GROFF_HTML): doc/groff.texi \
+  $(top_srcdir)/$(DOC_GNU_PNG) $(top_srcdir)/$(DOC_LINE_LAYOUT_PNG)
 	$(AM_V_GEN)$(MKDIR_P) `dirname $@` \
 	&& LANG=C LC_ALL=C $(MAKEINFO) --html \
 	  --css-ref="https://www.gnu.org/software/gnulib/manual.css"; \
 	  -I $(doc_builddir) -I $(doc_srcdir) \
 	  -o $(GROFF_HTML).node $< \
-	&& if test -f "$(srcdir)/$(DOC_GNU_PNG)"; then \
-	  cp -f "$(srcdir)/$(DOC_GNU_PNG)" \
-	    "$(srcdir)/$(DOC_LINE_LAYOUT_PNG)" $(GROFF_HTML).node; \
-	else \
-	  cp -f "$(builddir)/$(DOC_GNU_PNG)" \
-	    "$(builddir)/$(DOC_LINE_LAYOUT_PNG)" $(GROFF_HTML).node; \
-	fi \
+	&& cp -f "$(srcdir)/$(DOC_GNU_PNG)" \
+	     "$(srcdir)/$(DOC_LINE_LAYOUT_PNG)" $(GROFF_HTML).node \
 	&& LANG=C LC_ALL=C $(MAKEINFO) --html \
 	  --css-ref="https://www.gnu.org/software/gnulib/manual.css"; \
 	  -I $(doc_builddir) -I $(doc_srcdir) \
@@ -888,8 +876,7 @@ EXTRA_DIST += \
   $(DOC_LINE_LAYOUT_EPS) \
   $(DOC_LINE_LAYOUT_PNG)
 
-if MAINTAINER_MODE
-$(DOC_GNU_EPS): doc/gnu.xpm
+$(top_srcdir)/$(DOC_GNU_EPS): doc/gnu.xpm
 	$(AM_V_GEN)$(MKDIR_P) `dirname $@` \
 	&& if test "$(XPMTOPPM)" != found; then \
 	  echo "program 'xpmtoppm' is missing; can't generate $@" >&2; \
@@ -907,7 +894,7 @@ $(DOC_GNU_EPS): doc/gnu.xpm
 	xpmtoppm $(top_srcdir)/doc/gnu.xpm | pnmdepth 15 \
 	  | $(pnmtops_nosetpage) -noturn -rle >$@
 
-$(DOC_GNU_PNG): doc/gnu.xpm
+$(top_srcdir)/$(DOC_GNU_PNG): doc/gnu.xpm
 	$(AM_V_GEN)$(MKDIR_P) `dirname $@` \
 	&& if test "$(XPMTOPPM)" != found; then \
 	  echo "program 'xpmtoppm' is missing; can't generate $@" >&2; \
@@ -924,27 +911,41 @@ $(DOC_GNU_PNG): doc/gnu.xpm
 	fi; \
 	xpmtoppm $(top_srcdir)/doc/gnu.xpm | pnmtopng >$@
 
-$(DOC_LINE_LAYOUT_EPS): doc/line-layout.roff pic groff troff grops \
-  font/devps/stamp
-	$(AM_V_GEN)$(MKDIR_P) `dirname $@` \
+$(top_srcdir)/$(DOC_LINE_LAYOUT_EPS): doc/line-layout.roff pic groff \
+  troff grops font/devps/stamp
+# Create $(DOC_LINE_LAYOUT_EPS).tmp in $(top_builddir). Then move
+# $(DOC_LINE_LAYOUT_EPS).tmp into $(top_srcdir). But don't provoke
+# a gratuitous error in a VPATH build with read-only $(top_srcdir).
+	$(AM_V_GEN)$(MKDIR_P) `dirname $(DOC_LINE_LAYOUT_EPS).tmp` \
 	&& $(DOC_GROFF) -p -T ps -P -b16 $< >$(DOC_LL).ps \
 	&& gs -q -dNOPAUSE -sDEVICE=bbox -- $(DOC_LL).ps \
 	  2> $(DOC_LL).bbox \
-	&& sed -e '/^%%Orientation/r $(DOC_LL).bbox' \
-	  -e '/^%!PS-Adobe-3.0/s/$$/ EPSF-3.0/' $(DOC_LL).ps >[email protected] \
+	&& sed -e '/^%%CreationDate/d' \
+	  -e '/^%%Orientation/r $(DOC_LL).bbox' \
+	  -e '/^%!PS-Adobe-3.0/s/$$/ EPSF-3.0/' $(DOC_LL).ps \
+	  > $(DOC_LINE_LAYOUT_EPS).tmp \
 	&& $(RM) $(DOC_LL).ps $(DOC_LL).bbox \
-	&& mv [email protected] $@
+	&& if test '$(srcdir)' != . \
+	      && test -f $@ \
+	      && cmp $(DOC_LINE_LAYOUT_EPS).tmp $@ >/dev/null; then \
+	  rm -f $(DOC_LINE_LAYOUT_EPS).tmp; \
+	else \
+	  mv -f $(DOC_LINE_LAYOUT_EPS).tmp $@; \
+	fi
 
-$(DOC_LINE_LAYOUT_PNG): $(DOC_LINE_LAYOUT_EPS)
-	$(AM_V_GEN)$(MKDIR_P) `dirname $@` \
-	&& convert -density 300 $< PNG24:$@
-else
-$(DOC_GNU_EPS) \
-  $(DOC_GNU_PNG) \
-  $(DOC_LINE_LAYOUT_EPS) \
-  $(DOC_LINE_LAYOUT_PNG):
-	@:
-endif # MAINTAINER_MODE
+$(top_srcdir)/$(DOC_LINE_LAYOUT_PNG): $(top_srcdir)/$(DOC_LINE_LAYOUT_EPS)
+# Create $(DOC_LINE_LAYOUT_PNG) in $(top_builddir). Then move
+# $(DOC_LINE_LAYOUT_PNG) into $(top_srcdir). But don't provoke
+# a gratuitous error in a VPATH build with read-only $(top_srcdir).
+	$(AM_V_GEN)$(MKDIR_P) `dirname $(DOC_LINE_LAYOUT_PNG)` \
+	&& convert -density 300 $< PNG24:$(DOC_LINE_LAYOUT_PNG) \
+	&& if test '$(srcdir)' != .; then \
+	  if test -f $@ && cmp $(DOC_LINE_LAYOUT_PNG) $@ >/dev/null; then \
+	    rm -f $(DOC_LINE_LAYOUT_PNG); \
+	  else \
+	    mv -f $(DOC_LINE_LAYOUT_PNG) $@; \
+	  fi; \
+	fi
 
 MAINTAINERCLEANFILES += \
   $(DOC_GNU_EPS) \
-- 
2.53.0

  • ... Bruno Haible via discussion of the GNU roff typesetting system and related software
    • ... G. Branden Robinson
      • ... Bruno Haible via discussion of the GNU roff typesetting system and related software
        • ... G. Branden Robinson
          • ... Bruno Haible via discussion of the GNU roff typesetting system and related software

Reply via email to