This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Avoid bisect-runner.pl hanging on pre-5.004 if a file in MANIFEST is missing.
[perl5.git] / Porting / bisect-runner.pl
1 #!/usr/bin/perl -w
2 use strict;
3
4 use Getopt::Long;
5
6 my @targets = qw(miniperl lib/Config.pm perl test_prep);
7
8 my $target = 'test_prep';
9 my $j = '9';
10 my $test_should_pass = 1;
11 my $clean = 1;
12 my $one_liner;
13 my $match;
14
15 sub usage {
16     die "$0: [--target=...] [-j=4] [--expect-pass=0|1] thing to test";
17 }
18
19 unless(GetOptions('target=s' => \$target,
20                   'jobs|j=i' => \$j,
21                   'expect-pass=i' => \$test_should_pass,
22                   'expect-fail' => sub { $test_should_pass = 0; },
23                   'clean!' => \$clean, # mostly for debugging this
24                   'one-liner|e=s' => \$one_liner,
25                   'match=s' => \$match,
26                  )) {
27     usage();
28 }
29
30 my $exe = $target eq 'perl' || $target eq 'test_prep' ? 'perl' : 'miniperl';
31 my $expected = $target eq 'test_prep' ? 'perl' : $target;
32
33 unshift @ARGV, "./$exe", '-Ilib', '-e', $one_liner if defined $one_liner;
34
35 usage() unless @ARGV || $match;
36
37 die "$0: Can't build $target" unless grep {@targets} $target;
38
39 $j = "-j$j" if $j =~ /\A\d+\z/;
40
41 sub extract_from_file {
42     my ($file, $rx, $default) = @_;
43     open my $fh, '<', $file or die "Can't open $file: $!";
44     while (<$fh>) {
45         my @got = $_ =~ $rx;
46         return wantarray ? @got : $got[0]
47             if @got;
48     }
49     return $default if defined $default;
50     return;
51 }
52
53 sub clean {
54     if ($clean) {
55         # Needed, because files that are build products in this checked out
56         # version might be in git in the next desired version.
57         system 'git clean -dxf';
58         # Needed, because at some revisions the build alters checked out files.
59         # (eg pod/perlapi.pod). Also undoes any changes to makedepend.SH
60         system 'git reset --hard HEAD';
61     }
62 }
63
64 sub skip {
65     my $reason = shift;
66     clean();
67     warn "skipping - $reason";
68     exit 125;
69 }
70
71 sub report_and_exit {
72     my ($ret, $pass, $fail, $desc) = @_;
73
74     clean();
75
76     my $got = ($test_should_pass ? !$ret : $ret) ? 'good' : 'bad';
77     if ($ret) {
78         print "$got - $fail $desc\n";
79     } else {
80         print "$got - $pass $desc\n";
81     }
82
83     exit($got eq 'bad');
84 }
85
86 # Not going to assume that system perl is yet new enough to have autodie
87 system 'git clean -dxf' and die;
88
89 if ($match) {
90     my $matches;
91     my $re = qr/$match/;
92     foreach my $file (`git ls-files`) {
93         chomp $file;
94         open my $fh, '<', $file or die "Can't open $file: $!";
95         while (<$fh>) {
96             if ($_ =~ $re) {
97                 ++$matches;
98                 $_ .= "\n" unless /\n\z/;
99                 print "$file: $_";
100             }
101         }
102         close $fh or die "Can't close $file: $!";
103     }
104     report_and_exit(!$matches, 'matches for', 'no matches for', $match);
105 }
106
107 skip('no Configure - is this the //depot/perlext/Compiler branch?')
108     unless -f 'Configure';
109
110 # This changes to PERL_VERSION in 4d8076ea25903dcb in 1999
111 my $major
112     = extract_from_file('patchlevel.h',
113                         qr/^#define\s+(?:PERL_VERSION|PATCHLEVEL)\s+(\d+)\s/,
114                         0);
115
116 # There was a bug in makedepend.SH which was fixed in version 96a8704c.
117 # Symptom was './makedepend: 1: Syntax error: Unterminated quoted string'
118 # Remove this if you're actually bisecting a problem related to makedepend.SH
119 system 'git show blead:makedepend.SH > makedepend.SH' and die;
120
121 my @paths = qw(/usr/local/lib64 /lib64 /usr/lib64);
122
123 # if Encode is not needed for the test, you can speed up the bisect by
124 # excluding it from the runs with -Dnoextensions=Encode
125 # ccache is an easy win. Remove it if it causes problems.
126 my @ARGS = ('-des', '-Dusedevel', '-Doptimize=-g', '-Dcc=ccache gcc',
127             '-Dld=gcc', "-Dlibpth=@paths");
128
129 # Commit 1cfa4ec74d4933da adds ignore_versioned_solibs to Configure, and sets it
130 # to true in hints/linux.sh
131 # On dromedary, from that point on, Configure (by default) fails to find any
132 # libraries, because it scans /usr/local/lib /lib /usr/lib, which only contain
133 # versioned libraries. Without -lm, the build fails.
134 # Telling /usr/local/lib64 /lib64 /usr/lib64 works from that commit onwards,
135 # until commit faae14e6e968e1c0 adds it to the hints.
136 # However, prior to 1cfa4ec74d4933da telling Configure the truth doesn't work,
137 # because it will spot versioned libraries, pass them to the compiler, and then
138 # bail out pretty early on. Configure won't let us override libswanted, but it
139 # will let us override the entire libs list.
140
141 unless (extract_from_file('Configure', 'ignore_versioned_solibs')) {
142     # Before 1cfa4ec74d4933da, so force the libs list.
143
144     my @libs;
145     # This is the current libswanted list from Configure, less the libs removed
146     # by current hints/linux.sh
147     foreach my $lib (qw(sfio socket inet nsl nm ndbm gdbm dbm db malloc dl dld
148                         ld sun m crypt sec util c cposix posix ucb BSD)) {
149         foreach my $dir (@paths) {
150             next unless -f "$dir/lib$lib.so";
151             push @libs, "-l$lib";
152             last;
153         }
154     }
155     push @ARGS, "-Dlibs=@libs";
156 }
157
158 # This seems to be necessary to avoid makedepend becoming confused, and hanging
159 # on stdin. Seems that the code after make shlist || ...here... is never run.
160 push @ARGS, q{-Dtrnl='\n'}
161     if $major < 4;
162
163 # </dev/null because it seems that some earlier versions of Configure can
164 # call commands in a way that now has them reading from stdin (and hanging)
165 my $pid = fork;
166 die "Can't fork: $!" unless defined $pid;
167 if (!$pid) {
168     # Before dfe9444ca7881e71, Configure would refuse to run if stdin was not a
169     # tty. With that commit, the tty requirement was dropped for -de and -dE
170     if($major > 4) {
171         open STDIN, '<', '/dev/null' 
172     } else {
173         # If a file in MANIFEST is missing, Configure asks if you want to
174         # continue (the default being 'n'). With stdin closed or /dev/null,
175         # it exit immediately and the check for config.sh below will skip.
176         # To avoid a hang, we need to check MANIFEST for ourselves, and skip
177         # if anything is missing.
178         open my $fh, '<', 'MANIFEST';
179         skip("Could not open MANIFEST: $!")
180             unless $fh;
181         while (<$fh>) {
182             next unless /^(\S+)/;
183             skip("$1 from MANIFEST doesn't exist")
184                 unless -f $1;
185         }
186         close $fh or die "Can't close MANIFEST: $!";
187     }
188     exec './Configure', @ARGS;
189     die "Failed to start Configure: $!";
190 }
191 waitpid $pid, 0
192     or die "wait for Configure, pid $pid failed: $!";
193
194 # Skip if something went wrong with Configure
195 skip('no config.sh') unless -f 'config.sh';
196
197 # Correct makefile for newer GNU gcc
198 # Only really needed if you comment out the use of blead's makedepend.SH
199 {
200     local $^I = "";
201     local @ARGV = qw(makefile x2p/makefile);
202     while (<>) {
203         print unless /<(?:built-in|command|stdin)/;
204     }
205 }
206
207 # Parallel build for miniperl is safe
208 system "make $j miniperl";
209
210 if ($target ne 'miniperl') {
211     # Nearly all parallel build issues fixed by 5.10.0. Untrustworthy before that.
212     $j = '' unless $major > 10;
213
214     if ($target eq 'test_prep') {
215         if ($major < 8) {
216             # test-prep was added in 5.004_01, 3e3baf6d63945cb6.
217             # renamed to test_prep in 2001 in 5fe84fd29acaf55c.
218             # earlier than that, just make test. It will be fast enough.
219             $target = extract_from_file('Makefile.SH', qr/^(test[-_]prep):/,
220                                         'test');
221         }
222     }
223
224     system "make $j $target";
225 }
226
227 skip("could not build $target")
228     if $expected =~ /perl$/ ? !-x $expected : !-r $expected;
229
230 # This is what we came here to run:
231 my $ret = system @ARGV;
232
233 report_and_exit($ret, 'zero exit from', 'non-zero exit from', "@ARGV");
234
235 # Local variables:
236 # cperl-indent-level: 4
237 # indent-tabs-mode: nil
238 # End:
239 #
240 # ex: set ts=8 sts=4 sw=4 et: