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