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