lib/am/distdir.am: strip VPATH srcdir from #line in distributed yacc/lex outputs * bin/automake.in (%ylwrap_dist_files): New. (lang_yacc_target_hook, lang_lex_target_hook): Record distributed outputs and headers. (handle_dist): Define am__ylwrap_dist_files and YLWRAP-DIST. * lib/am/distdir.am (distdir-am): Strip the $(srcdir)/ prefix from "#line" directives of those files taken from the build directory, preserving their timestamps. * t/yacc-lex-vpath-dist-line.sh: New test. * t/list-of-tests.mk: Add it. * doc/automake.texi (Yacc and Lex): Document it. * NEWS: Mention it.
diff --git a/NEWS b/NEWS index e6ff5b6..1c7e152 100644 --- a/NEWS +++ b/NEWS
@@ -35,6 +35,11 @@ - distcheck now detects symbolic links left in the installation tree after uninstall, including dangling links. + - Yacc and lex outputs distributed from a VPATH build no longer carry + "#line" directives pointing to their sources through the build-time + srcdir, e.g. "../src/parse.y"; the distributed copies now refer to + the sources next to them. (bug#39666) + - dist-zstd now honors numeric ZSTD_CLEVEL values, such as 3, instead of treating them as input filenames. This fixes failed or incorrect distribution archives when ZSTD_CLEVEL is set.
diff --git a/bin/automake.in b/bin/automake.in index d8e37c3..8130a8a 100644 --- a/bin/automake.in +++ b/bin/automake.in
@@ -563,6 +563,8 @@ # in some conditions, as [$DISJCONDITIONS, $FILE] pairs. my @dist_common_if_present; +my %ylwrap_dist_files; + # This is set when 'handle_dist' has finished. Once this happens, # we should no longer push on dist_common. my $handle_dist_run; @@ -663,6 +665,7 @@ @dist_common = (); @dist_common_cond = (); @dist_common_if_present = (); + %ylwrap_dist_files = (); $handle_dist_run = 0; @proglist = (); @@ -4058,6 +4061,11 @@ if @if_present; $transform{'DIST-IF-PRESENT'} = !!@if_present; + define_pretty_variable ('am__ylwrap_dist_files', TRUE, INTERNAL, + sort keys %ylwrap_dist_files) + if %ylwrap_dist_files; + $transform{'YLWRAP-DIST'} = !!%ylwrap_dist_files; + # $(am__DIST_COMMON): files to be distributed automatically. Will be # appended to $(DIST_COMMON) in the generated Makefile. # Use 'sort' so that the expansion of $(DIST_COMMON) in the generated @@ -6156,8 +6164,11 @@ # Distribute the generated file, unless its .y source was # listed in a nodist_ variable. (handle_source_transform() # will set DIST_SOURCE.) - push_dist_common ($header) - if $transform{'DIST_SOURCE'}; + if ($transform{'DIST_SOURCE'}) + { + push_dist_common ($header); + $ylwrap_dist_files{$header} = 1; + } # The GNU rules say that yacc/lex output files should be removed # by maintainer-clean. However, if the files are not distributed, @@ -6167,6 +6178,8 @@ } # See the comment above for $HEADER. $clean_files{$output} = $transform{'DIST_SOURCE'} ? MAINTAINER_CLEAN : CLEAN; + $ylwrap_dist_files{$output} = 1 + if $transform{'DIST_SOURCE'}; } # This is a lex helper which is called whenever we have decided to @@ -6179,6 +6192,8 @@ # then we want to remove them with "make clean"; otherwise, # "make distcheck" will fail. $clean_files{$output} = $transform{'DIST_SOURCE'} ? MAINTAINER_CLEAN : CLEAN; + $ylwrap_dist_files{$output} = 1 + if $transform{'DIST_SOURCE'}; } # This is a helper for both lex and yacc.
diff --git a/doc/automake.texi b/doc/automake.texi index e4bcff2..c55334d 100644 --- a/doc/automake.texi +++ b/doc/automake.texi
@@ -6542,7 +6542,11 @@ The intermediate files generated by @command{yacc} (or @command{lex}) will be included in any distribution that is made. That way the user -doesn't need to have @command{yacc} or @command{lex}. +doesn't need to have @command{yacc} or @command{lex}. When these files +are generated in a VPATH build, their @samp{#line} directives refer to +the sources through @code{$(srcdir)}; @samp{make dist} removes this +prefix from the distributed copies, so that they refer to the sources +next to them. If a Yacc source file is seen, then your @file{configure.ac} must define the variable @code{YACC}. This is most easily done by invoking
diff --git a/lib/am/distdir.am b/lib/am/distdir.am index 76c886f..50e3612 100644 --- a/lib/am/distdir.am +++ b/lib/am/distdir.am
@@ -230,6 +230,21 @@ || exit 1; \ done endif %?DIST-IF-PRESENT% +if %?YLWRAP-DIST% + @if test "$(srcdir)" != .; then \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(am__ylwrap_dist_files)'; for file in $$list; do \ + case $$file in "$(srcdir)"/*) continue;; esac; \ + test -f $$file && test -f "$(distdir)/$$file" || continue; \ + rm -f "$(distdir)/$$file" \ + && sed -e "/^#/!b" \ + -e "s|^\(#[ ]*\(line[ ][ ]*\)\{0,1\}[0-9][0-9]*[ ][ ]*\"\)$$srcdirstrip/|\1|" \ + $$file >"$(distdir)/$$file" \ + && touch -r $$file "$(distdir)/$$file" \ + || exit 1; \ + done; \ + fi +endif %?YLWRAP-DIST% ## ## Test for directory existence here because a previous automake ## invocation might have created some directories. Note that we
diff --git a/t/list-of-tests.mk b/t/list-of-tests.mk index 5f4d931..9b7bdcb 100644 --- a/t/list-of-tests.mk +++ b/t/list-of-tests.mk
@@ -1357,6 +1357,7 @@ t/yacc-grepping.sh \ t/yacc-grepping2.sh \ t/yacc-headers-and-dist-pr47.sh \ +t/yacc-lex-vpath-dist-line.sh \ t/yacc-line.sh \ t/yacc-misc.sh \ t/yacc-mix-c-cxx.sh \
diff --git a/t/yacc-lex-vpath-dist-line.sh b/t/yacc-lex-vpath-dist-line.sh new file mode 100755 index 0000000..1aebcb6 --- /dev/null +++ b/t/yacc-lex-vpath-dist-line.sh
@@ -0,0 +1,163 @@ +#! /bin/sh +# Copyright (C) 2026 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +# Yacc and lex outputs generated in a VPATH build must not carry +# "#line" directives pointing through the srcdir into the distribution +# (automake bug#39666). The build tree copies must keep them. +# See also 'yacc-line.sh' and 'lex-line.sh'. + +required='cc yacc lex' +. test-init.sh + +cat >> configure.ac << 'END' +AC_CONFIG_FILES([sub/Makefile]) +AC_PROG_CC +AC_PROG_YACC +AC_PROG_LEX +AC_OUTPUT +END + +mkdir dir sub sub/dir + +cat > Makefile.am << 'END' +AM_LFLAGS = --never-interactive +SUBDIRS = sub +noinst_PROGRAMS = foo bar baz +AM_YFLAGS = -d +bar_YFLAGS = +foo_SOURCES = parse.y +bar_SOURCES = dir/quux.y +baz_SOURCES = scan.l +LDADD = $(LEXLIB) +## Avoid spurious failures with Solaris make. +parse.@OBJEXT@: parse.c +bar-quux.@OBJEXT@: bar-quux.c +END + +cat > sub/Makefile.am << 'END' +AUTOMAKE_OPTIONS = subdir-objects +AM_LFLAGS = --never-interactive +noinst_PROGRAMS = foo +foo_SOURCES = dir/parse.y dir/scan.l +LDADD = $(LEXLIB) +## Avoid spurious failures with Solaris make. +dir/parse.@OBJEXT@: dir/parse.c +dir/scan.@OBJEXT@: dir/scan.c +END + +cat > parse.y << 'END' +%{ +int yylex (void) { return 0; } +void yyerror (const char *s) {} +%} +%% +x : 'x' {}; +%% +int main (void) +{ + return yyparse (); +} +END + +cp parse.y dir/quux.y +sed 's/main/sub_main/;s/^int yylex (void).*/int yylex (void);/' parse.y \ + > sub/dir/parse.y +echo 'int main (void) { return sub_main (); }' >> sub/dir/parse.y + +cat > scan.l << 'END' +%% +"END" return EOF; +. +%% +int main (void) +{ + return 0; +} +int yywrap (void) +{ + return 1; +} +END + +cat > sub/dir/scan.l << 'END' +%% +"END" return 0; +. +%% +int yywrap (void) +{ + return 1; +} +END + +outputs='parse.c parse.h bar-quux.c scan.c sub/dir/parse.c sub/dir/scan.c' + +$ACLOCAL +$AUTOCONF +# FIXME: stop disabling the warnings in the 'unsupported' category +# FIXME: once the 'subdir-objects' option has been mandatory. +$AUTOMAKE -a -Wno-unsupported + +grep '^am__ylwrap_dist_files' Makefile.in sub/Makefile.in + +check_dist () +{ + srcdir=$1 + + $srcdir/configure + $MAKE + $MAKE distdir + ls -l $distdir $distdir/dir $distdir/sub/dir + + # For debugging. + for f in $outputs; do + grep '^#.*line' $distdir/$f || : + done + + # The build tree copies still point to the srcdir. + grep '^#.*line.*"\.\./\.\./sub/dir/parse\.y"' sub/dir/parse.c \ + || grep "^#.*line.*\"$srcdir/sub/dir/parse\\.y\"" sub/dir/parse.c + + # The distributed copies do not. + for f in $outputs; do + $EGREP '^#.*line.*"(\.\./|/)' $distdir/$f && exit 1 + done + grep '^#.*line.*"parse\.y"' $distdir/parse.c + grep '^#.*line.*"dir/quux\.y"' $distdir/bar-quux.c + grep '^#.*line.*"scan\.l"' $distdir/scan.c + grep '^#.*line.*"dir/parse\.y"' $distdir/sub/dir/parse.c + grep '^#.*line.*"dir/scan\.l"' $distdir/sub/dir/scan.c + + # The header must not be older than its parser. + test -z "$(find $distdir/parse.c -newer $distdir/parse.h)" + + $MAKE distcheck +} + +# Relative srcdir. +mkdir build +cd build +check_dist .. +cd .. +rm -rf build + +# Absolute srcdir. +mkdir build +cd build +check_dist "$(cd .. && pwd)" +cd .. + +: