This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Improve bisect.pl's documentation.
[perl5.git] / Porting / bisect-runner.pl
CommitLineData
6a8dbfd7
NC
1#!/usr/bin/perl -w
2use strict;
3
390a69a9 4use Getopt::Long qw(:config bundling no_auto_abbrev);
77ae6092 5use Pod::Usage;
2526f4b8 6use Config;
6a8dbfd7 7
2526f4b8
NC
8my @targets
9 = qw(config.sh config.h miniperl lib/Config.pm Fcntl perl test_prep);
6a8dbfd7 10
e4516dd0
NC
11my $cpus;
12if (open my $fh, '<', '/proc/cpuinfo') {
13 while (<$fh>) {
14 ++$cpus if /^processor\s+:\s+\d+$/;
15 }
d64af352
NC
16} elsif (-x '/sbin/sysctl') {
17 $cpus = 1 + $1 if `/sbin/sysctl hw.ncpu` =~ /^hw\.ncpu: (\d+)$/;
e4516dd0
NC
18}
19
f4800c99
NC
20my %options =
21 (
e4516dd0 22 jobs => defined $cpus ? $cpus + 1 : 2,
f4800c99
NC
23 'expect-pass' => 1,
24 clean => 1, # mostly for debugging this
25 );
6a8dbfd7 26
390a69a9
NC
27my @paths = qw(/usr/local/lib64 /lib64 /usr/lib64);
28
29my %defines =
30 (
31 usedevel => '',
32 optimize => '-g',
33 cc => 'ccache gcc',
34 ld => 'gcc',
e4516dd0 35 (`uname -sm` eq "Linux x86_64\n" ? (libpth => \@paths) : ()),
390a69a9
NC
36 );
37
f4800c99
NC
38unless(GetOptions(\%options,
39 'target=s', 'jobs|j=i', 'expect-pass=i',
40 'expect-fail' => sub { $options{'expect-pass'} = 0; },
41 'clean!', 'one-liner|e=s', 'match=s', 'force-manifest',
77ae6092 42 'test-build', 'check-args', 'A=s@', 'usage|help|?',
390a69a9
NC
43 'D=s@' => sub {
44 my (undef, $val) = @_;
45 if ($val =~ /\A([^=]+)=(.*)/s) {
46 $defines{$1} = length $2 ? $2 : "\0";
47 } else {
48 $defines{$val} = '';
49 }
50 },
51 'U=s@' => sub {
52 $defines{$_[1]} = undef;
53 },
6a8dbfd7 54 )) {
77ae6092 55 pod2usage(exitval => 255, verbose => 1);
6a8dbfd7
NC
56}
57
f4800c99 58my ($target, $j, $match) = @options{qw(target jobs match)};
e295b7be 59
77ae6092
NC
60pod2usage(exitval => 255, verbose => 1) if $options{usage};
61pod2usage(exitval => 255, verbose => 1)
62 unless @ARGV || $match || $options{'test-build'} || defined $options{'one-liner'};
6a8dbfd7 63
f4800c99 64exit 0 if $options{'check-args'};
6a8dbfd7 65
77ae6092
NC
66=head1 NAME
67
68bisect.pl - use git bisect to pinpoint changes
69
70=head1 SYNOPSIS
71
72 # When did this become an error?
73 .../Porting/bisect.pl -e 'my $a := 2;'
71d80638 74 # When did this stop being an error?
77ae6092
NC
75 .../Porting/bisect.pl --expect-fail -e '1 // 2'
76 # When did this stop matching?
77 .../Porting/bisect.pl --match '\b(?:PL_)hash_seed_set\b'
78 # When did this start matching?
79 .../Porting/bisect.pl --expect-fail --match '\buseithreads\b'
80 # When did this test program stop working?
81 .../Porting/bisect.pl --target=perl -- ./perl -Ilib test_prog.pl
82 # When did this first become valid syntax?
83 .../Porting/bisect.pl --target=miniperl --end=v5.10.0 \
84 --expect-fail -e 'my $a := 2;'
85 # What was the last revision to build with these options?
86 .../Porting/bisect.pl --test-build -Dd_dosuid
87
88=head1 DESCRIPTION
89
90Together C<bisect.pl> and C<bisect-runner.pl> attempt to automate the use
91of C<git bisect> as much as possible. With one command (and no other files)
92it's easy to find out
93
94=over 4
95
96=item *
97
98Which commit caused this example code to break?
99
100=item *
101
102Which commit caused this example code to start working?
103
104=item *
105
106Which commit added the first to match this regex?
107
108=item *
109
110Which commit removed the last to match this regex?
111
112=back
113
114usually without needing to know which versions of perl to use as start and
115end revisions.
116
117By default C<bisect.pl> will process all options, then use the rest of the
118command line as arguments to list C<system> to run a test case. By default,
119the test case should pass (exit with 0) on earlier perls, and fail (exit
120non-zero) on I<blead>. C<bisect.pl> will use C<bisect-runner.pl> to find the
121earliest stable perl version on which the test case passes, check that it
122fails on blead, and then use C<bisect-runner.pl> with C<git bisect run> to
123find the commit which caused the failure.
124
125Because the test case is the complete argument to C<system>, it is easy to
126run something other than the F<perl> built, if necessary. If you need to run
127the perl built, you'll probably need to invoke it as C<./perl -Ilib ...>
128
129=head1 OPTIONS
130
131=over 4
132
133=item *
134
135--start I<commit-ish>
136
137Earliest revision to test, as a I<commit-ish> (a tag, commit or anything
71d80638 138else C<git> understands as a revision). If not specified, C<bisect.pl> will
77ae6092
NC
139search stable perl releases from 5.002 to 5.14.0 until it finds one where
140the test case passes.
141
142=item *
143
144--end I<commit-ish>
145
146Most recent revision to test, as a I<commit-ish>. If not specified, defaults
b4f0ec5f 147to I<blead>.
77ae6092
NC
148
149=item *
150
151--target I<target>
152
153F<Makefile> target (or equivalent) needed, to run the test case. If specified,
154this should be one of
155
156=over 4
157
158=item *
159
160I<config.sh>
161
162Just run C<Configure>
163
164=item *
165
166I<config.h>
167
168Run the various F<*.SH> files to generate F<Makefile>, F<config.h>, I<etc>.
169
170=item *
171
172I<miniperl>
173
174Build F<miniperl>.
175
176=item *
177
178I<lib/Config.pm>
179
180Use F<miniperl> to build F<lib/Config.pm>
181
182=item *
183
2526f4b8
NC
184I<Fcntl>
185
186Build F<lib/auto/Fcntl/Fnctl.so> (strictly, C<.$Config{so}>). As L<Fcntl>
187is simple XS module present since 5.000, this provides a fast test of
b4f0ec5f 188whether XS modules can be built. Note, XS modules are built by F<miniperl>,
2526f4b8
NC
189hence this target will not build F<perl>.
190
191=item *
192
77ae6092
NC
193I<perl>
194
195Build F<perl>. This also builds pure-Perl modules in F<cpan>, F<dist> and
2526f4b8
NC
196F<ext>. XS modules (such as L<Fcntl>) are not built.
197
198=item *
199
77ae6092
NC
200I<test_prep>
201
202Build everything needed to run the tests. This is the default if we're
203running test code, but is time consuming, as it means building all
b4f0ec5f 204XS modules. For older F<Makefile>s, the previous name of C<test-prep>
77ae6092
NC
205is automatically substituted. For very old F<Makefile>s, C<make test> is
206run, as there is no target provided to just get things ready, and for 5.004
207and earlier the tests run very quickly.
208
209=back
210
211=item *
212
213--one-liner 'code to run'
214
215=item *
216
217-e 'code to run'
218
219Example code to run, just like you'd use with C<perl -e>.
220
221This prepends C<./perl -Ilib -e 'code to run'> to the test case given,
b4f0ec5f 222or C<./miniperl> if I<target> is C<miniperl>.
77ae6092
NC
223
224(Usually you'll use C<-e> instead of providing a test case in the
225non-option arguments to C<bisect.pl>)
226
227C<-E> intentionally isn't supported, as it's an error in 5.8.0 and earlier,
228which interferes with detecting errors in the example code itself.
229
230=item *
231
232--expect-fail
233
234The test case should fail for the I<start> revision, and pass for the I<end>
235revision. The bisect run will find the first commit where it passes.
236
237=item *
238
239-Dusethreads
240
241=item *
242
243-Uusedevel
244
245=item *
246
247-Accflags=-DNO_MATHOMS
248
249Arguments to pass to F<Configure>. Repeated C<-A> arguments are passed
250through as is. C<-D> and C<-U> are processed in order, and override
251previous settings for the same parameter.
252
253=item *
254
b4f0ec5f 255--jobs I<jobs>
77ae6092
NC
256
257=item *
258
b4f0ec5f 259-j I<jobs>
77ae6092 260
e4516dd0 261Number of C<make> jobs to run in parallel. If F</proc/cpuinfo> exists and can
b4f0ec5f 262be parsed, or F</sbin/sysctl> exists and reports C<hw.ncpu>, defaults to
d64af352 2631 + I<number of CPUs>. Otherwise defaults to 2.
77ae6092
NC
264
265=item *
266
b4f0ec5f 267--match pattern
77ae6092
NC
268
269Instead of running a test program to determine I<pass> or I<fail>, pass
270if the given regex matches, and hence search for the commit that removes
271the last matching file.
272
273If no I<target> is specified, the match is against all files in the
274repository (which is fast). If a I<target> is specified, that target is
275built, and the match is against only the built files. C<--expect-fail> can
276be used with C<--match> to search for a commit that adds files that match.
277
278=item *
279
280--test-build
281
282Test that the build completes, without running any test case.
283
284By default, if the build for the desired I<target> fails to complete,
285F<bisect-runner.pl> reports a I<skip> back to C<git bisect>, the assumption
286being that one wants to find a commit which changed state "builds && passes"
287to "builds && fails". If instead one is interested in which commit broke the
288build (possibly for particular F<Configure> options), use I<--test-build>
289to treat a build failure as a failure, not a "skip".
290
b4f0ec5f
NC
291Often this option isn't as useful as it first seems, because I<any> build
292failure will be reported to C<git bisect> as a failure, not just the failure
293that you're interested in. Generally, to debug a particular problem, it's
294more useful to use a I<target> that builds properly at the point of interest,
295and then a test case that runs C<make>. For example:
296
297 .../Porting/bisect.pl --start=perl-5.000 --end=perl-5.002 \
298 --expect-fail --force-manifest --target=miniperl make perl
299
300will find the first revision capable of building C<DynaLoader> and then
301C<perl>, without becoming confused by revisions where C<miniperl> won't
302even link.
303
77ae6092
NC
304=item *
305
b4f0ec5f
NC
306--force-manifest
307
77ae6092
NC
308By default, a build will "skip" if any files listed in F<MANIFEST> are not
309present. Usually this is useful, as it avoids false-failures. However, there
310are some long ranges of commits where listed files are missing, which can
311cause a bisect to abort because all that remain are skipped revisions.
312
313In these cases, particularly if the test case uses F<miniperl> and no modules,
314it may be more useful to force the build to continue, even if files
315F<MANIFEST> are missing.
316
317=item *
318
319--expect-pass [0|1]
320
321C<--expect-pass=0> is equivalent to C<--expect-fail>. I<1> is the default.
322
323=item *
324
325--no-clean
326
327Tell F<bisect-runner.pl> not to clean up after the build. This allows one
328to use F<bisect-runner.pl> to build the current particular perl revision for
329interactive testing, or for debugging F<bisect-runner.pl>.
330
331Passing this to F<bisect.pl> will likely cause the bisect to fail badly.
332
333=item *
334
335--check-args
336
337Validate the options and arguments, and exit silently if they are valid.
338
339=item *
340
341--usage
342
343=item *
344
345--help
346
347=item *
348
349-?
350
351Display the usage information and exit.
352
353=back
354
355=cut
356
0afef97d 357die "$0: Can't build $target" if defined $target && !grep {@targets} $target;
6a8dbfd7
NC
358
359$j = "-j$j" if $j =~ /\A\d+\z/;
360
0142f0ce
NC
361# Sadly, however hard we try, I don't think that it will be possible to build
362# modules in ext/ on x86_64 Linux before commit e1666bf5602ae794 on 1999/12/29,
363# which updated to MakeMaker 3.7, which changed from using a hard coded ld
364# in the Makefile to $(LD). On x86_64 Linux the "linker" is gcc.
365
6a8dbfd7
NC
366sub extract_from_file {
367 my ($file, $rx, $default) = @_;
368 open my $fh, '<', $file or die "Can't open $file: $!";
369 while (<$fh>) {
370 my @got = $_ =~ $rx;
371 return wantarray ? @got : $got[0]
372 if @got;
373 }
374 return $default if defined $default;
375 return;
376}
377
ab4a15f9 378sub clean {
f4800c99 379 if ($options{clean}) {
ab4a15f9
NC
380 # Needed, because files that are build products in this checked out
381 # version might be in git in the next desired version.
382 system 'git clean -dxf';
383 # Needed, because at some revisions the build alters checked out files.
384 # (eg pod/perlapi.pod). Also undoes any changes to makedepend.SH
385 system 'git reset --hard HEAD';
386 }
387}
388
389sub skip {
390 my $reason = shift;
391 clean();
392 warn "skipping - $reason";
393 exit 125;
394}
395
f1050811
NC
396sub report_and_exit {
397 my ($ret, $pass, $fail, $desc) = @_;
398
399 clean();
400
f4800c99 401 my $got = ($options{'expect-pass'} ? !$ret : $ret) ? 'good' : 'bad';
f1050811
NC
402 if ($ret) {
403 print "$got - $fail $desc\n";
404 } else {
405 print "$got - $pass $desc\n";
406 }
407
408 exit($got eq 'bad');
409}
410
0afef97d
NC
411sub match_and_exit {
412 my $target = shift;
413 my $matches = 0;
414 my $re = qr/$match/;
415 my @files;
416
417 {
418 local $/ = "\0";
419 @files = defined $target ? `git ls-files -o -z`: `git ls-files -z`;
420 chomp @files;
421 }
422
423 foreach my $file (@files) {
424 open my $fh, '<', $file or die "Can't open $file: $!";
425 while (<$fh>) {
426 if ($_ =~ $re) {
427 ++$matches;
428 if (tr/\t\r\n -~\200-\377//c) {
429 print "Binary file $file matches\n";
430 } else {
431 $_ .= "\n" unless /\n\z/;
432 print "$file: $_";
433 }
434 }
435 }
436 close $fh or die "Can't close $file: $!";
437 }
438 report_and_exit(!$matches,
439 $matches == 1 ? '1 match for' : "$matches matches for",
440 'no matches for', $match);
441}
442
0142f0ce
NC
443sub apply_patch {
444 my $patch = shift;
445
f1193e4b 446 my ($file) = $patch =~ qr!^diff.*a/(\S+) b/\1!;
eb315236 447 open my $fh, '|-', 'patch', '-p1' or die "Can't run patch: $!";
0142f0ce 448 print $fh $patch;
f1193e4b 449 close $fh or die "Can't patch $file: $?, $!";
0142f0ce
NC
450}
451
6a8dbfd7
NC
452# Not going to assume that system perl is yet new enough to have autodie
453system 'git clean -dxf' and die;
454
0afef97d
NC
455if (!defined $target) {
456 match_and_exit() if $match;
457 $target = 'test_prep';
bc96a05a
NC
458}
459
4b081584
NC
460skip('no Configure - is this the //depot/perlext/Compiler branch?')
461 unless -f 'Configure';
462
dbcdc176
NC
463# This changes to PERL_VERSION in 4d8076ea25903dcb in 1999
464my $major
465 = extract_from_file('patchlevel.h',
466 qr/^#define\s+(?:PERL_VERSION|PATCHLEVEL)\s+(\d+)\s/,
467 0);
468
0142f0ce
NC
469if ($major < 1) {
470 if (extract_from_file('Configure',
471 qr/^ \*=\*\) echo "\$1" >> \$optdef;;$/)) {
472 # This is " Spaces now allowed in -D command line options.",
473 # part of commit ecfc54246c2a6f42
474 apply_patch(<<'EOPATCH');
475diff --git a/Configure b/Configure
476index 3d3b38d..78ffe16 100755
477--- a/Configure
478+++ b/Configure
479@@ -652,7 +777,8 @@ while test $# -gt 0; do
480 echo "$me: use '-U symbol=', not '-D symbol='." >&2
481 echo "$me: ignoring -D $1" >&2
482 ;;
483- *=*) echo "$1" >> $optdef;;
484+ *=*) echo "$1" | \
485+ sed -e "s/'/'\"'\"'/g" -e "s/=\(.*\)/='\1'/" >> $optdef;;
486 *) echo "$1='define'" >> $optdef;;
487 esac
488 shift
489EOPATCH
490 }
491 if (extract_from_file('Configure', qr/^if \$contains 'd_namlen' \$xinc\b/)) {
492 # Configure's original simple "grep" for d_namlen falls foul of the
493 # approach taken by the glibc headers:
494 # #ifdef _DIRENT_HAVE_D_NAMLEN
495 # # define _D_EXACT_NAMLEN(d) ((d)->d_namlen)
496 #
497 # where _DIRENT_HAVE_D_NAMLEN is not defined on Linux.
498 # This is also part of commit ecfc54246c2a6f42
499 apply_patch(<<'EOPATCH');
500diff --git a/Configure b/Configure
501index 3d3b38d..78ffe16 100755
502--- a/Configure
503+++ b/Configure
504@@ -3935,7 +4045,8 @@ $rm -f try.c
505
506 : see if the directory entry stores field length
507 echo " "
508-if $contains 'd_namlen' $xinc >/dev/null 2>&1; then
509+$cppstdin $cppflags $cppminus < "$xinc" > try.c
510+if $contains 'd_namlen' try.c >/dev/null 2>&1; then
511 echo "Good, your directory entry keeps length information in d_namlen." >&4
512 val="$define"
513 else
514EOPATCH
515 }
516}
d90ae42b
NC
517
518if ($major < 10 && extract_from_file('Configure', qr/^set malloc\.h i_malloc$/)) {
5541f5e3
NC
519 # This is commit 01d07975f7ef0e7d, trimmed, with $compile inlined as
520 # prior to bd9b35c97ad661cc Configure had the malloc.h test before the
521 # definition of $compile.
d90ae42b
NC
522 apply_patch(<<'EOPATCH');
523diff --git a/Configure b/Configure
524index 3d2e8b9..6ce7766 100755
525--- a/Configure
526+++ b/Configure
527@@ -6743,5 +6743,22 @@ set d_dosuid
528
529 : see if this is a malloc.h system
530-set malloc.h i_malloc
531-eval $inhdr
532+: we want a real compile instead of Inhdr because some systems have a
533+: malloc.h that just gives a compile error saying to use stdlib.h instead
534+echo " "
535+$cat >try.c <<EOCP
536+#include <stdlib.h>
537+#include <malloc.h>
538+int main () { return 0; }
539+EOCP
540+set try
5541f5e3 541+if $cc $optimize $ccflags $ldflags -o try $* try.c $libs > /dev/null 2>&1; then
d90ae42b
NC
542+ echo "<malloc.h> found." >&4
543+ val="$define"
544+else
545+ echo "<malloc.h> NOT found." >&4
546+ val="$undef"
547+fi
548+$rm -f try.c try
549+set i_malloc
550+eval $setvar
551
552EOPATCH
553}
0142f0ce 554
6a8dbfd7
NC
555# There was a bug in makedepend.SH which was fixed in version 96a8704c.
556# Symptom was './makedepend: 1: Syntax error: Unterminated quoted string'
557# Remove this if you're actually bisecting a problem related to makedepend.SH
558system 'git show blead:makedepend.SH > makedepend.SH' and die;
559
d64af352
NC
560if ($^O eq 'freebsd') {
561 # There are rather too many version-specific FreeBSD hints fixes to patch
562 # individually. Also, more than once the FreeBSD hints file has been
563 # written in what turned out to be a rather non-future-proof style,
564 # with case statements treating the most recent version as the exception,
565 # instead of treating previous versions' behaviour explicitly and changing
566 # the default to cater for the current behaviour. (As strangely, future
567 # versions inherit the current behaviour.)
568 system 'git show blead:hints/freebsd.sh > hints/freebsd.sh' and die;
641e2ba6
NC
569
570 if ($major < 2) {
571 # 5.002 Configure and later have code to
572 #
573 # : Try to guess additional flags to pick up local libraries.
574 #
575 # which will automatically add --L/usr/local/lib because libpth
576 # contains /usr/local/lib
577 #
578 # Without it, if Configure finds libraries in /usr/local/lib (eg
579 # libgdbm.so) and adds them to the compiler commandline (as -lgdbm),
580 # then the link will fail. We can't fix this up in config.sh because
581 # the link will *also* fail in the test compiles that Configure does
582 # (eg $inlibc) which makes Configure get all sorts of things
583 # wrong. :-( So bodge it here.
584 #
585 # Possibly other platforms will need something similar. (if they
586 # have "wanted" libraries in /usr/local/lib, but the compiler
587 # doesn't default to putting that directory in its link path)
588 apply_patch(<<'EOPATCH');
589--- perl2/hints/freebsd.sh.orig 2011-10-05 16:44:55.000000000 +0200
590+++ perl2/hints/freebsd.sh 2011-10-05 16:45:52.000000000 +0200
591@@ -125,7 +125,7 @@
592 else
593 libpth="/usr/lib /usr/local/lib"
594 glibpth="/usr/lib /usr/local/lib"
595- ldflags="-Wl,-E "
596+ ldflags="-Wl,-E -L/usr/local/lib "
597 lddlflags="-shared "
598 fi
599 cccdlflags='-DPIC -fPIC'
600@@ -133,7 +133,7 @@
601 *)
602 libpth="/usr/lib /usr/local/lib"
603 glibpth="/usr/lib /usr/local/lib"
604- ldflags="-Wl,-E "
605+ ldflags="-Wl,-E -L/usr/local/lib "
606 lddlflags="-shared "
607 cccdlflags='-DPIC -fPIC'
608 ;;
609
610EOPATCH
611 }
d64af352
NC
612}
613
6a8dbfd7
NC
614# if Encode is not needed for the test, you can speed up the bisect by
615# excluding it from the runs with -Dnoextensions=Encode
616# ccache is an easy win. Remove it if it causes problems.
6a8dbfd7
NC
617# Commit 1cfa4ec74d4933da adds ignore_versioned_solibs to Configure, and sets it
618# to true in hints/linux.sh
619# On dromedary, from that point on, Configure (by default) fails to find any
620# libraries, because it scans /usr/local/lib /lib /usr/lib, which only contain
621# versioned libraries. Without -lm, the build fails.
622# Telling /usr/local/lib64 /lib64 /usr/lib64 works from that commit onwards,
623# until commit faae14e6e968e1c0 adds it to the hints.
624# However, prior to 1cfa4ec74d4933da telling Configure the truth doesn't work,
625# because it will spot versioned libraries, pass them to the compiler, and then
626# bail out pretty early on. Configure won't let us override libswanted, but it
627# will let us override the entire libs list.
628
629unless (extract_from_file('Configure', 'ignore_versioned_solibs')) {
630 # Before 1cfa4ec74d4933da, so force the libs list.
631
632 my @libs;
633 # This is the current libswanted list from Configure, less the libs removed
634 # by current hints/linux.sh
635 foreach my $lib (qw(sfio socket inet nsl nm ndbm gdbm dbm db malloc dl dld
636 ld sun m crypt sec util c cposix posix ucb BSD)) {
637 foreach my $dir (@paths) {
638 next unless -f "$dir/lib$lib.so";
639 push @libs, "-l$lib";
640 last;
641 }
642 }
390a69a9 643 $defines{libs} = \@libs unless exists $defines{libs};
6a8dbfd7
NC
644}
645
4b081584
NC
646# This seems to be necessary to avoid makedepend becoming confused, and hanging
647# on stdin. Seems that the code after make shlist || ...here... is never run.
390a69a9
NC
648$defines{trnl} = q{'\n'}
649 if $major < 4 && !exists $defines{trnl};
4b081584 650
390a69a9
NC
651$defines{usenm} = undef
652 if $major < 2 && !exists $defines{usenm};
0142f0ce 653
67382a3b
NC
654my (@missing, @created_dirs);
655
f4800c99 656if ($options{'force-manifest'}) {
67382a3b
NC
657 open my $fh, '<', 'MANIFEST'
658 or die "Could not open MANIFEST: $!";
659 while (<$fh>) {
660 next unless /^(\S+)/;
661 push @missing, $1
662 unless -f $1;
663 }
664 close $fh or die "Can't close MANIFEST: $!";
665
666 foreach my $pathname (@missing) {
667 my @parts = split '/', $pathname;
668 my $leaf = pop @parts;
669 my $path = '.';
670 while (@parts) {
671 $path .= '/' . shift @parts;
672 next if -d $path;
673 mkdir $path, 0700 or die "Can't create $path: $!";
674 unshift @created_dirs, $path;
675 }
676 open $fh, '>', $pathname or die "Can't open $pathname: $!";
677 close $fh or die "Can't close $pathname: $!";
678 chmod 0, $pathname or die "Can't chmod 0 $pathname: $!";
679 }
680}
681
dd4e46d7 682my @ARGS = $target eq 'config.sh' ? '-dEs' : '-des';
390a69a9
NC
683foreach my $key (sort keys %defines) {
684 my $val = $defines{$key};
685 if (ref $val) {
686 push @ARGS, "-D$key=@$val";
687 } elsif (!defined $val) {
688 push @ARGS, "-U$key";
689 } elsif (!length $val) {
690 push @ARGS, "-D$key";
691 } else {
692 $val = "" if $val eq "\0";
693 push @ARGS, "-D$key=$val";
694 }
695}
696push @ARGS, map {"-A$_"} @{$options{A}};
697
6a8dbfd7
NC
698# </dev/null because it seems that some earlier versions of Configure can
699# call commands in a way that now has them reading from stdin (and hanging)
700my $pid = fork;
701die "Can't fork: $!" unless defined $pid;
702if (!$pid) {
dbcdc176
NC
703 # Before dfe9444ca7881e71, Configure would refuse to run if stdin was not a
704 # tty. With that commit, the tty requirement was dropped for -de and -dE
8754c3bb 705 if($major > 4) {
67382a3b 706 open STDIN, '<', '/dev/null';
f4800c99 707 } elsif (!$options{'force-manifest'}) {
8754c3bb
NC
708 # If a file in MANIFEST is missing, Configure asks if you want to
709 # continue (the default being 'n'). With stdin closed or /dev/null,
710 # it exit immediately and the check for config.sh below will skip.
711 # To avoid a hang, we need to check MANIFEST for ourselves, and skip
712 # if anything is missing.
713 open my $fh, '<', 'MANIFEST';
714 skip("Could not open MANIFEST: $!")
715 unless $fh;
716 while (<$fh>) {
717 next unless /^(\S+)/;
718 skip("$1 from MANIFEST doesn't exist")
719 unless -f $1;
720 }
721 close $fh or die "Can't close MANIFEST: $!";
722 }
6a8dbfd7
NC
723 exec './Configure', @ARGS;
724 die "Failed to start Configure: $!";
725}
726waitpid $pid, 0
727 or die "wait for Configure, pid $pid failed: $!";
728
0afef97d
NC
729if ($target =~ /config\.s?h/) {
730 match_and_exit($target) if $match && -f $target;
dd4e46d7
NC
731 report_and_exit(!-f $target, 'could build', 'could not build', $target);
732} elsif (!-f 'config.sh') {
733 # Skip if something went wrong with Configure
734
735 skip('could not build config.sh');
736}
6a8dbfd7 737
67382a3b
NC
738# This is probably way too paranoid:
739if (@missing) {
740 my @errors;
eb4906f4 741 require Fcntl;
67382a3b
NC
742 foreach my $file (@missing) {
743 my (undef, undef, $mode, undef, undef, undef, undef, $size)
744 = stat $file;
745 if (!defined $mode) {
746 push @errors, "Added file $file has been deleted by Configure";
747 next;
748 }
eb4906f4 749 if (Fcntl::S_IMODE($mode) != 0) {
67382a3b
NC
750 push @errors,
751 sprintf 'Added file %s had mode changed by Configure to %03o',
752 $file, $mode;
753 }
754 if ($size != 0) {
755 push @errors,
756 "Added file $file had sized changed by Configure to $size";
757 }
758 unlink $file or die "Can't unlink $file: $!";
759 }
760 foreach my $dir (@created_dirs) {
761 rmdir $dir or die "Can't rmdir $dir: $!";
762 }
6c0925a0
NC
763 skip("@errors")
764 if @errors;
67382a3b
NC
765}
766
6a8dbfd7
NC
767# Correct makefile for newer GNU gcc
768# Only really needed if you comment out the use of blead's makedepend.SH
769{
770 local $^I = "";
771 local @ARGV = qw(makefile x2p/makefile);
772 while (<>) {
773 print unless /<(?:built-in|command|stdin)/;
774 }
775}
6a8dbfd7 776
0142f0ce
NC
777if ($major == 2 && extract_from_file('perl.c', qr/^ fclose\(e_fp\);$/)) {
778 # need to patch perl.c to avoid calling fclose() twice on e_fp when using -e
779 # This diff is part of commit ab821d7fdc14a438. The second close was
780 # introduced with perl-5.002, commit a5f75d667838e8e7
781 # Might want a6c477ed8d4864e6 too, for the corresponding change to pp_ctl.c
782 # (likely without this, eval will have "fun")
783 apply_patch(<<'EOPATCH');
784diff --git a/perl.c b/perl.c
785index 03c4d48..3c814a2 100644
786--- a/perl.c
787+++ b/perl.c
788@@ -252,6 +252,7 @@ setuid perl scripts securely.\n");
789 #ifndef VMS /* VMS doesn't have environ array */
790 origenviron = environ;
791 #endif
792+ e_tmpname = Nullch;
793
794 if (do_undump) {
795
796@@ -405,6 +406,7 @@ setuid perl scripts securely.\n");
797 if (e_fp) {
798 if (Fflush(e_fp) || ferror(e_fp) || fclose(e_fp))
799 croak("Can't write to temp file for -e: %s", Strerror(errno));
800+ e_fp = Nullfp;
801 argc++,argv--;
802 scriptname = e_tmpname;
803 }
804@@ -470,10 +472,10 @@ setuid perl scripts securely.\n");
805 curcop->cop_line = 0;
806 curstash = defstash;
807 preprocess = FALSE;
808- if (e_fp) {
809- fclose(e_fp);
810- e_fp = Nullfp;
811+ if (e_tmpname) {
812 (void)UNLINK(e_tmpname);
813+ Safefree(e_tmpname);
814+ e_tmpname = Nullch;
815 }
816
817 /* now that script is parsed, we can modify record separator */
818@@ -1369,7 +1371,7 @@ SV *sv;
819 scriptname = xfound;
820 }
821
822- origfilename = savepv(e_fp ? "-e" : scriptname);
823+ origfilename = savepv(e_tmpname ? "-e" : scriptname);
824 curcop->cop_filegv = gv_fetchfile(origfilename);
825 if (strEQ(origfilename,"-"))
826 scriptname = "";
827
828EOPATCH
829}
830
9a999a97
NC
831# Parallel build for miniperl is safe
832system "make $j miniperl";
833
2526f4b8
NC
834my $expected = $target =~ /^test/ ? 't/perl'
835 : $target eq 'Fcntl' ? "lib/auto/Fcntl/Fcntl.$Config{so}"
836 : $target;
837my $real_target = $target eq 'Fcntl' ? $expected : $target;
838
9a999a97
NC
839if ($target ne 'miniperl') {
840 # Nearly all parallel build issues fixed by 5.10.0. Untrustworthy before that.
372ba1f9 841 $j = '' if $major < 10;
9a999a97 842
2526f4b8 843 if ($real_target eq 'test_prep') {
9a999a97
NC
844 if ($major < 8) {
845 # test-prep was added in 5.004_01, 3e3baf6d63945cb6.
846 # renamed to test_prep in 2001 in 5fe84fd29acaf55c.
847 # earlier than that, just make test. It will be fast enough.
2526f4b8
NC
848 $real_target = extract_from_file('Makefile.SH',
849 qr/^(test[-_]prep):/,
850 'test');
9a999a97 851 }
6a8dbfd7 852 }
6a8dbfd7 853
eb315236
NC
854 if ($major < 10
855 and -f 'ext/IPC/SysV/SysV.xs',
856 and my ($line) = extract_from_file('ext/IPC/SysV/SysV.xs',
857 qr!^(# *include <asm/page.h>)$!)) {
858 apply_patch(<<"EOPATCH");
859diff --git a/ext/IPC/SysV/SysV.xs b/ext/IPC/SysV/SysV.xs
860index 35a8fde..62a7965 100644
861--- a/ext/IPC/SysV/SysV.xs
862+++ b/ext/IPC/SysV/SysV.xs
863\@\@ -4,7 +4,6 \@\@
864
865 #include <sys/types.h>
866 #ifdef __linux__
867-$line
868 #endif
869 #if defined(HAS_MSG) || defined(HAS_SEM) || defined(HAS_SHM)
870 #ifndef HAS_SEM
871EOPATCH
872 }
2526f4b8 873 system "make $j $real_target";
9a999a97 874}
6a8dbfd7 875
67382a3b
NC
876my $missing_target = $expected =~ /perl$/ ? !-x $expected : !-r $expected;
877
f4800c99 878if ($options{'test-build'}) {
2526f4b8
NC
879 report_and_exit($missing_target, 'could build', 'could not build',
880 $real_target);
67382a3b 881} elsif ($missing_target) {
2526f4b8 882 skip("could not build $real_target");
67382a3b 883}
6a8dbfd7 884
2526f4b8 885match_and_exit($real_target) if $match;
0afef97d
NC
886
887if (defined $options{'one-liner'}) {
2526f4b8 888 my $exe = $target =~ /^(?:perl$|test)/ ? 'perl' : 'miniperl';
0afef97d
NC
889 unshift @ARGV, "./$exe", '-Ilib', '-e', $options{'one-liner'};
890}
891
6a8dbfd7
NC
892# This is what we came here to run:
893my $ret = system @ARGV;
894
f1050811 895report_and_exit($ret, 'zero exit from', 'non-zero exit from', "@ARGV");
9a999a97
NC
896
897# Local variables:
898# cperl-indent-level: 4
899# indent-tabs-mode: nil
900# End:
901#
902# ex: set ts=8 sts=4 sw=4 et: