4 use Getopt::Long qw(:config bundling no_auto_abbrev);
9 = qw(config.sh config.h miniperl lib/Config.pm Fcntl perl test_prep);
12 if (open my $fh, '<', '/proc/cpuinfo') {
14 ++$cpus if /^processor\s+:\s+\d+$/;
16 } elsif (-x '/sbin/sysctl') {
17 $cpus = 1 + $1 if `/sbin/sysctl hw.ncpu` =~ /^hw\.ncpu: (\d+)$/;
22 jobs => defined $cpus ? $cpus + 1 : 2,
24 clean => 1, # mostly for debugging this
27 my @paths = qw(/usr/local/lib64 /lib64 /usr/lib64);
35 (`uname -sm` eq "Linux x86_64\n" ? (libpth => \@paths) : ()),
38 unless(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',
42 'test-build', 'check-args', 'A=s@', 'usage|help|?',
44 my (undef, $val) = @_;
45 if ($val =~ /\A([^=]+)=(.*)/s) {
46 $defines{$1} = length $2 ? $2 : "\0";
52 $defines{$_[1]} = undef;
55 pod2usage(exitval => 255, verbose => 1);
58 my ($target, $j, $match) = @options{qw(target jobs match)};
60 pod2usage(exitval => 255, verbose => 1) if $options{usage};
61 pod2usage(exitval => 255, verbose => 1)
62 unless @ARGV || $match || $options{'test-build'} || defined $options{'one-liner'};
64 exit 0 if $options{'check-args'};
68 bisect.pl - use git bisect to pinpoint changes
72 # When did this become an error?
73 .../Porting/bisect.pl -e 'my $a := 2;'
74 # When did this stop being an error?
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
90 Together C<bisect.pl> and C<bisect-runner.pl> attempt to automate the use
91 of C<git bisect> as much as possible. With one command (and no other files)
98 Which commit caused this example code to break?
102 Which commit caused this example code to start working?
106 Which commit added the first to match this regex?
110 Which commit removed the last to match this regex?
114 usually without needing to know which versions of perl to use as start and
117 By default C<bisect.pl> will process all options, then use the rest of the
118 command line as arguments to list C<system> to run a test case. By default,
119 the test case should pass (exit with 0) on earlier perls, and fail (exit
120 non-zero) on I<blead>. C<bisect.pl> will use C<bisect-runner.pl> to find the
121 earliest stable perl version on which the test case passes, check that it
122 fails on blead, and then use C<bisect-runner.pl> with C<git bisect run> to
123 find the commit which caused the failure.
125 Because the test case is the complete argument to C<system>, it is easy to
126 run something other than the F<perl> built, if necessary. If you need to run
127 the perl built, you'll probably need to invoke it as C<./perl -Ilib ...>
135 --start I<commit-ish>
137 Earliest revision to test, as a I<commit-ish> (a tag, commit or anything
138 else C<git> understands as a revision). If not specified, C<bisect.pl> will
139 search stable perl releases from 5.002 to 5.14.0 until it finds one where
140 the test case passes.
146 Most recent revision to test, as a I<commit-ish>. If not specified, defaults
153 F<Makefile> target (or equivalent) needed, to run the test case. If specified,
154 this should be one of
162 Just run C<Configure>
168 Run the various F<*.SH> files to generate F<Makefile>, F<config.h>, I<etc>.
180 Use F<miniperl> to build F<lib/Config.pm>
186 Build F<lib/auto/Fcntl/Fnctl.so> (strictly, C<.$Config{so}>). As L<Fcntl>
187 is simple XS module present since 5.000, this provides a fast test of
188 whether XS modules can be build. Note, XS modules are built by F<miniperl>,
189 hence this target will not build F<perl>.
195 Build F<perl>. This also builds pure-Perl modules in F<cpan>, F<dist> and
196 F<ext>. XS modules (such as L<Fcntl>) are not built.
206 Build everything needed to run the tests. This is the default if we're
207 running test code, but is time consuming, as it means building all
208 C<XS> modules. For older F<Makefile>s, the previous name of C<test-prep>
209 is automatically substituted. For very old F<Makefile>s, C<make test> is
210 run, as there is no target provided to just get things ready, and for 5.004
211 and earlier the tests run very quickly.
217 --one-liner 'code to run'
223 Example code to run, just like you'd use with C<perl -e>.
225 This prepends C<./perl -Ilib -e 'code to run'> to the test case given,
226 or C<./miniperl> if I<target> is C<miniperl>
228 (Usually you'll use C<-e> instead of providing a test case in the
229 non-option arguments to C<bisect.pl>)
231 C<-E> intentionally isn't supported, as it's an error in 5.8.0 and earlier,
232 which interferes with detecting errors in the example code itself.
238 The test case should fail for the I<start> revision, and pass for the I<end>
239 revision. The bisect run will find the first commit where it passes.
251 -Accflags=-DNO_MATHOMS
253 Arguments to pass to F<Configure>. Repeated C<-A> arguments are passed
254 through as is. C<-D> and C<-U> are processed in order, and override
255 previous settings for the same parameter.
265 Number of C<make> jobs to run in parallel. If F</proc/cpuinfo> exists and can
266 be parsed, or F</sbin/sysctl> exists and reports <hw.ncpu>, defaults to
267 1 + I<number of CPUs>. Otherwise defaults to 2.
273 Instead of running a test program to determine I<pass> or I<fail>, pass
274 if the given regex matches, and hence search for the commit that removes
275 the last matching file.
277 If no I<target> is specified, the match is against all files in the
278 repository (which is fast). If a I<target> is specified, that target is
279 built, and the match is against only the built files. C<--expect-fail> can
280 be used with C<--match> to search for a commit that adds files that match.
286 Test that the build completes, without running any test case.
288 By default, if the build for the desired I<target> fails to complete,
289 F<bisect-runner.pl> reports a I<skip> back to C<git bisect>, the assumption
290 being that one wants to find a commit which changed state "builds && passes"
291 to "builds && fails". If instead one is interested in which commit broke the
292 build (possibly for particular F<Configure> options), use I<--test-build>
293 to treat a build failure as a failure, not a "skip".
297 By default, a build will "skip" if any files listed in F<MANIFEST> are not
298 present. Usually this is useful, as it avoids false-failures. However, there
299 are some long ranges of commits where listed files are missing, which can
300 cause a bisect to abort because all that remain are skipped revisions.
302 In these cases, particularly if the test case uses F<miniperl> and no modules,
303 it may be more useful to force the build to continue, even if files
304 F<MANIFEST> are missing.
310 C<--expect-pass=0> is equivalent to C<--expect-fail>. I<1> is the default.
316 Tell F<bisect-runner.pl> not to clean up after the build. This allows one
317 to use F<bisect-runner.pl> to build the current particular perl revision for
318 interactive testing, or for debugging F<bisect-runner.pl>.
320 Passing this to F<bisect.pl> will likely cause the bisect to fail badly.
326 Validate the options and arguments, and exit silently if they are valid.
340 Display the usage information and exit.
346 die "$0: Can't build $target" if defined $target && !grep {@targets} $target;
348 $j = "-j$j" if $j =~ /\A\d+\z/;
350 # Sadly, however hard we try, I don't think that it will be possible to build
351 # modules in ext/ on x86_64 Linux before commit e1666bf5602ae794 on 1999/12/29,
352 # which updated to MakeMaker 3.7, which changed from using a hard coded ld
353 # in the Makefile to $(LD). On x86_64 Linux the "linker" is gcc.
355 sub extract_from_file {
356 my ($file, $rx, $default) = @_;
357 open my $fh, '<', $file or die "Can't open $file: $!";
360 return wantarray ? @got : $got[0]
363 return $default if defined $default;
368 if ($options{clean}) {
369 # Needed, because files that are build products in this checked out
370 # version might be in git in the next desired version.
371 system 'git clean -dxf';
372 # Needed, because at some revisions the build alters checked out files.
373 # (eg pod/perlapi.pod). Also undoes any changes to makedepend.SH
374 system 'git reset --hard HEAD';
381 warn "skipping - $reason";
385 sub report_and_exit {
386 my ($ret, $pass, $fail, $desc) = @_;
390 my $got = ($options{'expect-pass'} ? !$ret : $ret) ? 'good' : 'bad';
392 print "$got - $fail $desc\n";
394 print "$got - $pass $desc\n";
408 @files = defined $target ? `git ls-files -o -z`: `git ls-files -z`;
412 foreach my $file (@files) {
413 open my $fh, '<', $file or die "Can't open $file: $!";
417 if (tr/\t\r\n -~\200-\377//c) {
418 print "Binary file $file matches\n";
420 $_ .= "\n" unless /\n\z/;
425 close $fh or die "Can't close $file: $!";
427 report_and_exit(!$matches,
428 $matches == 1 ? '1 match for' : "$matches matches for",
429 'no matches for', $match);
435 my ($file) = $patch =~ qr!^diff.*a/(\S+) b/\1!;
436 open my $fh, '|-', 'patch', '-p1' or die "Can't run patch: $!";
438 close $fh or die "Can't patch $file: $?, $!";
441 # Not going to assume that system perl is yet new enough to have autodie
442 system 'git clean -dxf' and die;
444 if (!defined $target) {
445 match_and_exit() if $match;
446 $target = 'test_prep';
449 skip('no Configure - is this the //depot/perlext/Compiler branch?')
450 unless -f 'Configure';
452 # This changes to PERL_VERSION in 4d8076ea25903dcb in 1999
454 = extract_from_file('patchlevel.h',
455 qr/^#define\s+(?:PERL_VERSION|PATCHLEVEL)\s+(\d+)\s/,
459 if (extract_from_file('Configure',
460 qr/^ \*=\*\) echo "\$1" >> \$optdef;;$/)) {
461 # This is " Spaces now allowed in -D command line options.",
462 # part of commit ecfc54246c2a6f42
463 apply_patch(<<'EOPATCH');
464 diff --git a/Configure b/Configure
465 index 3d3b38d..78ffe16 100755
468 @@ -652,7 +777,8 @@ while test $# -gt 0; do
469 echo "$me: use '-U symbol=', not '-D symbol='." >&2
470 echo "$me: ignoring -D $1" >&2
472 - *=*) echo "$1" >> $optdef;;
474 + sed -e "s/'/'\"'\"'/g" -e "s/=\(.*\)/='\1'/" >> $optdef;;
475 *) echo "$1='define'" >> $optdef;;
480 if (extract_from_file('Configure', qr/^if \$contains 'd_namlen' \$xinc\b/)) {
481 # Configure's original simple "grep" for d_namlen falls foul of the
482 # approach taken by the glibc headers:
483 # #ifdef _DIRENT_HAVE_D_NAMLEN
484 # # define _D_EXACT_NAMLEN(d) ((d)->d_namlen)
486 # where _DIRENT_HAVE_D_NAMLEN is not defined on Linux.
487 # This is also part of commit ecfc54246c2a6f42
488 apply_patch(<<'EOPATCH');
489 diff --git a/Configure b/Configure
490 index 3d3b38d..78ffe16 100755
493 @@ -3935,7 +4045,8 @@ $rm -f try.c
495 : see if the directory entry stores field length
497 -if $contains 'd_namlen' $xinc >/dev/null 2>&1; then
498 +$cppstdin $cppflags $cppminus < "$xinc" > try.c
499 +if $contains 'd_namlen' try.c >/dev/null 2>&1; then
500 echo "Good, your directory entry keeps length information in d_namlen." >&4
507 if ($major < 10 && extract_from_file('Configure', qr/^set malloc\.h i_malloc$/)) {
508 # This is commit 01d07975f7ef0e7d, trimmed, with $compile inlined as
509 # prior to bd9b35c97ad661cc Configure had the malloc.h test before the
510 # definition of $compile.
511 apply_patch(<<'EOPATCH');
512 diff --git a/Configure b/Configure
513 index 3d2e8b9..6ce7766 100755
516 @@ -6743,5 +6743,22 @@ set d_dosuid
518 : see if this is a malloc.h system
519 -set malloc.h i_malloc
521 +: we want a real compile instead of Inhdr because some systems have a
522 +: malloc.h that just gives a compile error saying to use stdlib.h instead
527 +int main () { return 0; }
530 +if $cc $optimize $ccflags $ldflags -o try $* try.c $libs > /dev/null 2>&1; then
531 + echo "<malloc.h> found." >&4
534 + echo "<malloc.h> NOT found." >&4
544 # There was a bug in makedepend.SH which was fixed in version 96a8704c.
545 # Symptom was './makedepend: 1: Syntax error: Unterminated quoted string'
546 # Remove this if you're actually bisecting a problem related to makedepend.SH
547 system 'git show blead:makedepend.SH > makedepend.SH' and die;
549 if ($^O eq 'freebsd') {
550 # There are rather too many version-specific FreeBSD hints fixes to patch
551 # individually. Also, more than once the FreeBSD hints file has been
552 # written in what turned out to be a rather non-future-proof style,
553 # with case statements treating the most recent version as the exception,
554 # instead of treating previous versions' behaviour explicitly and changing
555 # the default to cater for the current behaviour. (As strangely, future
556 # versions inherit the current behaviour.)
557 system 'git show blead:hints/freebsd.sh > hints/freebsd.sh' and die;
560 # 5.002 Configure and later have code to
562 # : Try to guess additional flags to pick up local libraries.
564 # which will automatically add --L/usr/local/lib because libpth
565 # contains /usr/local/lib
567 # Without it, if Configure finds libraries in /usr/local/lib (eg
568 # libgdbm.so) and adds them to the compiler commandline (as -lgdbm),
569 # then the link will fail. We can't fix this up in config.sh because
570 # the link will *also* fail in the test compiles that Configure does
571 # (eg $inlibc) which makes Configure get all sorts of things
572 # wrong. :-( So bodge it here.
574 # Possibly other platforms will need something similar. (if they
575 # have "wanted" libraries in /usr/local/lib, but the compiler
576 # doesn't default to putting that directory in its link path)
577 apply_patch(<<'EOPATCH');
578 --- perl2/hints/freebsd.sh.orig 2011-10-05 16:44:55.000000000 +0200
579 +++ perl2/hints/freebsd.sh 2011-10-05 16:45:52.000000000 +0200
582 libpth="/usr/lib /usr/local/lib"
583 glibpth="/usr/lib /usr/local/lib"
585 + ldflags="-Wl,-E -L/usr/local/lib "
588 cccdlflags='-DPIC -fPIC'
591 libpth="/usr/lib /usr/local/lib"
592 glibpth="/usr/lib /usr/local/lib"
594 + ldflags="-Wl,-E -L/usr/local/lib "
596 cccdlflags='-DPIC -fPIC'
603 # if Encode is not needed for the test, you can speed up the bisect by
604 # excluding it from the runs with -Dnoextensions=Encode
605 # ccache is an easy win. Remove it if it causes problems.
606 # Commit 1cfa4ec74d4933da adds ignore_versioned_solibs to Configure, and sets it
607 # to true in hints/linux.sh
608 # On dromedary, from that point on, Configure (by default) fails to find any
609 # libraries, because it scans /usr/local/lib /lib /usr/lib, which only contain
610 # versioned libraries. Without -lm, the build fails.
611 # Telling /usr/local/lib64 /lib64 /usr/lib64 works from that commit onwards,
612 # until commit faae14e6e968e1c0 adds it to the hints.
613 # However, prior to 1cfa4ec74d4933da telling Configure the truth doesn't work,
614 # because it will spot versioned libraries, pass them to the compiler, and then
615 # bail out pretty early on. Configure won't let us override libswanted, but it
616 # will let us override the entire libs list.
618 unless (extract_from_file('Configure', 'ignore_versioned_solibs')) {
619 # Before 1cfa4ec74d4933da, so force the libs list.
622 # This is the current libswanted list from Configure, less the libs removed
623 # by current hints/linux.sh
624 foreach my $lib (qw(sfio socket inet nsl nm ndbm gdbm dbm db malloc dl dld
625 ld sun m crypt sec util c cposix posix ucb BSD)) {
626 foreach my $dir (@paths) {
627 next unless -f "$dir/lib$lib.so";
628 push @libs, "-l$lib";
632 $defines{libs} = \@libs unless exists $defines{libs};
635 # This seems to be necessary to avoid makedepend becoming confused, and hanging
636 # on stdin. Seems that the code after make shlist || ...here... is never run.
637 $defines{trnl} = q{'\n'}
638 if $major < 4 && !exists $defines{trnl};
640 $defines{usenm} = undef
641 if $major < 2 && !exists $defines{usenm};
643 my (@missing, @created_dirs);
645 if ($options{'force-manifest'}) {
646 open my $fh, '<', 'MANIFEST'
647 or die "Could not open MANIFEST: $!";
649 next unless /^(\S+)/;
653 close $fh or die "Can't close MANIFEST: $!";
655 foreach my $pathname (@missing) {
656 my @parts = split '/', $pathname;
657 my $leaf = pop @parts;
660 $path .= '/' . shift @parts;
662 mkdir $path, 0700 or die "Can't create $path: $!";
663 unshift @created_dirs, $path;
665 open $fh, '>', $pathname or die "Can't open $pathname: $!";
666 close $fh or die "Can't close $pathname: $!";
667 chmod 0, $pathname or die "Can't chmod 0 $pathname: $!";
671 my @ARGS = $target eq 'config.sh' ? '-dEs' : '-des';
672 foreach my $key (sort keys %defines) {
673 my $val = $defines{$key};
675 push @ARGS, "-D$key=@$val";
676 } elsif (!defined $val) {
677 push @ARGS, "-U$key";
678 } elsif (!length $val) {
679 push @ARGS, "-D$key";
681 $val = "" if $val eq "\0";
682 push @ARGS, "-D$key=$val";
685 push @ARGS, map {"-A$_"} @{$options{A}};
687 # </dev/null because it seems that some earlier versions of Configure can
688 # call commands in a way that now has them reading from stdin (and hanging)
690 die "Can't fork: $!" unless defined $pid;
692 # Before dfe9444ca7881e71, Configure would refuse to run if stdin was not a
693 # tty. With that commit, the tty requirement was dropped for -de and -dE
695 open STDIN, '<', '/dev/null';
696 } elsif (!$options{'force-manifest'}) {
697 # If a file in MANIFEST is missing, Configure asks if you want to
698 # continue (the default being 'n'). With stdin closed or /dev/null,
699 # it exit immediately and the check for config.sh below will skip.
700 # To avoid a hang, we need to check MANIFEST for ourselves, and skip
701 # if anything is missing.
702 open my $fh, '<', 'MANIFEST';
703 skip("Could not open MANIFEST: $!")
706 next unless /^(\S+)/;
707 skip("$1 from MANIFEST doesn't exist")
710 close $fh or die "Can't close MANIFEST: $!";
712 exec './Configure', @ARGS;
713 die "Failed to start Configure: $!";
716 or die "wait for Configure, pid $pid failed: $!";
718 if ($target =~ /config\.s?h/) {
719 match_and_exit($target) if $match && -f $target;
720 report_and_exit(!-f $target, 'could build', 'could not build', $target);
721 } elsif (!-f 'config.sh') {
722 # Skip if something went wrong with Configure
724 skip('could not build config.sh');
727 # This is probably way too paranoid:
731 foreach my $file (@missing) {
732 my (undef, undef, $mode, undef, undef, undef, undef, $size)
734 if (!defined $mode) {
735 push @errors, "Added file $file has been deleted by Configure";
738 if (Fcntl::S_IMODE($mode) != 0) {
740 sprintf 'Added file %s had mode changed by Configure to %03o',
745 "Added file $file had sized changed by Configure to $size";
747 unlink $file or die "Can't unlink $file: $!";
749 foreach my $dir (@created_dirs) {
750 rmdir $dir or die "Can't rmdir $dir: $!";
756 # Correct makefile for newer GNU gcc
757 # Only really needed if you comment out the use of blead's makedepend.SH
760 local @ARGV = qw(makefile x2p/makefile);
762 print unless /<(?:built-in|command|stdin)/;
766 if ($major == 2 && extract_from_file('perl.c', qr/^ fclose\(e_fp\);$/)) {
767 # need to patch perl.c to avoid calling fclose() twice on e_fp when using -e
768 # This diff is part of commit ab821d7fdc14a438. The second close was
769 # introduced with perl-5.002, commit a5f75d667838e8e7
770 # Might want a6c477ed8d4864e6 too, for the corresponding change to pp_ctl.c
771 # (likely without this, eval will have "fun")
772 apply_patch(<<'EOPATCH');
773 diff --git a/perl.c b/perl.c
774 index 03c4d48..3c814a2 100644
777 @@ -252,6 +252,7 @@ setuid perl scripts securely.\n");
778 #ifndef VMS /* VMS doesn't have environ array */
779 origenviron = environ;
781 + e_tmpname = Nullch;
785 @@ -405,6 +406,7 @@ setuid perl scripts securely.\n");
787 if (Fflush(e_fp) || ferror(e_fp) || fclose(e_fp))
788 croak("Can't write to temp file for -e: %s", Strerror(errno));
791 scriptname = e_tmpname;
793 @@ -470,10 +472,10 @@ setuid perl scripts securely.\n");
794 curcop->cop_line = 0;
801 (void)UNLINK(e_tmpname);
802 + Safefree(e_tmpname);
803 + e_tmpname = Nullch;
806 /* now that script is parsed, we can modify record separator */
807 @@ -1369,7 +1371,7 @@ SV *sv;
811 - origfilename = savepv(e_fp ? "-e" : scriptname);
812 + origfilename = savepv(e_tmpname ? "-e" : scriptname);
813 curcop->cop_filegv = gv_fetchfile(origfilename);
814 if (strEQ(origfilename,"-"))
820 # Parallel build for miniperl is safe
821 system "make $j miniperl";
823 my $expected = $target =~ /^test/ ? 't/perl'
824 : $target eq 'Fcntl' ? "lib/auto/Fcntl/Fcntl.$Config{so}"
826 my $real_target = $target eq 'Fcntl' ? $expected : $target;
828 if ($target ne 'miniperl') {
829 # Nearly all parallel build issues fixed by 5.10.0. Untrustworthy before that.
830 $j = '' if $major < 10;
832 if ($real_target eq 'test_prep') {
834 # test-prep was added in 5.004_01, 3e3baf6d63945cb6.
835 # renamed to test_prep in 2001 in 5fe84fd29acaf55c.
836 # earlier than that, just make test. It will be fast enough.
837 $real_target = extract_from_file('Makefile.SH',
838 qr/^(test[-_]prep):/,
844 and -f 'ext/IPC/SysV/SysV.xs',
845 and my ($line) = extract_from_file('ext/IPC/SysV/SysV.xs',
846 qr!^(# *include <asm/page.h>)$!)) {
847 apply_patch(<<"EOPATCH");
848 diff --git a/ext/IPC/SysV/SysV.xs b/ext/IPC/SysV/SysV.xs
849 index 35a8fde..62a7965 100644
850 --- a/ext/IPC/SysV/SysV.xs
851 +++ b/ext/IPC/SysV/SysV.xs
854 #include <sys/types.h>
858 #if defined(HAS_MSG) || defined(HAS_SEM) || defined(HAS_SHM)
862 system "make $j $real_target";
865 my $missing_target = $expected =~ /perl$/ ? !-x $expected : !-r $expected;
867 if ($options{'test-build'}) {
868 report_and_exit($missing_target, 'could build', 'could not build',
870 } elsif ($missing_target) {
871 skip("could not build $real_target");
874 match_and_exit($real_target) if $match;
876 if (defined $options{'one-liner'}) {
877 my $exe = $target =~ /^(?:perl$|test)/ ? 'perl' : 'miniperl';
878 unshift @ARGV, "./$exe", '-Ilib', '-e', $options{'one-liner'};
881 # This is what we came here to run:
882 my $ret = system @ARGV;
884 report_and_exit($ret, 'zero exit from', 'non-zero exit from', "@ARGV");
887 # cperl-indent-level: 4
888 # indent-tabs-mode: nil
891 # ex: set ts=8 sts=4 sw=4 et: