# -*- mode: cperl -*-
eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
if 0; # not running under some shell
# PODNAME: bootstrap-perl
# ABSTRACT: Bootstrap Perl inclusive CPAN from git
use strict;
use warnings;
use Getopt::Long ":config", "no_ignore_case", "bundling";
use Cwd "getcwd";
my $HOME = $ENV{HOME};
my $build_path = "/tmp/bootstrap-perl-build";
my $build_path_perl = "$build_path/perl";
my $logfile = "$build_path/bootstrap-perl.log";
my $giturl = "git://github.com/Perl/perl5.git";
my $cpucount = `cat /proc/cpuinfo | grep bogomips | wc -l`; chomp $cpucount;
my $threadcount = $cpucount + 1;
# getopt
my $dry;
my $prefix;
my $prefixbase = "/opt";
my $version = "blead";
my $installdeps;
my $sourcetgz = "/var/tmp/perl.tar.gz";
my $blead = 0;
my $usethreads = 1;
my $bit64 = 1;
my $help = 0;
my $test = 0;
my $cpan = 1;
my $cleancpansources = 0;
my $forcecpancfg = 1;
my $perlformance = 0;
my $perlformance_local = 0;
my $perlformance_report = 0;
my $jobs = $threadcount;
my @mirrors;
my @modules;
my @runscripts = ();
my @runargs = ();
my @confargs = ();
my @exesuffixes = ();
my $OLDSTDOUT = *STDOUT;
my $OLDSTDERR = *STDERR;
sub print_and_system {
my ($cmd) = @_;
print $cmd."\n";
system ($cmd);
}
sub print_and_qx {
my ($cmd) = @_;
print $cmd."\n";
qx($cmd);
}
sub print_and_qx_chomp {
my $out = print_and_qx @_;
chomp $out;
$out;
}
sub _perl_base_name {
my ($perl_revision, $perl_version, $perl_subversion, $usethreads, $bit64, $gitdescribe, $gitchangeset, $exe_suffixes, $blead) = @_;
return join("-",
($blead ? "blead" : "$perl_revision.$perl_version"),
($usethreads ? "" : "no" )."thread",
($bit64 ? "" : "no" )."64bit",
@$exe_suffixes,
);
}
sub _perl_exe_name {
my ($perl_revision, $perl_version, $perl_subversion, $usethreads, $bit64, $gitdescribe, $gitchangeset, $exe_suffixes, $blead) = @_;
return join("-",
"perl",
_perl_base_name(@_),
);
}
sub _perl_pathprefix {
my ($perl_revision, $perl_version, $perl_subversion, $usethreads, $bit64, $gitdescribe, $gitchangeset, $exe_suffixes, $blead) = @_;
return join("-",
$prefixbase."/perl",
_perl_base_name(@_),
$gitdescribe,
);
}
# ========== getopt ==========
my $ok = GetOptions (
"prefix=s" => \$prefix,
"prefixbase=s" => \$prefixbase,
"version|commit|c=s" => \$version,
"installdeps=s" => \$installdeps,
"sourcetgz=s" => \$sourcetgz,
"blead!" => \$blead,
"usethreads!" => \$usethreads,
"use64bit!" => \$bit64,
"help|h" => \$help,
"jobs|j=i" => \$jobs,
"test|t" => \$test,
"cpan!" => \$cpan,
"cleancpansources!" => \$cleancpansources,
"forcecpancfg!" => \$forcecpancfg,
'perlformance' => \$perlformance,
'perlformance-local' => \$perlformance_local,
'perlformance-report' => \$perlformance_report,
'dry|n' => \$dry,
'mirror|m=s@' => \@mirrors,
'module|M=s@' => \@modules,
'run|r=s@' => \@runscripts,
'runargs=s@' => \@runargs,
'confargs=s@' => \@confargs,
'exesuffixes=s@' => \@exesuffixes,
'giturl|g=s' => \$giturl,
);
if ($help) {
exec("perldoc", "bootstrap-perl") or do {
print "\nPlease see 'perldoc bootstrap-perl' for help.\n";
exit 0;
}
}
my $DISTROPREFSREPO = "git://github.com/renormalist/cpanpm-distroprefs.git";
my $DISTROPREFSSRCBASE = "$build_path";
my $DISTROPREFSSRC1 = "$DISTROPREFSSRCBASE/cpanpm-distroprefs/cpanpm/distroprefs";
my $DISTROPREFSSRC2 = "$DISTROPREFSSRCBASE/cpanpm-distroprefs/renormalist/distroprefs";
my $DISTROPREFSDIR = $prefixbase."/cpan/prefs";
my $SOURCESDIR = $prefixbase."/cpan/sources";
my $CPANBUILDDIR = $prefixbase."/cpan/build";
# defaults
my @default_runscripts = ();
my @default_confargs = ();
my @default_runargs = ();
my @default_modules = ();
my @default_mirrors = (qw( http://search.cpan.org/CPAN/ ));
print "\n";
print "============================================================\n";
print "Bootstrap Perl\n";
print "============================================================\n";
# giturl "." means clone from local dir
if ($giturl eq '.') {
$giturl = getcwd;
my $firstcommit = qx!git log --oneline 8d063cd8450e59ea1c611a2f4f5a21059a2804f1 2> /dev/null!;
if ($firstcommit !~ /a "replacement" for awk and sed/) {
print "Local git repo does not look like it is Perl's.\n";
exit 1;
}
}
# version "." is replaced with current repo's HEAD
if ($version =~ /^\./) {
my $rev = print_and_qx_chomp qq!git rev-parse HEAD!;
$version =~ s/^\./$rev/ if $rev;
}
if ($perlformance_local) {
$giturl = ".";
@default_modules = qw(Benchmark::Perl::Formance);
@default_mirrors = qw(http://perlformance.net/PINTO/perlformance/);
@default_runscripts = qw(benchmark-perlformance);
@default_runargs = ("--plugins=Fib,FibOO,DPath,Mem,Rx,Shootout::fasta,Shootout::binarytrees,Shootout::nbody,Shootout::spectralnorm");
}
if ($perlformance or $perlformance_report) {
@default_modules = qw(Task::PerlFormance);
@default_mirrors = qw(http://perlformance.net/PINTO/perlformance/);
@default_runscripts = qw(benchmark-perlformance);
@default_runargs = qw(--plugins=ALL);
}
if ($perlformance_report) {
@default_runscripts = qw(tapper-testsuite-benchmark-perlformance);
@default_runargs = qw(--plugins=ALL);
@default_runargs = ("-Doptimize='-O2 -falign-loops=8 -falign-jumps=8 -falign-functions=64 -falign-labels=8 -mpreferred-stack-boundary=8 -minline-all-stringops'");
}
# modules/mirros/runscripts can be comma-separated
my @MODULES = map { chomp; $_ } map { split(qr/,/, $_) } (@modules ? @modules : @default_modules);
my @CPANMIRRORS = map { chomp; $_ } map { split(qr/,/, $_) } (@mirrors ? @mirrors : @default_mirrors);
my @RUNSCRIPTS = map { chomp; $_ } map { split(qr/,/, $_) } (@runscripts ? @runscripts : @default_runscripts);
my @RUNARGS = map { chomp; $_ } map { split(qr/;/, $_) } (@runargs ? @runargs : @default_runargs);
my @EXESUFFIXES = sort map { chomp; $_ } map { split(qr/,/, $_) } @exesuffixes;
my $CONFARGS = join " ", map { chomp; $_ } (@confargs ? @confargs : @default_confargs); # repeatable, but no comma-separate
# ========== build dependencies ==========
sub installdeps_debian
{
my $APTGETOPTIONS ='-o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" --yes';
my $APTGET = "DEBIAN_FRONTEND=noninteractive; export DEBIAN_FRONTEND ; sudo apt-get $APTGETOPTIONS";
my @DEPENDECIES = (qw(make
patch
makepatch
curl
wget
rsync
gcc
g++
git
perl-modules
libbz2-1.0
libbz2-dev
libdb-dev
libsqlite3-dev
linux-source
libgmp3-dev
libssl-dev
libpcre3-dev
));
foreach my $dep (@DEPENDECIES) {
print_and_system "$APTGET install $dep\n";
}
}
if ($installdeps) {
my @SUPPORTED_DISTROS = (qw(debian));
if (grep { /$installdeps/ } @SUPPORTED_DISTROS) {
print "Install dependencies for: $installdeps\n";
eval "installdeps_$installdeps()";
} else {
print "Unsupported dependency installation for distro: $installdeps\n";
print "Allowed distros: ".join(", ", @SUPPORTED_DISTROS), "\n";
exit 1;
}
}
# ========== prepare ==========
print_and_system "mkdir -p $build_path";
if (-d "$build_path_perl/.git") {
print_and_system "cd $build_path_perl && git config remote.origin.url $giturl";
}
else
{
if (-e $sourcetgz) {
print_and_system "cd $build_path && tar xzf $sourcetgz";
} else {
print_and_system "cd $build_path && git clone $giturl perl";
}
}
chdir "$build_path_perl"; # important, I don't remember for what below
print_and_system "cd $build_path_perl && rm -f $build_path_perl/.git/index.lock";
print_and_system "cd $build_path_perl && git reset --hard";
print_and_system "cd $build_path_perl && git clean -dxf";
print_and_system "cd $build_path_perl && git checkout blead";
print_and_system "cd $build_path_perl && git pull";
print_and_system "cd $build_path_perl && git checkout $version";
print_and_system "cd $build_path_perl && git pull";
# cherry pick several bugfixes in 5.8/5.9 that break building
if ($version =~ /(v|perl-)?5\.8\./ or $version =~ /(v|perl-)?5\.9\.[01234]/) {
print "*** cherry-pick building fixes for older perl versions\n";
# FIX: <command-line>
print_and_system qq!cd $build_path_perl && git cherry-pick -n cf14425e2bd169ce935f76d359f3253b51e441a0!;
# FIX: rebuild / gcc -g
print_and_system qq!cd $build_path_perl && git cherry-pick -n a3d1be69db4c082c1b9cef14f51a6e7fe4a9dac9!;
# FIX: makedepend.SH
print_and_system qq!cd $build_path_perl && git cherry-pick -n 96a8704c85b1e14bb3d63195b0b720f2fd5b8182!;
# FIX: create missing link (5.8.8)
print_and_system q'sudo ln -sf `find /usr/src -name page.h | grep arch/x86/include/asm/page.h | tail -1` /usr/include/asm/' if ! -e "/usr/include/asm/page.h";
}
# ========== prepare paths ==========
my $gitdescribe;
$gitdescribe = print_and_qx_chomp qq!cd $build_path_perl && git describe --all!;
$gitdescribe = print_and_qx_chomp qq!cd $build_path_perl && git describe! if ($gitdescribe =~ m,/, && $gitdescribe !~ m,tags/,);
$gitdescribe =~ s|^tags/||g;
my $gitchangeset = print_and_qx_chomp qq!cd $build_path_perl && git rev-parse HEAD!;
my ($perl_revision, $perl_version, $perl_subversion) = $gitdescribe =~ m/^\D*(\d+)[._](\d+)(?:[._](\d+))?.*$/g;
$perl_version = sprintf("%02d", $perl_version);
$perl_subversion ||= 0;
unless (defined $perl_revision && defined $perl_version)
{
no warnings 'uninitialized';
print "# Bummer! Unrecognized version schema ($gitdescribe).\n";
print "# ($perl_revision, $perl_version, $perl_subversion)\n";
exit 1;
}
my $codespeed_executable = _perl_exe_name ($perl_revision, $perl_version, $perl_subversion, $usethreads, $bit64, $gitdescribe, $gitchangeset, \@EXESUFFIXES, $blead);
my $PREFIX = $prefix || _perl_pathprefix($perl_revision, $perl_version, $perl_subversion, $usethreads, $bit64, $gitdescribe, $gitchangeset, \@EXESUFFIXES, $blead);
my $USETHREADS = $usethreads ? "-Dusethreads" : "";
my $BIT64 = $bit64 ? "-Duse64bitall" : "";
print "\n";
print "============================================================\n\n";
print " Bootstrap Perl\n";
print " --------------\n\n";
print " version: $version\n\n";
print " git-describe: $gitdescribe\n\n";
print " git-changeset: $gitchangeset\n\n";
print " codespeed name: $codespeed_executable\n\n";
print " PREFIX: $PREFIX\n\n";
print " configureargs: ".join("\n ", @confargs)."\n\n";
print " CPAN mirrors: ".join("\n ", @CPANMIRRORS)."\n\n";
print " modules: ".join("\n ", @MODULES)."\n\n";
print " scripts: ".join("\n ", map { $_ ." ".join(" ", @RUNARGS) } @RUNSCRIPTS)."\n\n";
print "============================================================\n\n";
my @in_blead = grep { / blead$/ }
map { chomp ; $_ }
print_and_qx qq!git branch --contains $gitchangeset!;
if ($blead && !@in_blead) {
print "# Bummer!\n";
print "# Use '--blead' only with commits in blead branch.\n";
exit 1;
}
$ENV{PERL_AUTOINSTALL} = "--defaultdeps";
$ENV{TEST_JOBS} = $threadcount;
$ENV{TWMC_TEST_PORT} = "9876";
my $perl_gitdescribe = "$PREFIX/bin/perl-gitdescribe";
my $perl_gitchangeset = "$PREFIX/bin/perl-gitchangeset";
my $perl_codespeed = "$PREFIX/bin/perl-codespeed-executable";
my $THREADS = $jobs ? "-j $jobs" : "-j $threadcount";
my $DRY = $dry ? "-n" : "";
# ========== build ==========
if ( ! -e $perl_codespeed )
{
print "*** BUILD perl\n";
# ========== configure ==========
print_and_system "cd $build_path_perl; sh Configure -de -Dusedevel $USETHREADS $BIT64 $CONFARGS -Dprefix=$PREFIX";
# ========== make ==========
print_and_system "cd $build_path_perl; make $THREADS";
if ($test)
{
my $api_version = print_and_qx_chomp qq!cd $build_path_perl; . ./config.sh && echo \$api_version!;
my $TEST = $api_version >= 11 ? "test_harness" : "test"; # only Perl 5.11+
my $TEST_JOBS = $jobs ? "TEST_JOBS=$jobs" : "TEST_JOBS=$threadcount";
print_and_system "cd $build_path_perl; $TEST_JOBS make $TEST";
}
# ========== install ==========
print_and_system "cd $build_path_perl; make $DRY install";
} else {
print "*** SKIP building perl - already existing.\n";
}
# ========== perlformance utils ==========
# create a binary that prints git version
if (open my $PERLGITDESCRIBE, ">", $perl_gitdescribe)
{
print $PERLGITDESCRIBE sprintf(qq{#! /usr/bin/env perl\n\nprint '%s'."\n";}, $gitdescribe);
print_and_system "chmod ugo+x $perl_gitdescribe";
close $PERLGITDESCRIBE;
}
if (open my $PERLGITCHANGESET, ">", $perl_gitchangeset)
{
print $PERLGITCHANGESET sprintf(qq{#! /usr/bin/env perl\n\nprint '%s'."\n";}, $gitchangeset);
print_and_system "chmod ugo+x $perl_gitchangeset";
close $PERLGITCHANGESET;
}
# create a binary that prints sensible executable name for codespeed
if (open my $PERLCODESPEED, ">", $perl_codespeed)
{
print $PERLCODESPEED sprintf(qq{#! /usr/bin/env perl\n\nprint '%s'."\n";}, $codespeed_executable);
print_and_system "chmod ugo+x $perl_codespeed";
close $PERLCODESPEED;
}
# binaries
my $CPAN = print_and_qx_chomp qq!ls -drt1 $PREFIX/bin/cpan5.*.* | tail -1!;
my $PERL = print_and_qx_chomp qq!ls -drt1 $PREFIX/bin/perl5.*.* | tail -1!;
my $PERLDOC = print_and_qx_chomp qq!ls -drt1 $PREFIX/bin/perldoc5.*.* | tail -1!;
my $POD2TEXT = print_and_qx_chomp qq!ls -drt1 $PREFIX/bin/pod2text5.*.* | tail -1!;
print "# CPAN: $CPAN\n";
print "# PERL: $PERL\n";
print "# PERLDOC: $PERLDOC\n";
print "# POD2TEXT: $POD2TEXT\n";
my $bin_perl = "$PREFIX/bin/perl";
my $bin_cpan = "$PREFIX/bin/cpan";
my $bin_perldoc = "$PREFIX/bin/perldoc";
my $bin_pod2text = "$PREFIX/bin/pod2text";
# some dists don't find the versioned developer files
print_and_system "if [ ! -e $bin_perl ] ; then ln -sf $PERL $bin_perl ; fi";
print_and_system "if [ ! -e $bin_cpan ] ; then ln -sf $CPAN $bin_cpan ; fi";
print_and_system "if [ ! -e $bin_perldoc ] ; then ln -sf $PERLDOC $bin_perldoc ; fi";
print_and_system "if [ ! -e $bin_pod2text ] ; then ln -sf $POD2TEXT $bin_pod2text ; fi";
# ========== cpan ==========
if ($cpan)
{
# distroprefs: get all from git
print_and_system "mkdir -p $DISTROPREFSSRCBASE";
print_and_system "cd $DISTROPREFSSRCBASE && git clone $DISTROPREFSREPO";
print_and_system "cd $DISTROPREFSSRCBASE/cpanpm-distroprefs && git pull";
print_and_system "cd $DISTROPREFSSRCBASE/cpanpm-distroprefs && git submodule update --init --recursive";
print_and_system "cd $DISTROPREFSSRCBASE/cpanpm-distroprefs && git pull";
# distroprefs: merge our flavour
print_and_system qq!mkdir -p $DISTROPREFSDIR!;
print_and_system qq!rsync -r $DISTROPREFSSRC1/ $DISTROPREFSDIR/!;
print_and_system qq!rsync -r $DISTROPREFSSRC2/ $DISTROPREFSDIR/!;
# Cleanup build dir
print_and_system qq!rm -fr $CPANBUILDDIR!;
# Configure CPAN initially
my $CFG = print_and_qx_chomp qq!$PERLDOC -l CPAN | sed -e "s/CPAN\.pm/CPAN\\/Config.pm/"!;
if ($forcecpancfg or ! -e $CFG) {
my $CPANCFG = do { local $/; <DATA> };
my $MIRRORSLIST = join(" ", @CPANMIRRORS);
$CPANCFG =~ s/__DISTROPREFSDIR__/$DISTROPREFSDIR/g;
$CPANCFG =~ s/__MIRRORS__/$MIRRORSLIST/g;
$CPANCFG =~ s/__PREFIXBASE__/$prefixbase/g;
open CPANCFG, ">", $CFG or die "Can not create $CFG";
print CPANCFG $CPANCFG;
close CPANCFG;
}
# remove stale cpan lock
my $cpanlock = "$prefixbase/cpan/.lock";
if (-e $cpanlock) {
my ($pid, $host) = qx!cat $cpanlock!;
chomp $pid;
my $exists = kill 0, $pid;
if (not $exists) {
print "Remove stale CPAN.pm lock.\n";
print_and_system qq!rm -f $cpanlock!;
}
}
# optionally remove sources cache to avoid conflicts,
# like happening with hot-patched CPAN mirrors (via Pinto)
if ($cleancpansources) {
print "Remove $SOURCESDIR.\n";
print_and_system qq!rm -fr '$SOURCESDIR'!;
}
# force a CPAN.pm with all features we need, assume old-school CPAN.pm
print_and_system qq{if [ -L $bin_cpan -o ! -e $bin_cpan ] ; then /bin/rm $bin_cpan ; echo "force install CPAN" | $PERL -MCPAN -e shell ; fi};
# once upon a time the cpan exe missed the executable bit - set it to be sure
print_and_system qq!chmod +x $CPAN!;
print_and_system qq!chmod +x $bin_cpan!;
# install extended cpan toolchain; contains some "force" where we know they are really required
print_and_system qq!$bin_cpan -j $CFG YAML::XS!;
print_and_system qq!$bin_cpan -j $CFG YAML!;
# try really hard with some modules until we find a version
# that fits currrent Perl
my %mod_dists = (
"YAML" => [qw(MSTROUT/YAML-0.84.tar.gz
MSTROUT/YAML-0.83.tar.gz
MSTROUT/YAML-0.82.tar.gz
INGY/YAML-0.81.tar.gz
INGY/YAML-0.80.tar.gz
INGY/YAML-0.79.tar.gz
INGY/YAML-0.78.tar.gz
INGY/YAML-0.77.tar.gz
INGY/YAML-0.76.tar.gz)],
# "Devel::Size" => [qw(NWCLARK/Devel-Size-0.78.tar.gz
# NWCLARK/Devel-Size-0.77.tar.gz
# NWCLARK/Devel-Size-0.76.tar.gz
# NWCLARK/Devel-Size-0.75.tar.gz
# BROWSERUK/Devel-Size-0.72.tar.gz
# TELS/devel/Devel-Size-0.71.tar.gz
# TELS/devel/Devel-Size-0.70.tar.gz)],
);
foreach my $mod (keys %mod_dists) {
foreach my $dist (@{$mod_dists{$mod}}) {
print_and_system qq{if ! $PERL -M$mod -e1 ; then $bin_cpan -j $CFG $dist ; fi };
}
print_and_system qq{if ! $PERL -M$mod -e1 ; then $bin_cpan -j $CFG -f -i $mod ; fi };
}
print_and_system qq{if ! $PERL -MIO::Compress::Base -e1 ; then $bin_cpan -j $CFG -f -i IO::Compress::Base ; fi };
if ($gitdescribe =~ /perl-5\.8\.0/) {
# ignore known failing tests
print_and_system qq!$bin_cpan -j $CFG -f -i Module::Build!;
}
if ($gitdescribe =~ /perl-5\.9\./) {
# ignore known hanging tests with utf8
print_and_system qq! echo "notest install Test::Simple" | $bin_cpan -j $CFG!;
}
# if ($gitdescribe =~ /perl-5\.15\./) {
# # ignore known failing tests
# print_and_system qq!$bin_cpan -j $CFG -f -i Devel::Size!;
# }
print_and_system qq{if ! $PERL -M"version 0.97" -e1 ; then $bin_cpan -j $CFG -f -i version ; fi };
#print_and_system qq!$bin_cpan -j $CFG -i CPAN::SQLite!;
print_and_system qq!$bin_cpan -j $CFG -i YAML::Syck!;
print_and_system qq!$bin_cpan -j $CFG -i IO::Tty!;
print_and_system qq!$bin_cpan -j $CFG -i Expect!;
print_and_system qq!$bin_cpan -j $CFG -i Bundle::CPAN!;
print_and_system qq!$bin_cpan -j $CFG -i LWP!;
print_and_system qq!$bin_cpan -j $CFG -i AAAA::Mail::SpamAssassin! if $perlformance || $perlformance_report;
# install modules from CPAN
foreach my $module (@MODULES) {
print_and_system qq!$bin_cpan -j $CFG -i $module!;
if ($module =~ qr/^(Benchmark::Perl::Formance|Mail::SPF)$/) {
# That's the whole deal, so we force it.
print_and_system qq{if ! $PERL -M$module -e1 ; then $bin_cpan -j $CFG -f -i $module ; fi };
}
}
} # if ($cpan)
# Run scripts from inside the just installed Perl
foreach my $runscript (@RUNSCRIPTS) {
print_and_system qq!$PREFIX/bin/$runscript !.join(" ", @RUNARGS);
}
# print_and_system qq!$PREFIX/bin/tapper-testsuite-benchmark-perlformance!;
=pod
=encoding utf-8
=head1 NAME
bootstrap-perl - Bootstrap Perl inclusive CPAN from git
=head1 SYNOPSIS
Install a threaded 64bit Perl using current "blead"
from git with CPAN config into a path like
C</opt/perl-5.15-thread-64bit-v5.15.5-258-ge7d0a3f>:
$ bootstrap-perl [ <OPTIONS> ]
=head2 Specify git revisions
=head3 latest "blead"
$ bootstrap-perl --version blead # same as default
=head3 tag
# note the different tag forms before and after Perl 5.10
$ bootstrap-perl --version perl-5.8.7
$ bootstrap-perl --version v5.14.1
=head3 branch name
$ bootstrap-perl --version remotes/origin/smoke-me/cpan
$ bootstrap-perl --version remotes/origin/zefram/pad_api
$ bootstrap-perl --version remotes/origin/maint-5.12
$ bootstrap-perl --version remotes/origin/maint-5.12^
$ bootstrap-perl --version remotes/origin/maint-5.12~3
=head3 by commit id
$ bootstrap-perl --version c14f2f9db08de3f50fe2ff7438429153d6ceb9a5
$ bootstrap-perl --version c14f2f9db08de3f50fe2ff7438429153d6ceb9a5^
=head3 current HEAD in local git repo
A leading C<.> is replaced with HEAD's commitid in current subdir; you
can still combine that like usual git revisions:
$ bootstrap-perl --version .
$ bootstrap-perl --version .^
$ bootstrap-perl --version .~5
=head2 Installation options
=head3 specify giturl
$ bootstrap-perl --giturl git://github.com/mirrors/perl.git
$ bootstrap-perl -g git://github.com/mirrors/perl.git # same
$ bootstrap-perl -g . # local dir
The giturl is always cloned from the specified giturl to a temporary
working directory, so your local subdir stays untouched.
=head3 install directory
Install into other install directory than the unified naming schema
(see below for more on this schema):
$ bootstrap-perl --prefix <PREFIX>
Use the unified naming schema but not under C</opt>:
$ bootstrap-perl --prefixbase /foo/bar
=head3 install build dependencies
Provide the distro for which to install known build dependencies, like
gcc, git, make, etc.:
$ bootstrap-perl --installdeps=debian
Currently there is only one: C<debian>. Simply send me a patch for
your preferred distro, it's easy.
=head3 parallel build
Use this many parallel jobs to build:
$ bootstrap-perl --jobs <n>
$ bootstrap-perl -j <n>
Default is to use core count + 1.
=head3 test
Run the perl test suite:
$ bootstrap-perl --test
$ bootstrap-perl -t
Default is B<not> to run the tests.
=head3 use threads
Build a threaded Perl (C<-Dusethreads>):
$ bootstrap-perl --usethreads
which is already the default. To build non-threaded Perl use:
$ bootstrap-perl --nousethreads
=head3 use 64bit
Build a 64bit enabled Perl (C<-Duse64bitall>):
$ bootstrap-perl --use64bit
which is already the default. To build Perl without 64bit use:
$ bootstrap-perl --nouse64bit
=head3 version numbers vs. blead
By default the Perl version number is derived from git-describe and
kept for later reference (e.g., for codespeed exe name). However, if you
specify
$ bootstrap-perl --blead
then the version used in paths or codespeed executables is using
"blead" in order to generate a make it belong to to a common
development line besides the yearly segmented graphs.
It is only possible to use C<--blead> with development versions in
order to create consistent results from only the blead branch.
Note that C<--blead> does not set a version but only modifies the
formats of path prefix and how the version is reported to
Perl::Formance; it is B<not> the same as C<--version blead>.
=head3 configure CPAN and modules
Configure CPAN to use these mirrors:
$ bootstrap-perl --mirror file:///home/ss5/MINICPAN/
$ bootstrap-perl -m file:///home/ss5/MINICPAN/ -m ftp://ftp.rub.de/pub/CPAN/
$ bootstrap-perl -m file:///home/ss5/MINICPAN/,ftp://ftp.rub.de/pub/CPAN/
(Option can be repeated and allow comma separated lists.)
Install these modules from CPAN:
$ bootstrap-perl --module YAML::Syck
$ bootstrap-perl -M YAML::Syck -M Digest::SHA1 -M IO::Tty -M LWP
$ bootstrap-perl -M YAML::Syck,Digest::SHA1 -M IO::Tty,LWP
(Option can be repeated and allow comma separated lists.)
=head3 run scripts
Run these scripts relative to built <PREFIX>/bin/:
$ bootstrap-perl --run tapper-testsuite-benchmark-perlformance
$ bootstrap-perl --run tapper-testsuite-benchmark-perlformance --runargs="--plugins=Fib,FibOO;-vvv"
$ bootstrap-perl -r tapper-testsuite-benchmark-perlformance -r primes.pl
(Option C<--run> can be repeated and allows comma separated lists.)
(Option C<--runargs> can be repeated and allows semicolon[sic] separated lists.)
=head3 run Perl::Formance benchmarks
To do everything in one go needed for running
Benchmark::Perl::Formance do:
$ bootstrap-perl --perlformance
This sets defaults equivalent to C<-M Task::PerlFormance> C<-m
http://perlformance.net/PINTO/perlformance/> C<--run
benchmark-perlformance> C<--runargs=--plugins=ALL>.
You can override parts of that like this:
$ bootstrap-perl --perlformance --runargs="--plugins=Fib,FibOO"
to specify different set ob benchmarks.
To use current subdir as Perl's repo and run only
those benchmarks with no extra dependencies
$ bootstrap-perl --perlformance-local
$ bootstrap-perl --perlformance-local -c .
$ bootstrap-perl --perlformance-local -c .^
$ bootstrap-perl --perlformance-local -c .~5
=head2 Unified installation prefix schema
It uses a unified naming schema for it's installation PREFIX:
/opt/perl-5.<VERSION>-<(no)?thread>-<(no)?64bit>-<git-describe>
which leads to paths like this:
/opt/perl-5.10-thread-64bit-v5.10.0
/opt/perl-5.15-thread-64bit-v5.15.5-258-ge7d0a3f
This naming schema consist of the major version, basic configuration
and I<git-describe>.
=head2 Meta info utilities
To easily provide the raw I<git-describe> two scripts are is put inside
each install
perl-gitdescribe
perl-gitchangeset
which prints the I<git-describe> of that installation.
Another script
perl-codespeed-executable
is put inside each install which prints a so called "executable name"
for this built perl used on a codespeed instance like
L<http://speed.perlformance.net|http://speed.perlformance.net>. Although
this is unlikely to be useful for others it is always created.
These two utility scripts B<could> be derived from the install prefix
but also work when you provided your own prefix.
=head1 ABOUT
The script B<bootstrap-perl> bootstraps Perl installations with
complete CPAN environment, inclusive distroprefs, from git.
It was originally developed to be used by
L<Benchmark::Perl::Formance|Benchmark::Perl::Formance> and now lives
on its own.
It should work for Perl versions from 5.8.6 to blead. Occasionally it
cherry-picks a very few patches to fix some known build issues, like
for 5.8.x.
=head1 AUTHOR
Steffen Schwigon <ss5@renormalist.net>
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2015 by Steffen Schwigon.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut
__DATA__
# This is CPAN.pm's systemwide configuration file. This file provides
# defaults for users, and the values can be changed in a per-user
# configuration file. The user-config file is being looked for as
# ~/.cpan/CPAN/MyConfig.pm.
$CPAN::Config = {
'applypatch' => q[/usr/bin/applypatch],
'auto_commit' => q[1],
'build_cache' => q[10],
'build_dir' => q[__PREFIXBASE__/cpan/build],
'build_dir_reuse' => q[0],
'build_requires_install_policy' => q[yes],
'bzip2' => q[/bin/bzip2],
'cache_metadata' => q[0],
'check_sigs' => q[0],
'colorize_debug' => q[bold cyan],
'colorize_output' => q[1],
'colorize_print' => q[bold blue],
'colorize_warn' => q[bold red],
'commandnumber_in_prompt' => q[0],
'connect_to_internet_ok' => q[0],
'cpan_home' => q[__PREFIXBASE__/cpan],
'dontload_hash' => { },
'ftp' => q[/usr/bin/ftp],
'patch' => q[/usr/bin/patch],
'ftp_passive' => q[1],
'ftp_proxy' => q[],
'getcwd' => q[cwd],
'gpg' => q[/usr/bin/gpg],
'gzip' => q[/bin/gzip],
'halt_on_failure' => q[0],
'histfile' => q[__PREFIXBASE__/cpan/histfile],
'histsize' => q[100],
'http_proxy' => q[],
'inactivity_timeout' => q[0],
'index_expire' => q[0],
'inhibit_startup_message' => q[0],
'keep_source_where' => q[__PREFIXBASE__/cpan/sources],
'load_module_verbosity' => q[v],
'lynx' => q[],
'make' => q[/usr/bin/make],
'make_arg' => q[],
'make_install_arg' => q[],
'make_install_make_command' => q[/usr/bin/make],
'makepl_arg' => q[],
'mbuild_arg' => q[],
'mbuild_install_arg' => q[],
'mbuild_install_build_command' => q[./Build],
'mbuildpl_arg' => q[],
'ncftp' => q[],
'ncftpget' => q[],
'no_proxy' => q[],
'pager' => q[/usr/bin/less],
'perl5lib_verbosity' => q[v],
'prefer_installer' => q[MB],
'prefs_dir' => q[__DISTROPREFSDIR__],
'prerequisites_policy' => q[follow],
'scan_cache' => q[atstart],
'shell' => q[/bin/bash],
'show_unparsable_versions' => q[0],
'show_upload_date' => q[0],
'show_zero_versions' => q[0],
'tar' => q[/bin/tar],
'tar_verbosity' => q[v],
'term_is_latin' => q[0],
'term_ornaments' => q[1],
'test_report' => q[0],
'trust_test_report_history' => q[0],
'unzip' => q[],
'urllist' => [qw[__MIRRORS__]],
'use_sqlite' => q[0],
'version_timeout' => q[15],
'wget' => q[/usr/bin/wget],
'yaml_load_code' => q[0],
'yaml_module' => q[YAML],
};
1;