This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
buildperl.pl: Don't die if make install returns >0
[perl5.git] / dist / Devel-PPPort / devel / buildperl.pl
CommitLineData
adfe19db
MHM
1#!/usr/bin/perl -w
2################################################################################
3#
4# buildperl.pl -- build various versions of perl automatically
5#
6################################################################################
7#
b2049988 8# Version 3.x, Copyright (C) 2004-2013, Marcus Holland-Moritz.
adfe19db
MHM
9# Version 2.x, Copyright (C) 2001, Paul Marquess.
10# Version 1.x, Copyright (C) 1999, Kenneth Albanowski.
11#
12# This program is free software; you can redistribute it and/or
13# modify it under the same terms as Perl itself.
14#
15################################################################################
16
17use strict;
18use Getopt::Long;
19use Pod::Usage;
20use File::Find;
21use File::Path;
22use Data::Dumper;
23use IO::File;
24use Cwd;
25
0d0f8426
MHM
26# TODO: - extra arguments to Configure
27
679ad62d
MHM
28#
29# --test-archives=1 check if archives can be read
30# --test-archives=2 like 1, but also extract archives
31# --test-archives=3 like 2, but also apply patches
32#
33
adfe19db 34my %opt = (
1d175cda
MHM
35 prefix => '/tmp/perl/install/<config>/<perl>',
36 build => '/tmp/perl/build/<config>',
37 source => '/tmp/perl/source',
38 force => 0,
39 test => 0,
40 install => 1,
41 oneshot => 0,
42 configure => 0,
58a3bd53 43 jobs => 1,
cac25305 44 'test-archives' => 0,
adfe19db
MHM
45);
46
47my %config = (
4a582685 48 default => {
b2049988 49 config_args => '-des',
adfe19db 50 },
4a582685 51 thread => {
b2049988
MHM
52 config_args => '-des -Dusethreads',
53 masked_versions => [ qr/^5\.00[01234]/ ],
adfe19db 54 },
4a582685 55 thread5005 => {
b2049988
MHM
56 config_args => '-des -Duse5005threads',
57 masked_versions => [ qr/^5\.00[012345]|^5\.(9|\d\d)|^5\.8\.9/ ],
adfe19db 58 },
4a582685 59 debug => {
b2049988 60 config_args => '-des -Doptimize=-g',
adfe19db
MHM
61 },
62);
63
64my @patch = (
65 {
66 perl => [
0d0f8426 67 qr/^5\.00[01234]/,
adfe19db 68 qw/
0d0f8426
MHM
69 5.005
70 5.005_01
71 5.005_02
72 5.005_03
adfe19db
MHM
73 /,
74 ],
75 subs => [
76 [ \&patch_db, 1 ],
77 ],
78 },
79 {
80 perl => [
b2049988 81 qw/
0d0f8426
MHM
82 5.6.0
83 5.6.1
84 5.7.0
85 5.7.1
86 5.7.2
87 5.7.3
88 5.8.0
b2049988 89 /,
adfe19db
MHM
90 ],
91 subs => [
92 [ \&patch_db, 3 ],
93 ],
94 },
95 {
96 perl => [
679ad62d 97 qr/^5\.004_0[1234]$/,
adfe19db
MHM
98 ],
99 subs => [
100 [ \&patch_doio ],
101 ],
102 },
679ad62d
MHM
103 {
104 perl => [
105 qw/
106 5.005
107 5.005_01
108 5.005_02
109 /,
110 ],
111 subs => [
112 [ \&patch_sysv, old_format => 1 ],
113 ],
114 },
115 {
116 perl => [
117 qw/
118 5.005_03
119 5.005_04
120 /,
121 qr/^5\.6\.[0-2]$/,
122 qr/^5\.7\.[0-3]$/,
123 qr/^5\.8\.[0-8]$/,
124 qr/^5\.9\.[0-5]$/
125 ],
126 subs => [
127 [ \&patch_sysv ],
128 ],
129 },
49ef49fe
CBW
130 {
131 perl => [
132 qr/^5\.004_05$/,
133 qr/^5\.005(?:_0[1-4])?$/,
134 qr/^5\.6\.[01]$/,
135 ],
136 subs => [
137 [ \&patch_configure ],
138 [ \&patch_makedepend_lc ],
139 ],
140 },
141 {
142 perl => [
143 '5.8.0',
144 ],
145 subs => [
146 [ \&patch_makedepend_lc ],
147 ],
148 },
adfe19db
MHM
149);
150
151my(%perl, @perls);
152
153GetOptions(\%opt, qw(
154 config=s@
155 prefix=s
0d0f8426 156 build=s
adfe19db
MHM
157 source=s
158 perl=s@
159 force
0d0f8426
MHM
160 test
161 install!
679ad62d 162 test-archives=i
1d175cda
MHM
163 patch!
164 oneshot
58a3bd53 165 jobs=i
adfe19db
MHM
166)) or pod2usage(2);
167
1d175cda
MHM
168my %current;
169
58a3bd53
KW
170my $job_string = "";
171$job_string = "-j$opt{jobs}" if $opt{jobs} != 1;
172
1d175cda
MHM
173if ($opt{patch} || $opt{oneshot}) {
174 @{$opt{perl}} == 1 or die "Exactly one --perl must be given with --patch or --oneshot\n";
175 my $perl = $opt{perl}[0];
176 patch_source($perl) if !exists $opt{patch} || $opt{patch};
177 if (exists $opt{oneshot}) {
178 eval { require String::ShellQuote };
179 die "--oneshot requires String::ShellQuote to be installed\n" if $@;
180 %current = (config => 'oneshot', version => $perl);
181 $config{oneshot} = { config_args => String::ShellQuote::shell_quote(@ARGV) };
182 build_and_install($perl{$perl});
183 }
184 exit 0;
185}
186
adfe19db
MHM
187if (exists $opt{config}) {
188 for my $cfg (@{$opt{config}}) {
189 exists $config{$cfg} or die "Unknown configuration: $cfg\n";
190 }
191}
192else {
193 $opt{config} = [sort keys %config];
194}
195
196find(sub {
49ef49fe 197 /^(perl-?(5\..*))\.tar\.(gz|bz2|lzma)$/ or return;
0d0f8426 198 $perl{$1} = { version => $2, source => $File::Find::name, compress => $3 };
adfe19db
MHM
199}, $opt{source});
200
201if (exists $opt{perl}) {
202 for my $perl (@{$opt{perl}}) {
203 my $p = $perl;
204 exists $perl{$p} or $p = "perl$perl";
205 exists $perl{$p} or $p = "perl-$perl";
206 exists $perl{$p} or die "Cannot find perl: $perl\n";
207 push @perls, $p;
208 }
209}
210else {
211 @perls = sort keys %perl;
212}
213
cac25305
MHM
214if ($opt{'test-archives'}) {
215 my $test = 'test';
216 my $cwd = cwd;
217 -d $test or mkpath($test);
218 chdir $test or die "chdir $test: $!\n";
219 for my $perl (@perls) {
220 eval {
221 my $d = extract_source($perl{$perl});
679ad62d
MHM
222 if ($opt{'test-archives'} > 2) {
223 my $cwd2 = cwd;
224 chdir $d or die "chdir $d: $!\n";
225 patch_source($perl{$perl}{version});
226 chdir $cwd2 or die "chdir $cwd2:$!\n"
227 }
cac25305
MHM
228 rmtree($d) if -e $d;
229 };
230 warn $@ if $@;
231 }
232 chdir $cwd or die "chdir $cwd: $!\n";
233 print STDERR "cleaning up\n";
234 rmtree($test);
235 exit 0;
236}
237
adfe19db
MHM
238for my $cfg (@{$opt{config}}) {
239 for my $perl (@perls) {
240 my $config = $config{$cfg};
0d0f8426 241 %current = (config => $cfg, perl => $perl, version => $perl{$perl}{version});
adfe19db 242
0d0f8426 243 if (is($config->{masked_versions}, $current{version})) {
adfe19db
MHM
244 print STDERR "skipping $perl for configuration $cfg (masked)\n";
245 next;
246 }
247
248 if (-d expand($opt{prefix}) and !$opt{force}) {
249 print STDERR "skipping $perl for configuration $cfg (already installed)\n";
250 next;
251 }
252
253 my $cwd = cwd;
254
255 my $build = expand($opt{build});
256 -d $build or mkpath($build);
257 chdir $build or die "chdir $build: $!\n";
258
259 print STDERR "building $perl with configuration $cfg\n";
260 buildperl($perl, $config);
261
262 chdir $cwd or die "chdir $cwd: $!\n";
263 }
264}
265
266sub expand
267{
268 my $in = shift;
269 $in =~ s/(<(\w+)>)/exists $current{$2} ? $current{$2} : $1/eg;
270 return $in;
271}
272
273sub is
274{
275 my($s1, $s2) = @_;
4a582685 276
adfe19db
MHM
277 defined $s1 != defined $s2 and return 0;
278
279 ref $s2 and ($s1, $s2) = ($s2, $s1);
280
281 if (ref $s1) {
282 if (ref $s1 eq 'ARRAY') {
283 is($_, $s2) and return 1 for @$s1;
284 return 0;
285 }
286 return $s2 =~ $s1;
287 }
288
289 return $s1 eq $s2;
290}
291
292sub buildperl
293{
294 my($perl, $cfg) = @_;
295
296 my $d = extract_source($perl{$perl});
297 chdir $d or die "chdir $d: $!\n";
298
0d0f8426 299 patch_source($perl{$perl}{version});
adfe19db
MHM
300
301 build_and_install($perl{$perl});
302}
303
304sub extract_source
305{
1d175cda
MHM
306 eval { require Archive::Tar };
307 die "Archive processing requires Archive::Tar to be installed\n" if $@;
308
adfe19db 309 my $perl = shift;
adfe19db 310
cac25305
MHM
311 my $what = $opt{'test-archives'} ? 'test' : 'read';
312 print "${what}ing $perl->{source}\n";
adfe19db 313
0d0f8426 314 my $target;
adfe19db 315
0d0f8426
MHM
316 for my $f (Archive::Tar->list_archive($perl->{source})) {
317 my($t) = $f =~ /^([^\\\/]+)/ or die "ooops, should always match...\n";
318 die "refusing to extract $perl->{source}, as it would not extract to a single directory\n"
319 if defined $target and $target ne $t;
320 $target = $t;
321 }
adfe19db 322
cac25305
MHM
323 if ($opt{'test-archives'} == 0 || $opt{'test-archives'} > 1) {
324 if (-d $target) {
325 print "removing old build directory $target\n";
326 rmtree($target);
327 }
adfe19db 328
cac25305 329 print "extracting $perl->{source}\n";
0d0f8426 330
cac25305
MHM
331 Archive::Tar->extract_archive($perl->{source})
332 or die "extract failed: " . Archive::Tar->error() . "\n";
0d0f8426 333
cac25305
MHM
334 -d $target or die "oooops, $target not found\n";
335 }
adfe19db
MHM
336
337 return $target;
338}
339
340sub patch_source
341{
0d0f8426 342 my $version = shift;
adfe19db
MHM
343
344 for my $p (@patch) {
0d0f8426 345 if (is($p->{perl}, $version)) {
adfe19db
MHM
346 for my $s (@{$p->{subs}}) {
347 my($sub, @args) = @$s;
348 $sub->(@args);
349 }
350 }
351 }
352}
353
354sub build_and_install
355{
356 my $perl = shift;
357 my $prefix = expand($opt{prefix});
358
49ef49fe
CBW
359 run_or_die(q{sed -i -e "s:\\*/\\*) finc=\\"-I\\`echo \\$file | sed 's#/\\[^/\\]\\*\\$##\\`\\" ;;:*/*) finc=\\"-I\\`echo \\$file | sed 's#/[^/]\\*\\$##'\\`\\" ;;:" makedepend.SH});
360
adfe19db
MHM
361 print "building perl $perl->{version} ($current{config})\n";
362
363 run_or_die("./Configure $config{$current{config}}{config_args} -Dusedevel -Uinstallusrbinperl -Dprefix=$prefix");
b2049988
MHM
364 if (-f "x2p/makefile") {
365 run_or_die("sed -i -e '/^.*<builtin>/d' -e '/^.*<built-in>/d' -e '/^.*<command line>/d' -e '/^.*<command-line>/d' makefile x2p/makefile");
366 }
58a3bd53
KW
367 run_or_die("make $job_string all");
368 run("TEST_JOBS=$opt{jobs} make $job_string test") if $opt{test};
0d0f8426 369 if ($opt{install}) {
be2ee45c 370 run("make $job_string install");
0d0f8426
MHM
371 }
372 else {
373 print "\n*** NOT INSTALLING PERL ***\n\n";
374 }
adfe19db
MHM
375}
376
377sub patch_db
378{
379 my $ver = shift;
679ad62d 380 print "patching ext/DB_File/DB_File.xs\n";
adfe19db
MHM
381 run_or_die("sed -i -e 's/<db.h>/<db$ver\\/db.h>/' ext/DB_File/DB_File.xs");
382}
383
384sub patch_doio
385{
679ad62d 386 patch(<<'END');
adfe19db
MHM
387--- doio.c.org 2004-06-07 23:14:45.000000000 +0200
388+++ doio.c 2003-11-04 08:03:03.000000000 +0100
389@@ -75,6 +75,16 @@
390 # endif
391 #endif
4a582685 392
adfe19db
MHM
393+#if _SEM_SEMUN_UNDEFINED
394+union semun
395+{
396+ int val;
397+ struct semid_ds *buf;
398+ unsigned short int *array;
399+ struct seminfo *__buf;
400+};
401+#endif
402+
403 bool
404 do_open(gv,name,len,as_raw,rawmode,rawperm,supplied_fp)
405 GV *gv;
406END
407}
408
679ad62d
MHM
409sub patch_sysv
410{
411 my %opt = @_;
412
413 # check if patching is required
414 return if $^O ne 'linux' or -f '/usr/include/asm/page.h';
415
416 if ($opt{old_format}) {
417 patch(<<'END');
418--- ext/IPC/SysV/SysV.xs.org 1998-07-20 10:20:07.000000000 +0200
419+++ ext/IPC/SysV/SysV.xs 2007-08-12 10:51:06.000000000 +0200
420@@ -3,9 +3,6 @@
421 #include "XSUB.h"
422
423 #include <sys/types.h>
424-#ifdef __linux__
425-#include <asm/page.h>
426-#endif
427 #if defined(HAS_MSG) || defined(HAS_SEM) || defined(HAS_SHM)
428 #include <sys/ipc.h>
429 #ifdef HAS_MSG
430END
431 }
432 else {
433 patch(<<'END');
434--- ext/IPC/SysV/SysV.xs.org 2007-08-11 00:12:46.000000000 +0200
435+++ ext/IPC/SysV/SysV.xs 2007-08-11 00:10:51.000000000 +0200
436@@ -3,9 +3,6 @@
437 #include "XSUB.h"
438
439 #include <sys/types.h>
440-#ifdef __linux__
441-# include <asm/page.h>
442-#endif
443 #if defined(HAS_MSG) || defined(HAS_SEM) || defined(HAS_SHM)
444 #ifndef HAS_SEM
445 # include <sys/ipc.h>
446END
447 }
448}
449
49ef49fe
CBW
450sub patch_configure
451{
452 patch(<<'END');
453--- Configure
454+++ Configure
455@@ -3380,6 +3380,18 @@
456 test "X$gfpthkeep" != Xy && gfpth=""
457 EOSC
458
459+# gcc 3.1 complains about adding -Idirectories that it already knows about,
460+# so we will take those off from locincpth.
461+case "$gccversion" in
462+3*)
463+ echo "main(){}">try.c
464+ for incdir in `$cc -v -c try.c 2>&1 | \
465+ sed '1,/^#include <\.\.\.>/d;/^End of search list/,$d;s/^ //'` ; do
466+ locincpth=`echo $locincpth | sed s!$incdir!!`
467+ done
468+ $rm -f try try.*
469+esac
470+
471 : What should the include directory be ?
472 echo " "
473 $echo $n "Hmm... $c"
474END
475}
476
477sub patch_makedepend_lc
478{
479 patch(<<'END');
480--- makedepend.SH
481+++ makedepend.SH
482@@ -58,6 +58,10 @@ case $PERL_CONFIG_SH in
483 ;;
484 esac
485
486+# Avoid localized gcc/cc messages
487+LC_ALL=C
488+export LC_ALL
489+
490 # We need .. when we are in the x2p directory if we are using the
491 # cppstdin wrapper script.
492 # Put .. and . first so that we pick up the present cppstdin, not
493END
494}
495
adfe19db
MHM
496sub patch
497{
679ad62d
MHM
498 my($patch) = @_;
499 print "patching $_\n" for $patch =~ /^\+{3}\s+(\S+)/gm;
500 my $diff = 'tmp.diff';
adfe19db
MHM
501 write_or_die($diff, $patch);
502 run_or_die("patch -s -p0 <$diff");
503 unlink $diff or die "unlink $diff: $!\n";
504}
505
506sub write_or_die
507{
508 my($file, $data) = @_;
509 my $fh = new IO::File ">$file" or die "$file: $!\n";
510 $fh->print($data);
511}
512
513sub run_or_die
514{
515 # print "[running @_]\n";
516 system "@_" and die "@_: $?\n";
517}
518
519sub run
520{
521 # print "[running @_]\n";
522 system "@_" and warn "@_: $?\n";
523}
0d0f8426
MHM
524
525__END__
526
527=head1 NAME
528
529buildperl.pl - build/install perl distributions
530
531=head1 SYNOPSIS
532
533 perl buildperl.pl [options]
534
535 --help show this help
536
537 --source=directory directory containing source tarballs
538 [default: /tmp/perl/source]
539
540 --build=directory directory used for building perls [EXPAND]
541 [default: /tmp/perl/build/<config>]
542
543 --prefix=directory use this installation prefix [EXPAND]
5cde1e48
KW
544 [default:
545 /tmp/perl/install/<config>/<perl>]
0d0f8426
MHM
546
547 --config=configuration build this configuration [MULTI]
548 [default: all possible configurations]
549
550 --perl=version build this version of perl [MULTI]
551 [default: all possible versions]
552
5cde1e48
KW
553 --force rebuild and install already installed
554 versions
0d0f8426
MHM
555
556 --test run test suite after building
557
558 --noinstall don't install after building
559
5cde1e48
KW
560 --patch only patch the perl source in the current
561 directory
1d175cda 562
5cde1e48
KW
563 --oneshot build from the perl source in the current
564 directory (extra arguments are passed to
565 Configure)
1d175cda 566
58a3bd53
KW
567 -j N Build and test with N parallel jobs, default 1.
568
0d0f8426
MHM
569 options tagged with [MULTI] can be given multiple times
570
571 options tagged with [EXPAND] expand the following items
572
573 <perl> versioned perl directory (e.g. 'perl-5.6.1')
574 <version> perl version (e.g. '5.6.1')
575 <config> name of the configuration (e.g. 'default')
576
577=head1 EXAMPLES
578
579The following examples assume that your Perl source tarballs are
580in F</tmp/perl/source>. If they are somewhere else, use the C<--source>
581option to specify a different source directory.
582
583To build a default configuration of perl5.004_05 and install it
584to F</opt/perl5.004_05>, you would say:
585
586 buildperl.pl --prefix='/opt/<perl>' --perl=5.004_05 --config=default
587
588To build debugging configurations of all perls in the source directory
589and install them to F</opt>, use:
590
591 buildperl.pl --prefix='/opt/<perl>' --config=debug
592
593To build all configurations for perl-5.8.5 and perl-5.8.6, test them
594and don't install them, run:
595
596 buildperl.pl --perl=5.8.5 --perl=5.8.6 --test --noinstall
597
1d175cda
MHM
598To build and install a single version of perl with special configuration
599options, use:
600
5cde1e48
KW
601 buildperl.pl --perl=5.6.0 --prefix=/opt/p560ld --oneshot -- -des \
602 -Duselongdouble
1d175cda 603
0d0f8426
MHM
604=head1 COPYRIGHT
605
b2049988 606Copyright (c) 2004-2013, Marcus Holland-Moritz.
0d0f8426
MHM
607
608This program is free software; you can redistribute it and/or
609modify it under the same terms as Perl itself.
610
611=head1 SEE ALSO
612
ba120f6f 613See L<Devel::PPPort> and L<HACKERS>.