maint: Update HACKING
[automake.git] / gen-testsuite-part
blob3c5fc3852768430643c7bdcc9761c4f26a42cc01
1 #! /usr/bin/env perl
2 # Automatically compute some dependencies for the hand-written tests
3 # of the Automake testsuite. Also, automatically generate some more
4 # tests from them (for particular cases/setups only).
6 # Copyright (C) 2011-2017 Free Software Foundation, Inc.
8 # This program is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 2, or (at your option)
11 # any later version.
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with this program. If not, see <https://www.gnu.org/licenses/>.
21 #--------------------------------------------------------------------------
23 use warnings FATAL => "all";
24 use strict;
25 use File::Basename ();
26 use constant TRUE => 1;
27 use constant FALSE => 0;
29 my $me = File::Basename::basename $0;
31 # For use in VPATH builds.
32 my $srcdir = ".";
34 # The testsuite subdirectory, relative to the top-lever source directory.
35 my $testdir = "t";
37 # Where testsuite-related helper scripts, data files and shell libraries
38 # are placed. Relative to the top-lever source directory.
39 my $testauxdir = "$testdir/ax";
41 #--------------------------------------------------------------------------
43 sub unindent ($)
45 my $text = shift;
46 $text =~ /^(\s*)/;
47 my $indentation = $1;
48 $text =~ s/^$indentation//gm;
49 return $text;
52 sub atomic_write ($$;$)
54 my ($outfile, $func) = (shift, shift);
55 my $perms = @_ > 0 ? shift : 0777;
56 my $tmpfile = "$outfile-t";
57 foreach my $f ($outfile, $tmpfile)
59 unlink $f or die "$me: cannot unlink '$f': $!\n"
60 if -e $f;
62 open (my $fh, ">$tmpfile")
63 or die "$me: can't write to '$tmpfile': $!\n";
64 $func->($fh);
65 close $fh
66 or die "$me: closing '$tmpfile': $!\n";
67 chmod ($perms & ~umask, $tmpfile)
68 or die "$me: cannot change perms for '$tmpfile': $!\n";
69 rename ($tmpfile, $outfile)
70 or die "$me: renaming '$tmpfile' -> '$outfile: $!\n'";
73 sub line_match ($$)
75 my ($re, $file) = (shift, shift);
76 # Try both builddir and srcdir, with builddir first, to play nice
77 # with VPATH builds.
78 open (FH, "<$file") or open (FH, "<$srcdir/$file")
79 or die "$me: cannot open file '$file': $!\n";
80 my $ret = 0;
81 while (defined (my $line = <FH>))
83 if ($line =~ $re)
85 $ret = 1;
86 last;
89 close FH or die "$me: cannot close file '$file': $!\n";
90 return $ret;
93 sub write_wrapper_script ($$$)
95 my ($file_handle, $wrapped_test, $shell_setup_code, $creator_name) = @_;
96 print $file_handle unindent <<EOF;
97 #! /bin/sh
98 # This file has been automatically generated. DO NOT EDIT BY HAND!
99 . test-lib.sh
100 $shell_setup_code
101 # In the spirit of VPATH, we prefer a test in the build tree
102 # over one in the source tree.
103 for dir in . "\$am_top_srcdir"; do
104 if test -f "\$dir/$wrapped_test"; then
105 echo "\$0: will source \$dir/$wrapped_test"
106 . "\$dir/$wrapped_test"; exit \$?
108 done
109 echo "\$0: cannot find wrapped test '$wrapped_test'" >&2
110 exit 99
114 sub get_list_of_tests ()
116 my $make = defined $ENV{MAKE} ? $ENV{MAKE} : "make";
117 # Unset MAKEFLAGS, for when we are called from make itself.
118 my $cmd = "MAKEFLAGS= && unset MAKEFLAGS && cd '$srcdir' && "
119 . "$make -s -f $testdir/list-of-tests.mk print-list-of-tests";
120 my @tests_list = split /\s+/, `$cmd`;
121 die "$me: cannot get list of tests\n" unless $? == 0 && @tests_list;
122 my $ok = 1;
123 foreach my $test (@tests_list)
125 # Respect VPATH builds.
126 next if -f $test || -f "$srcdir/$test";
127 warn "$me: test '$test' not found\n";
128 $ok = 0;
130 die "$me: some test scripts not found\n" if !$ok;
131 return @tests_list;
134 sub parse_options (@)
136 use Getopt::Long qw/GetOptions/;
137 local @ARGV = @_;
138 GetOptions ('srcdir=s' => \$srcdir) or die "$me: usage error\n";
139 die "$me: too many arguments\n" if @ARGV > 0;
140 die "$me: srcdir '$srcdir': not a directory\n" unless -d $srcdir;
143 #--------------------------------------------------------------------------
145 my %deps_extractor =
147 libtool_macros =>
149 line_matcher => qr/^\s*required=.*\blibtool/,
150 nodist_prereqs => "$testdir/libtool-macros.log",
152 gettext_macros =>
154 line_matcher => qr/^\s*required=.*\bgettext/,
155 nodist_prereqs => "$testdir/gettext-macros.log",
157 pkgconfig_macros =>
159 line_matcher => qr/^\s*required=.*\bpkg-config/,
160 nodist_prereqs => "$testdir/pkg-config-macros.log",
162 use_trivial_test_driver =>
164 line_matcher => qr/\btrivial-test-driver\b/,
165 dist_prereqs => "$testauxdir/trivial-test-driver",
167 check_testsuite_summary =>
169 line_matcher => qr/\btestsuite-summary-checks\.sh\b/,
170 dist_prereqs => "$testauxdir/testsuite-summary-checks.sh",
172 extract_testsuite_summary =>
174 line_matcher => qr/\bextract-testsuite-summary\.pl\b/,
175 dist_prereqs => "$testauxdir/extract-testsuite-summary.pl",
177 check_tap_testsuite_summary =>
179 line_matcher => qr/\btap-summary-aux\.sh\b/,
180 dist_prereqs => "$testauxdir/tap-summary-aux.sh",
182 on_tap_with_common_setup =>
184 line_matcher => qr/\btap-setup\.sh\b/,
185 dist_prereqs => "$testauxdir/tap-setup.sh",
186 nodist_prereqs => "$testdir/tap-common-setup.log",
188 depcomp =>
190 line_matcher => qr/\bdepcomp\.sh\b/,
191 dist_prereqs => "$testauxdir/depcomp.sh",
195 #--------------------------------------------------------------------------
197 my %test_generators =
200 # Any test script in the Automake testsuite that checks features of
201 # the Automake-provided parallel testsuite harness might want to
202 # define a sibling test that does similar checks, but for the old
203 # serial testsuite harness instead.
205 # Individual tests can request the creation of such a sibling by
206 # making the string "try-with-serial-tests" appear any line of the
207 # test itself.
209 serial_testsuite_harness =>
211 line_matcher => qr/\btry-with-serial-tests\b/,
212 shell_setup_code => 'am_serial_tests=yes',
215 # For each test script in the Automake testsuite that tests features
216 # of one or more automake-provided shell script from the 'lib/'
217 # subdirectory by running those scripts directly (i.e., not thought
218 # make calls and automake-generated makefiles), define a sibling test
219 # that does likewise, but running the said script with the configure
220 # time $SHELL instead of the default system shell /bin/sh.
222 # A test is considered a candidate for sibling-generation if it calls
223 # the 'get_shell_script' function anywhere.
225 # Individual tests can prevent the creation of such a sibling by
226 # explicitly setting the '$am_test_prefer_config_shell' variable
227 # to either "yes" or "no".
228 # The rationale for this is that if the variable is set to "yes",
229 # the test already uses $SHELL, so that a sibling would be just a
230 # duplicate; while if the variable is set to "no", the test doesn't
231 # support, or is not meant to use, $SHELL to run the script under
232 # testing, and forcing it to do so in the sibling would likely
233 # cause a spurious failure.
235 prefer_config_shell =>
237 line_matcher =>
238 qr/(^|\s)get_shell_script\s/,
239 line_rejecter =>
240 qr/\bam_test_prefer_config_shell=/,
241 shell_setup_code =>
242 'am_test_prefer_config_shell=yes',
246 #--------------------------------------------------------------------------
248 parse_options @ARGV;
250 my @all_tests = get_list_of_tests;
251 my @generated_tests = (); # Will be updated later.
253 print "## -*- Makefile -*-\n";
254 print "## Generated by $me. DO NOT EDIT BY HAND!\n\n";
256 print <<EOF;
258 ## --------------------------------------------- ##
259 ## Autogenerated tests and their dependencies. ##
260 ## --------------------------------------------- ##
264 # A test script '$test' can possibly match more than one condition, so
265 # for each tests we need to keep a list of generated wrapper tests.
266 # Since what defines these wrapper scripts is the set of initializations
267 # that are issued before sourcing the original, wrapped tests, these
268 # initializations is what we put in our list entries.
269 # The list will be saved in the hash entry '$wrapper_setups{$test}'.
270 my %wrapper_setups = ();
271 foreach my $test (@all_tests)
273 my @setups = ('');
274 foreach my $x (values %test_generators)
276 next
277 if not line_match $x->{line_matcher}, $test;
278 next
279 if $x->{line_rejecter} and line_match $x->{line_rejecter}, $test;
280 @setups = map { ($_, "$_\n$x->{shell_setup_code}") } @setups;
282 @setups = grep { $_ ne '' } @setups;
283 $wrapper_setups{$test} = \@setups if @setups;
285 # And now create all the wrapper tests.
286 for my $wrapped_test (sort keys %wrapper_setups)
288 my $setup_list = $wrapper_setups{$wrapped_test};
289 (my $base = $wrapped_test) =~ s/\.([^.]*)$//;
290 my $suf = $1 or die "$me: test '$wrapped_test' lacks a suffix\n";
291 my $count = 0;
292 foreach my $setup (@$setup_list)
294 $count++;
295 my $wbase = "$base-w" . ($count > 1 ? $count : '');
296 my $wrapper_test = "$wbase.$suf";
297 # Register wrapper test as "autogenerated".
298 push @generated_tests, $wrapper_test;
299 # Create wrapper test.
300 atomic_write $wrapper_test,
301 sub { write_wrapper_script $_[0], $wrapped_test,
302 $setup },
303 0444;
304 # The generated test works by sourcing the original test, so that
305 # it has to be re-run every time that changes ...
306 print "$wbase.log: $wrapped_test\n";
307 # ... but also every time the prerequisites of the wrapped test
308 # changes. The simpler (although suboptimal) way to do so is to
309 # ensure that the wrapped tests runs before the wrapper one (in
310 # case it needs to be re-run *at all*).
311 # FIXME: we could maybe refactor the script to find a more
312 # granular way to express such implicit dependencies.
313 print "$wbase.log: $base.log\n";
317 print <<EOF;
319 ## ---------------------------------------------------- ##
320 ## Ad-hoc autogenerated tests and their dependencies. ##
321 ## ---------------------------------------------------- ##
325 print "## Tests on automatic dependency tracking (see 'depcomp.sh').\n";
327 # Key: depmode, value: list of required programs.
328 my %depmodes =
330 auto => ["cc"],
331 disabled => ["cc"],
332 makedepend => ["cc", "makedepend", "-c-o"],
333 dashmstdout => ["gcc"],
334 cpp => ["gcc"],
335 # This was for older (pre-3.x) GCC versions (newer versions
336 # have depmode "gcc3"). But other compilers use this depmode
337 # as well (for example, the IMB xlc/xlC compilers, and the HP
338 # C compiler, see 'lib/depcomp' for more info), so it's not
339 # obsolete, and it's worth giving it some coverage.
340 gcc => ["gcc"],
341 # This is for older (pre-7) msvc versions. Newer versions
342 # have depmodes "msvc7" and "msvc7msys".
343 msvisualcpp => ["cl", "cygpath"],
344 msvcmsys => ["cl", "mingw"],
347 foreach my $lt (TRUE, FALSE)
349 foreach my $m (sort keys %depmodes)
351 my $planned = ($lt && $m eq "auto") ? 84 : 28;
352 my @required =
354 @{$depmodes{$m}},
355 $lt ? ("libtoolize",) : (),
357 my @vars_init =
359 "am_create_testdir=empty",
360 "depmode=$m",
361 "depcomp_with_libtool=" . ($lt ? "yes" : "no"),
363 my $test = "$testdir/depcomp" . ($lt ? "-lt-" : "-") . "$m.tap";
364 # Register wrapper test as "autogenerated" ...
365 push @generated_tests, $test;
366 # ... and create it.
367 atomic_write ($test, sub
369 my $file_handle = shift;
370 print $file_handle unindent <<EOF;
371 #! /bin/sh
372 # Automatically generated test. DO NOT EDIT BY HAND!
373 @vars_init
374 required="@required"
375 . test-init.sh
376 plan_ $planned
377 . depcomp.sh
378 exit \$?
381 0444);
385 # Update generated makefile fragment to account for all the generated tests.
386 print "generated_TESTS =\n";
387 map { print "generated_TESTS += $_\n" } @generated_tests;
389 # The test scripts are scanned for automatic dependency generation *after*
390 # the generated tests have been created, so they too can be scanned. To
391 # do so correctly, we need to update the list in '@all_tests' to make it
392 # comprise also the freshly-generated tests.
394 push @all_tests, @generated_tests;
396 print <<EOF;
398 ## ----------------------------- ##
399 ## Autogenerated dependencies. ##
400 ## ----------------------------- ##
404 for my $k (sort keys %deps_extractor)
406 my $x = $deps_extractor{$k};
407 my $dist_prereqs = $x->{dist_prereqs} || "";
408 my $nodist_prereqs = $x->{nodist_prereqs} || "";
409 my @tests = grep { line_match $x->{line_matcher}, $_ } @all_tests;
410 map { s/\.[^.]*$//; s/$/\.log/; } (my @logs = @tests);
411 print "## Added by deps-extracting key '$k'.\n";
412 ## The list of all tests which have a dependency detected by the
413 ## current key.
414 print join(" \\\n ", "${k}_TESTS =", @tests) . "\n";
415 print "EXTRA_DIST += $dist_prereqs\n";
416 map { print "$_: $dist_prereqs $nodist_prereqs\n" } @logs;
417 print "\n";
420 __END__