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