This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
bisect-runner.pl now fixes more 5.11-era make bugs.
[perl5.git] / Porting / bisect-runner.pl
index 7f9de33..df36968 100755 (executable)
@@ -53,7 +53,7 @@ my %defines =
     (
      usedevel => '',
      optimize => '-g',
-     cc => 'ccache cc',
+     cc => (`ccache --version`, $?) ? 'cc' : 'ccache cc',
      ld => 'cc',
      ($linux64 ? (libpth => \@paths) : ()),
     );
@@ -62,8 +62,8 @@ unless(GetOptions(\%options,
                   'target=s', 'jobs|j=i', 'expect-pass=i',
                   'expect-fail' => sub { $options{'expect-pass'} = 0; },
                   'clean!', 'one-liner|e=s', 'match=s', 'force-manifest',
-                  'force-regen', 'test-build', 'check-args', 'A=s@',
-                  'usage|help|?',
+                  'force-regen', 'test-build', 'A=s@', 'l', 'w',
+                  'check-args', 'check-shebang!', 'usage|help|?',
                   'D=s@' => sub {
                       my (undef, $val) = @_;
                       if ($val =~ /\A([^=]+)=(.*)/s) {
@@ -84,6 +84,10 @@ my ($target, $j, $match) = @options{qw(target jobs match)};
 pod2usage(exitval => 255, verbose => 1) if $options{usage};
 pod2usage(exitval => 255, verbose => 1)
     unless @ARGV || $match || $options{'test-build'} || defined $options{'one-liner'};
+pod2usage(exitval => 255, verbose => 1)
+    if !$options{'one-liner'} && ($options{l} || $options{w});
+
+check_shebang($ARGV[0]) if $options{'check-shebang'} && @ARGV;
 
 exit 0 if $options{'check-args'};
 
@@ -270,6 +274,27 @@ which interferes with detecting errors in the example code itself.
 
 =item *
 
+-l
+
+Add C<-l> to the command line with C<-e>
+
+This will automatically append a newline to every output line of your testcase.
+Note that you can't specify an argument to F<perl>'s C<-l> with this, as it's
+not feasible to emulate F<perl>'s somewhat quirky switch parsing with
+L<Getopt::Long>. If you need the full flexibility of C<-l>, you need to write
+a full test case, instead of using C<bisect.pl>'s C<-e> shortcut.
+
+=item *
+
+-w
+
+Add C<-w> to the command line with C<-e>
+
+It's not valid to pass C<-l> or C<-w> to C<bisect.pl> unless you are also
+using C<-e>
+
+=item *
+
 --expect-fail
 
 The test case should fail for the I<start> revision, and pass for the I<end>
@@ -387,12 +412,16 @@ Passing this to F<bisect.pl> will likely cause the bisect to fail badly.
 
 --validate
 
-Test that all stable revisions can be built. Attempts to build I<blead>,
-I<v5.14.0> .. I<perl-5.002>. Stops at the first failure, without cleaning
-the checkout. Ignores I<--start> and I<--end>. Useful for validating a new
+Test that all stable revisions can be built. By default, attempts to build
+I<blead>, I<v5.14.0> .. I<perl-5.002>. Stops at the first failure, without
+cleaning the checkout. Use I<--start> to specify the earliest revision to
+test, I<--end> to specify the most recent. Useful for validating a new
 OS/CPU/compiler combination. For example
 
-    ../perl/Porting/bisect.pl --validate -e'print "Hello from $]\n"'
+    ../perl/Porting/bisect.pl --validate -le 'print "Hello from $]"'
+
+If no testcase is specified, the default is to use F<t/TEST> to run
+F<t/base/*.t>
 
 =item *
 
@@ -402,6 +431,20 @@ Validate the options and arguments, and exit silently if they are valid.
 
 =item *
 
+--check-shebang
+
+Validate that the test case isn't an executable file with a
+C<#!/usr/bin/perl> line (or similar). As F<bisect-runner.pl> does B<not>
+prepend C<./perl> to the test case, a I<#!> line specifying an external
+F<perl> binary will cause the test case to always run with I<that> F<perl>,
+not the F<perl> built by the bisect runner. Likely this is not what you
+wanted. If your test case is actually a wrapper script to run other
+commands, you should run it with an explicit interpreter, to be clear. For
+example, instead of C<../perl/Porting/bisect.pl ~/test/testcase.pl> you'd
+run C<../perl/Porting/bisect.pl /usr/bin/perl ~/test/testcase.pl>
+
+=item *
+
 --usage
 
 =item *
@@ -499,6 +542,36 @@ sub checkout_file {
         and die "Could not extract $file at revision $commit";
 }
 
+sub check_shebang {
+    my $file = shift;
+    return unless -e $file;
+    if (!-x $file) {
+        die "$file is not executable.
+system($file, ...) is always going to fail.
+
+Bailing out";
+    }
+    my $fh = open_or_die($file);
+    my $line = <$fh>;
+    return unless $line =~ m{\A#!(/\S+/perl\S*)\s};
+    die "$file will always be run by $1
+It won't be tested by the ./perl we build.
+If you intended to run it with that perl binary, please change your
+test case to
+
+    $1 @ARGV
+
+If you intended to test it with the ./perl we build, please change your
+test case to
+
+    ./perl -Ilib @ARGV
+
+[You may also need to add -- before ./perl to prevent that -Ilib as being
+parsed as an argument to bisect.pl]
+
+Bailing out";
+}
+
 sub clean {
     if ($options{clean}) {
         # Needed, because files that are build products in this checked out
@@ -729,7 +802,10 @@ match_and_exit($real_target) if $match;
 
 if (defined $options{'one-liner'}) {
     my $exe = $target =~ /^(?:perl$|test)/ ? 'perl' : 'miniperl';
-    unshift @ARGV, "./$exe", '-Ilib', '-e', $options{'one-liner'};
+    unshift @ARGV, '-e', $options{'one-liner'};
+    unshift @ARGV, '-l' if $options{l};
+    unshift @ARGV, '-w' if $options{w};
+    unshift @ARGV, "./$exe", '-Ilib';
 }
 
 # This is what we came here to run:
@@ -1558,6 +1634,119 @@ index f61d0db..6097954 100644
  
 EOPATCH
         }
+
+        if ($major == 11) {
+            if (extract_from_file('patchlevel.h',
+                                  qr/^#include "unpushed\.h"/)) {
+                # I had thought it easier to detect when building one of the 52
+                # commits with the original method of incorporating the git
+                # revision and drop parallel make flags. Commits shown by
+                # git log 46807d8e809cc127^..dcff826f70bf3f64^ ^d4fb0a1f15d1a1c4
+                # However, it's not actually possible to make miniperl for that
+                # configuration as-is, because the file .patchnum is only made
+                # as a side effect of target 'all'
+                # I also don't think that it's "safe" to simply run
+                # make_patchnum.sh before the build. We need the proper
+                # dependency rules in the Makefile to *stop* it being run again
+                # at the wrong time.
+                # This range is important because contains the commit that
+                # merges Schwern's y2038 work.
+                apply_patch(<<'EOPATCH');
+diff --git a/Makefile.SH b/Makefile.SH
+index 9ad8b6f..106e721 100644
+--- a/Makefile.SH
++++ b/Makefile.SH
+@@ -540,9 +544,14 @@ sperl.i: perl.c $(h)
+ .PHONY: all translators utilities make_patchnum
+-make_patchnum:
++make_patchnum: lib/Config_git.pl
++
++lib/Config_git.pl: make_patchnum.sh
+       sh $(shellflags) make_patchnum.sh
++# .patchnum, unpushed.h and lib/Config_git.pl are built by make_patchnum.sh
++unpushed.h .patchnum: lib/Config_git.pl
++
+ # make sure that we recompile perl.c if .patchnum changes
+ perl$(OBJ_EXT): .patchnum unpushed.h
+EOPATCH
+            } elsif (-f '.gitignore'
+                     && extract_from_file('.gitignore', qr/^\.patchnum$/)) {
+                # 8565263ab8a47cda to 46807d8e809cc127^ inclusive.
+                edit_file('Makefile.SH', sub {
+                              my $code = shift;
+                              $code =~ s/^make_patchnum:\n/make_patchnum: .patchnum
+
+.sha1: .patchnum
+
+.patchnum: make_patchnum.sh
+/m;
+                              return $code;
+                          });
+            } elsif (-f 'lib/.gitignore'
+                     && extract_from_file('lib/.gitignore',
+                                          qr!^/Config_git.pl!)
+                     && !extract_from_file('Makefile.SH',
+                                        qr/^uudmap\.h.*:bitcount.h$/)) {
+                # Between commits and dcff826f70bf3f64 and 0f13ebd5d71f8177^
+                edit_file('Makefile.SH', sub {
+                              my $code = shift;
+                              # Bug introduced by 344af494c35a9f0f
+                              # fixed in 0f13ebd5d71f8177
+                              $code =~ s{^(pod/perlapi\.pod) (pod/perlintern\.pod): }
+                                        {$1: $2\n\n$2: }m;
+                              # Bug introduced by efa50c51e3301a2c
+                              # fixed in 0f13ebd5d71f8177
+                              $code =~ s{^(uudmap\.h) (bitcount\.h): }
+                                        {$1: $2\n\n$2: }m;
+
+                              # The rats nest of getting git_version.h correct
+
+                              if ($code =~ s{git_version\.h: stock_git_version\.h
+\tcp stock_git_version\.h git_version\.h}
+                                            {}m) {
+                                  # before 486cd780047ff224
+
+                                  # We probably can't build between
+                                  # 953f6acfa20ec275^ and 8565263ab8a47cda
+                                  # inclusive, but all commits in that range
+                                  # relate to getting make_patchnum.sh working,
+                                  # so it is extremely unlikely to be an
+                                  # interesting bisect target. They will skip.
+
+                                  # No, don't spawn a submake if
+                                  # make_patchnum.sh or make_patchnum.pl fails
+                                  $code =~ s{\|\| \$\(MAKE\) miniperl.*}
+                                            {}m;
+                                  $code =~ s{^\t(sh.*make_patchnum\.sh.*)}
+                                            {\t-$1}m;
+
+                                  # Use an external perl to run make_patchnum.pl
+                                  # because miniperl still depends on
+                                  # git_version.h
+                                  $code =~ s{^\t.*make_patchnum\.pl}
+                                            {\t-$^X make_patchnum.pl}m;
+
+
+                                  # "Truth in advertising" - running
+                                  # make_patchnum generates 2 files.
+                                  $code =~ s{^make_patchnum:.*}{
+make_patchnum: lib/Config_git.pl
+
+git_version.h: lib/Config_git.pl
+
+perlmini\$(OBJ_EXT): git_version.h
+
+lib/Config_git.pl:}m;
+                              }
+                              return $code;
+                          });
+            }
+        }
+
         if ($major < 14) {
             # Commits dc0655f797469c47 and d11a62fe01f2ecb2
             edit_file('Makefile.SH', sub {
@@ -1871,9 +2060,13 @@ EOPATCH
         apply_commit('e1c148c28bf3335b', 'av.c');
     }
 
-    if ($major == 4 && !extract_from_file('perl.c', qr/delimcpy.*,$/)) {
-        # bug introduced in 2a92aaa05aa1acbf, fixed in 8490252049bf42d3
-        apply_patch(<<'EOPATCH');
+    if ($major == 4) {
+        my $rest = extract_from_file('perl.c', qr/delimcpy(.*)/);
+        if (defined $rest and $rest !~ /,$/) {
+            # delimcpy added in fc36a67e8855d031, perl.c refactored to use it.
+            # bug introduced in 2a92aaa05aa1acbf, fixed in 8490252049bf42d3
+            # code then moved to util.c in commit 491527d0220de34e
+            apply_patch(<<'EOPATCH');
 diff --git a/perl.c b/perl.c
 index 4eb69e3..54bbb00 100644
 --- a/perl.c
@@ -1888,6 +2081,7 @@ index 4eb69e3..54bbb00 100644
                         &len);
  #endif        /* ! (atarist || DOSISH) */
 EOPATCH
+        }
     }
 
     if ($major == 4 && $^O eq 'linux') {