From: Nick Bowler Date: Wed, 6 Dec 2023 04:00:42 +0000 (-0500) Subject: fix-gnulib.pl: Convert rules to dirstamp prerequisites. X-Git-Url: https://git.draconx.ca/gitweb/dxcommon.git/commitdiff_plain/8c45dd9fec485578a09dbf541d4209dcf77acd5f fix-gnulib.pl: Convert rules to dirstamp prerequisites. ULTRIX 4.5 make fails during rule lookup when it tries to build a target in a nonexistent directory that might have inference rules associated with it (i.e., ends with a defined suffix), for example: % echo 'nonexistent/baz.o: ;' | make -f - Directory nonexistent/: Make: Cannot open. Stop. We can work around this problem by using a prerequisite to create the output directory instead of creating it directly in the rule. Automake itself actually does this already using dirstamps, so let's try to patch things to use the same mechanism. As a bonus, this should reduce the number of mkdir invocations. This breaks some of the relevant tests which are looking for specific output. Drop the %reldir% test completely as it appears every usage in gnulib is for this exact scenario, and patch the subdirectory test to expect the new output. --- diff --git a/scripts/fix-gnulib.pl b/scripts/fix-gnulib.pl index 640f1cd..9a1f273 100755 --- a/scripts/fix-gnulib.pl +++ b/scripts/fix-gnulib.pl @@ -63,7 +63,6 @@ open STDOUT, ">", $output or die "$output: $!\n" if (defined $output); open STDIN, "<", $input or die "$input: $!\n" if (defined $input); my $printed_header = 0; -my $check_mkdir; my @cleanfiles; # Hashes to record make variables used in the automake source. The allvars @@ -72,6 +71,13 @@ my @cleanfiles; # the value is always set to 1. my (%allvars, %sourcevars); +# Collected names of subdirectories that may need to be created at build time. +# The keys are directory names, the values are targets. +my %gl_dirstamps; + +# State to drop MKDIR_P lines that have been replaced by dirstamps. +my ($have_dirstamp) = (0); + sub drop { undef $_; next; @@ -123,7 +129,21 @@ sub mangle_target { @left = map(mangle_file($_), @left); @right = map(mangle_file($_), @right); - return join(" ", @left) . ": " . join(" ", @right) . "\n"; + my @dirstamps = get_dirstamps(@left); + + return join(" ", @left) . ": " . join(" ", @dirstamps, @right) . "\n"; +} + +sub get_dirstamps { + my %h; + + foreach (@_) { + next unless $_[0] =~ m|^(lib(/.*)?)/[^/]*$|; + + $h{$gl_dirstamps{$1} = "$1/\$(am__dirstamp)"} = 1; + } + + return keys %h; } while () { @@ -232,24 +252,11 @@ EOF # ordinary variable so we can deal with them later. s/BUILT_SOURCES/gnulib_core_headers/; - # Rules for "toplevel" header files do not include commands to create - # the target directory; let's add that. - if (defined $check_mkdir) { - if (/gl_V_at/ || /AM_V_GEN/ and not /MKDIR_P/) { - my $dir = "lib/$check_mkdir"; - $dir =~ s|/[^/]*||; - - print "\t\$(AM_V_GEN)\$(MKDIR_P) $dir\n"; - s/AM_V_GEN|gl_V_at/AM_V_at/; - } - undef $check_mkdir - } - # Targets are similar to variables: the target and its dependencies # need to be mangled. if (/^([^\t:]*):/) { - $check_mkdir = $1; $_ = mangle_target($_); + $have_dirstamp = /am__dirstamp/; } # MKDIR_P commands need to be fixed up; in principle Gnulib could also @@ -271,12 +278,28 @@ EOF # component. s/t-\$@/\$\@-t/g; - # Finally, $(srcdir), $(builddir) and %reldir% need to be fixed up. + # $(srcdir), $(builddir) and %reldir% need to be fixed up. s:\$\(srcdir\):\$\(top_srcdir\)/lib:g; s:\$\(builddir\):\$\(top_builddir\)/lib:g; s:%reldir%:lib:g; + + # If we installed a dirstamp prerequisite for this target, don't + # emit the mkdir line which creates the output directory. + if ($have_dirstamp && m|\$[({]MKDIR_P[})][ '"]*lib/|) { + drop unless s/^(\t\$[({](AM_V_GEN|gl_V_at)[})]).*/\1:/; + } + undef $have_dirstamp if /^\t/; } continue { s/(\n.)/\\\1/g; print; }; +# Define a bunch of fake programs which will ensure Automake produces the +# necessary dirstamp rules, as unfortunately we cannot know in advance which +# will be generated, and the usual Automake behaviour where generated rules +# are suppressed by rules in Makefile.am doesn't actaully work for these. +print <test.mk.in -AT_CHECK([grep '%reldir%' test.mk.in >/dev/null || exit 99]) - -sed -n expout ' -$G -$p -$b -/^## begin gnulib/,/^## end gnulib/!b -/^#/{ -p -b -} -s|(srcdir)|(top_srcdir)| -s|%reldir%|lib| -s|BUILT_SOURCES|gnulib_core_headers| -s|sys[[/_]]|lib/&|g -/^MOSTLYCLEANFILES/{ -h -b -} -p' - -AT_CHECK([test_fix_gnulib -i test.mk.in -o test.mk || exit -sed -n -e '/^## begin gnulib/,/^## end gnulib/p' \ - -e '/CLEANFILES/p' test.mk], -[0], [expout]) - -AT_CLEANUP - AT_SETUP([fix-gnulib.pl warning removal]) AT_KEYWORDS([fix-gnulib perl script scripts]) @@ -965,34 +933,31 @@ AT_CLEANUP AT_SETUP([fix-gnulib.pl header directory creation]) AT_KEYWORDS([fix-gnulib perl script scripts]) -AT_DATA([extract.sed], -[[/AM_V_GEN/b ok -/gl_V_at/b ok -s/:.*/:/ -h -b -:ok -s/'//g -x -G -p -n -s/[)].*/)/ -p +AT_DATA([extract.awk], +[[$0 !~ /^\t/ && $1 ~ /:$/ { + target=$1; + + for (i = 2; i <= NF; i++) { + if ($i ~ /am__dirstamp/) + target = target " " $i; + } + + next; +} + +target != "" && sub(/[$][({](AM_V_GEN|gl_V_at)[})].*$/, "[OK]") { + print target, $1; +} + +{ target=""; } ]]) test_gnulib_mk alloca-opt sys_types stddef >test.mk.in AT_CHECK([test_fix_gnulib -i test.mk.in -o test.mk || exit -sed -n -f extract.sed test.mk], [0], -[[lib/alloca.h: - $(AM_V_GEN)$(MKDIR_P) lib - $(AM_V_at) -lib/sys/types.h: - $(AM_V_GEN)$(MKDIR_P) lib/sys - $(AM_V_at) -lib/stddef.h: - $(AM_V_GEN)$(MKDIR_P) lib - $(AM_V_at) +$AWK -f extract.awk test.mk], [0], +[[lib/alloca.h: lib/$(am__dirstamp) [OK] +lib/sys/types.h: lib/sys/$(am__dirstamp) [OK] +lib/stddef.h: lib/$(am__dirstamp) [OK] ]]) AT_CLEANUP