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