This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
perltodo.pod: add perlio todos/thinkabouts
[perl5.git] / ext / 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#
ba120f6f 8# $Revision: 9 $
adfe19db 9# $Author: mhx $
ba120f6f 10# $Date: 2006/05/28 20:42:53 +0200 $
adfe19db
MHM
11#
12################################################################################
13#
0d0f8426 14# Version 3.x, Copyright (C) 2004-2006, Marcus Holland-Moritz.
adfe19db
MHM
15# Version 2.x, Copyright (C) 2001, Paul Marquess.
16# Version 1.x, Copyright (C) 1999, Kenneth Albanowski.
17#
18# This program is free software; you can redistribute it and/or
19# modify it under the same terms as Perl itself.
20#
21################################################################################
22
23use strict;
24use Getopt::Long;
25use Pod::Usage;
26use File::Find;
27use File::Path;
28use Data::Dumper;
29use IO::File;
0d0f8426 30use Archive::Tar;
adfe19db
MHM
31use Cwd;
32
0d0f8426
MHM
33# TODO: - extra arguments to Configure
34
adfe19db 35my %opt = (
0d0f8426
MHM
36 prefix => '/tmp/perl/install/<config>/<perl>',
37 build => '/tmp/perl/build/<config>',
38 source => '/tmp/perl/source',
39 force => 0,
40 test => 0,
41 install => 1,
adfe19db
MHM
42);
43
44my %config = (
4a582685 45 default => {
adfe19db
MHM
46 config_args => '-des',
47 },
4a582685 48 thread => {
adfe19db 49 config_args => '-des -Dusethreads',
0d0f8426 50 masked_versions => [ qr/^5\.00[01234]/ ],
adfe19db 51 },
4a582685 52 thread5005 => {
adfe19db 53 config_args => '-des -Duse5005threads',
0d0f8426 54 masked_versions => [ qr/^5\.00[012345]|^5.(9|\d\d)/ ],
adfe19db 55 },
4a582685 56 debug => {
adfe19db
MHM
57 config_args => '-des -Doptimize=-g',
58 },
59);
60
61my @patch = (
62 {
63 perl => [
0d0f8426 64 qr/^5\.00[01234]/,
adfe19db 65 qw/
0d0f8426
MHM
66 5.005
67 5.005_01
68 5.005_02
69 5.005_03
adfe19db
MHM
70 /,
71 ],
72 subs => [
73 [ \&patch_db, 1 ],
74 ],
75 },
76 {
77 perl => [
78 qw/
0d0f8426
MHM
79 5.6.0
80 5.6.1
81 5.7.0
82 5.7.1
83 5.7.2
84 5.7.3
85 5.8.0
adfe19db
MHM
86 /,
87 ],
88 subs => [
89 [ \&patch_db, 3 ],
90 ],
91 },
92 {
93 perl => [
0d0f8426 94 qr/^5\.004_0[1234]/,
adfe19db
MHM
95 ],
96 subs => [
97 [ \&patch_doio ],
98 ],
99 },
100);
101
102my(%perl, @perls);
103
104GetOptions(\%opt, qw(
105 config=s@
106 prefix=s
0d0f8426 107 build=s
adfe19db
MHM
108 source=s
109 perl=s@
110 force
0d0f8426
MHM
111 test
112 install!
adfe19db
MHM
113)) or pod2usage(2);
114
115if (exists $opt{config}) {
116 for my $cfg (@{$opt{config}}) {
117 exists $config{$cfg} or die "Unknown configuration: $cfg\n";
118 }
119}
120else {
121 $opt{config} = [sort keys %config];
122}
123
124find(sub {
0d0f8426
MHM
125 /^(perl-?(5\..*))\.tar\.(gz|bz2)$/ or return;
126 $perl{$1} = { version => $2, source => $File::Find::name, compress => $3 };
adfe19db
MHM
127}, $opt{source});
128
129if (exists $opt{perl}) {
130 for my $perl (@{$opt{perl}}) {
131 my $p = $perl;
132 exists $perl{$p} or $p = "perl$perl";
133 exists $perl{$p} or $p = "perl-$perl";
134 exists $perl{$p} or die "Cannot find perl: $perl\n";
135 push @perls, $p;
136 }
137}
138else {
139 @perls = sort keys %perl;
140}
141
adfe19db
MHM
142my %current;
143
144for my $cfg (@{$opt{config}}) {
145 for my $perl (@perls) {
146 my $config = $config{$cfg};
0d0f8426 147 %current = (config => $cfg, perl => $perl, version => $perl{$perl}{version});
adfe19db 148
0d0f8426 149 if (is($config->{masked_versions}, $current{version})) {
adfe19db
MHM
150 print STDERR "skipping $perl for configuration $cfg (masked)\n";
151 next;
152 }
153
154 if (-d expand($opt{prefix}) and !$opt{force}) {
155 print STDERR "skipping $perl for configuration $cfg (already installed)\n";
156 next;
157 }
158
159 my $cwd = cwd;
160
161 my $build = expand($opt{build});
162 -d $build or mkpath($build);
163 chdir $build or die "chdir $build: $!\n";
164
165 print STDERR "building $perl with configuration $cfg\n";
166 buildperl($perl, $config);
167
168 chdir $cwd or die "chdir $cwd: $!\n";
169 }
170}
171
172sub expand
173{
174 my $in = shift;
175 $in =~ s/(<(\w+)>)/exists $current{$2} ? $current{$2} : $1/eg;
176 return $in;
177}
178
179sub is
180{
181 my($s1, $s2) = @_;
4a582685 182
adfe19db
MHM
183 defined $s1 != defined $s2 and return 0;
184
185 ref $s2 and ($s1, $s2) = ($s2, $s1);
186
187 if (ref $s1) {
188 if (ref $s1 eq 'ARRAY') {
189 is($_, $s2) and return 1 for @$s1;
190 return 0;
191 }
192 return $s2 =~ $s1;
193 }
194
195 return $s1 eq $s2;
196}
197
198sub buildperl
199{
200 my($perl, $cfg) = @_;
201
202 my $d = extract_source($perl{$perl});
203 chdir $d or die "chdir $d: $!\n";
204
0d0f8426 205 patch_source($perl{$perl}{version});
adfe19db
MHM
206
207 build_and_install($perl{$perl});
208}
209
210sub extract_source
211{
212 my $perl = shift;
adfe19db 213
0d0f8426 214 print "reading $perl->{source}\n";
adfe19db 215
0d0f8426 216 my $target;
adfe19db 217
0d0f8426
MHM
218 for my $f (Archive::Tar->list_archive($perl->{source})) {
219 my($t) = $f =~ /^([^\\\/]+)/ or die "ooops, should always match...\n";
220 die "refusing to extract $perl->{source}, as it would not extract to a single directory\n"
221 if defined $target and $target ne $t;
222 $target = $t;
223 }
adfe19db 224
0d0f8426
MHM
225 if (-d $target) {
226 print "removing old build directory $target\n";
227 rmtree($target);
adfe19db
MHM
228 }
229
0d0f8426
MHM
230 print "extracting $perl->{source}\n";
231
232 Archive::Tar->extract_archive($perl->{source})
233 or die "extract failed: " . Archive::Tar->error() . "\n";
234
235 -d $target or die "oooops, $target not found\n";
adfe19db
MHM
236
237 return $target;
238}
239
240sub patch_source
241{
0d0f8426 242 my $version = shift;
adfe19db
MHM
243
244 for my $p (@patch) {
0d0f8426 245 if (is($p->{perl}, $version)) {
adfe19db
MHM
246 for my $s (@{$p->{subs}}) {
247 my($sub, @args) = @$s;
248 $sub->(@args);
249 }
250 }
251 }
252}
253
254sub build_and_install
255{
256 my $perl = shift;
257 my $prefix = expand($opt{prefix});
258
259 print "building perl $perl->{version} ($current{config})\n";
260
261 run_or_die("./Configure $config{$current{config}}{config_args} -Dusedevel -Uinstallusrbinperl -Dprefix=$prefix");
262 run_or_die("sed -i -e '/^.*<built-in>/d' -e '/^.*<command line>/d' makefile x2p/makefile");
263 run_or_die("make all");
0d0f8426
MHM
264 run("make test") if $opt{test};
265 if ($opt{install}) {
266 run_or_die("make install");
267 }
268 else {
269 print "\n*** NOT INSTALLING PERL ***\n\n";
270 }
adfe19db
MHM
271}
272
273sub patch_db
274{
275 my $ver = shift;
276 print "patching DB_File\n";
277 run_or_die("sed -i -e 's/<db.h>/<db$ver\\/db.h>/' ext/DB_File/DB_File.xs");
278}
279
280sub patch_doio
281{
282 patch('doio.c', <<'END');
283--- doio.c.org 2004-06-07 23:14:45.000000000 +0200
284+++ doio.c 2003-11-04 08:03:03.000000000 +0100
285@@ -75,6 +75,16 @@
286 # endif
287 #endif
4a582685 288
adfe19db
MHM
289+#if _SEM_SEMUN_UNDEFINED
290+union semun
291+{
292+ int val;
293+ struct semid_ds *buf;
294+ unsigned short int *array;
295+ struct seminfo *__buf;
296+};
297+#endif
298+
299 bool
300 do_open(gv,name,len,as_raw,rawmode,rawperm,supplied_fp)
301 GV *gv;
302END
303}
304
305sub patch
306{
307 my($file, $patch) = @_;
308 print "patching $file\n";
309 my $diff = "$file.diff";
310 write_or_die($diff, $patch);
311 run_or_die("patch -s -p0 <$diff");
312 unlink $diff or die "unlink $diff: $!\n";
313}
314
315sub write_or_die
316{
317 my($file, $data) = @_;
318 my $fh = new IO::File ">$file" or die "$file: $!\n";
319 $fh->print($data);
320}
321
322sub run_or_die
323{
324 # print "[running @_]\n";
325 system "@_" and die "@_: $?\n";
326}
327
328sub run
329{
330 # print "[running @_]\n";
331 system "@_" and warn "@_: $?\n";
332}
0d0f8426
MHM
333
334__END__
335
336=head1 NAME
337
338buildperl.pl - build/install perl distributions
339
340=head1 SYNOPSIS
341
342 perl buildperl.pl [options]
343
344 --help show this help
345
346 --source=directory directory containing source tarballs
347 [default: /tmp/perl/source]
348
349 --build=directory directory used for building perls [EXPAND]
350 [default: /tmp/perl/build/<config>]
351
352 --prefix=directory use this installation prefix [EXPAND]
353 [default: /tmp/perl/install/<config>/<perl>]
354
355 --config=configuration build this configuration [MULTI]
356 [default: all possible configurations]
357
358 --perl=version build this version of perl [MULTI]
359 [default: all possible versions]
360
361 --force rebuild and install already installed versions
362
363 --test run test suite after building
364
365 --noinstall don't install after building
366
367 options tagged with [MULTI] can be given multiple times
368
369 options tagged with [EXPAND] expand the following items
370
371 <perl> versioned perl directory (e.g. 'perl-5.6.1')
372 <version> perl version (e.g. '5.6.1')
373 <config> name of the configuration (e.g. 'default')
374
375=head1 EXAMPLES
376
377The following examples assume that your Perl source tarballs are
378in F</tmp/perl/source>. If they are somewhere else, use the C<--source>
379option to specify a different source directory.
380
381To build a default configuration of perl5.004_05 and install it
382to F</opt/perl5.004_05>, you would say:
383
384 buildperl.pl --prefix='/opt/<perl>' --perl=5.004_05 --config=default
385
386To build debugging configurations of all perls in the source directory
387and install them to F</opt>, use:
388
389 buildperl.pl --prefix='/opt/<perl>' --config=debug
390
391To build all configurations for perl-5.8.5 and perl-5.8.6, test them
392and don't install them, run:
393
394 buildperl.pl --perl=5.8.5 --perl=5.8.6 --test --noinstall
395
396=head1 COPYRIGHT
397
ba120f6f 398Copyright (c) 2004-2006, Marcus Holland-Moritz.
0d0f8426
MHM
399
400This program is free software; you can redistribute it and/or
401modify it under the same terms as Perl itself.
402
403=head1 SEE ALSO
404
ba120f6f 405See L<Devel::PPPort> and L<HACKERS>.
0d0f8426 406