On Fri, Nov 27, 2009 at 02:24:53PM +0800, Sergey Aleynikov wrote:
> Hello,
> 
> I'm just entering automated perl testing, so have a question related
> to this topic. I want to test as much possible combinations as
> possible on a single machine,
> but there's no glue what really matters and what - not. So, currently
> i've chosen pairs mymalloc/nothreads and nomymalloc/threaded for perls
> 5.8.8, 5.8.9, 5.10.1, 5.11.2, on
> i386 and amd64 Freebsd systems. But, is this a correct choice?
> Shouldn't i, for example, add 64-bit-int options to any of theese
> configs, or make new triplets (so, varying 3 params)?
> 
> Probably, this should go to a new section of testing faq?

I'm not going to address the question directly as Andreas gave a good answer.

This post, and Andreas's answer, did remind me to post my
build-perl-variants script that I've used to generate automate the
creation of multiple perl variants for testing (NYTProf etc).

Currently it build variants of these config values: usemymalloc
DEBUGGING usemultiplicity uselongdouble useshrplib usethreads
use64bitall. With just that set it creates 128 perl builds!
Add one more, like -Dmad, and you'll get 256 perl builds.
Andreas's point should be clear!

On the other hand, I have found it useful.

I've meant to add command line options to enable building with a subset
of config values (i.e. "exclude uselongdouble & use64bitall" and "only
use usethreads & useshrplib & debugging") but haven't got round to it
yet -- I just hack the source instead :)

If anyone hacks on this please send the patches to me.
Perhaps it'll get added to the perl distribution one day.

Tim.

#!/usr/bin/env perl

use strict;
use warnings;

=head1 NAME

build-perl-variants - build, optionally test, and install multiple variants of 
perl

=head1 SYNOPSIS

  build-perl-variants [options] root_dir

For example:

  $ cd perl-5.11.1
  $ build-perl-variants ~/myperls
  ... a long time passes ...
  $ ls ~/myperls
  perl-5.11.1-debug-longdouble-noshrplib-nothreads   
perl-5.11.1-nodebug-longdouble-noshrplib-nothreads
  perl-5.11.1-debug-longdouble-noshrplib-threads     
perl-5.11.1-nodebug-longdouble-noshrplib-threads
  perl-5.11.1-debug-longdouble-shrplib-nothreads     
perl-5.11.1-nodebug-longdouble-shrplib-threads
  perl-5.11.1-debug-nolongdouble-noshrplib-nothreads 
perl-5.11.1-nodebug-nolongdouble-noshrplib-nothreads
  perl-5.11.1-debug-nolongdouble-shrplib-nothreads   
perl-5.11.1-nodebug-nolongdouble-noshrplib-threads
  perl-5.11.1-debug-nolongdouble-shrplib-threads     
perl-5.11.1-nodebug-nolongdouble-shrplib-nothreads

=head1 DESCRIPTION

This utility is designed to make it easy to build and install multiple variant
configurations of a single perl version for testing.

It knows about a small set of the possible configuation options:

    usethreads
    usemultiplicity
    useshrplib
    use64bitall
    uselongdouble
    usemymalloc
    DEBUGGING

By default all options are included in the set from which all the combinations
are calculated.

Since the goal is testing it errs on the side of caution: to be immune from
defaults it uses C<-Ufoo> to disable the options that aren't being enabled, and
it installs the perls into unambiguously named directories.

=head1 TODO

Add way to pass extra options, like -Dusedevel -Uversiononly

Provide a way to specify variants to include or exclude.

Detect Ctrl-C and kill off the builds. It doesn't work at the moment.

=head2 Other Ideas

Do an initial trial Configure run and parse the generated config.sh to
determine what variants can't be built on this platform and eliminate them from
the trial set.

=head1 AUTHOR

Tim Bunce.

=head1 COPYRIGHT

Copyright (c) 1994-2009 Tim Bunce. Ireland.  All rights reserved.
You may distribute under the terms of either the GNU General Public
License or the Artistic License, as specified in the Perl 5.10.0 README file.

=cut

use Getopt::Long qw(:config require_order);
use Cwd;
use Data::Dumper;

my %all_variants = (
    usethreads => {},
    usemultiplicity => {},
    useshrplib => {},
    use64bitall => {},
    uselongdouble => {},
    usemymalloc => {},
    DEBUGGING  => { tag => 'debug' },
);

GetOptions(
    'name=s'    => \my $opt_name,        # eg myperl-x.y.z
    'only=s'    => \my $opt_only,        # only build variants matching this 
regex
    'skip=s'    => \my $opt_skip,        # don't build variants matching this 
regex
    'test!'     => \(my $opt_test = 1),  # run make test, --notest to disable
    'jobs=i'    => \(my $opt_jobs = 3),  # for $ENV{TEST_JOBS}
    'n!'        => \my $opt_n,           # just list, don't act
) or exit 1;

my $root = shift
    or die "No installation root directory specified\n";
-w $root
    or mkdir($root, 0711)
    or die "Can't create installation root directory '$root': $!\n";

$opt_name ||= do {
    if (open my $fh, '<', 'patchlevel.h') {
        my %patchlevel;
        while (<$fh>) {
            $patchlevel{$1} = $2 if m/define \s+ (\w+) \s+ (\d+)/x;
        }
        "perl-" . join ".", @patchlevel{qw(PERL_REVISION PERL_VERSION 
PERL_SUBVERSION)};
    }
    elsif ($opt_n) {
        "perl-" . join ".", 0, 0, 0;
    }
    else {
        die "Can't open patchlevel.h: $!";
    }
};

my @build_variants = keys %all_variants;
@build_variants = grep { /$opt_only/ } @build_variants
    if $opt_only;
@build_variants = grep { !/$opt_skip/ } @build_variants
    if $opt_skip;

# XXX this doesn't seem able to stop the charging hurd of nested makes
$ENV{PERL_SIGNALS} = 'unsafe';
my $aborted = 0;
sub catch_sigint { $aborted++; die "Aborted" };
use POSIX qw(SIGINT);
POSIX::sigaction(SIGINT, POSIX::SigAction->new(\&catch_sigint)) or do {
    warn "Error setting SIGINT handler: $!\n";
    $SIG{INT} = \&catch_sigint;
};


my $powerset = powerset(@build_variants);
printf "Building %d variants using combinations of: %s\n",
    scalar @$powerset, "@build_variants";

my %status;
foreach my $set (@$powerset) {
    my %enabled = map { $_=>1 } @$set;
    my %option_state = map { $_ => ($enabled{$_}) ? 1 : 0 } @build_variants;

    my @options;
    my $tag = '';
    while ( my ($option, $enabled) = each %option_state ) {
        my $opt = $all_variants{$option}{tag}
            || do { $option =~ m/^use(.*)/ ? $1 : $option };
        if ($enabled) {
            push @options, "-D$option";
            $tag .= "-$opt";
        }
        else {
            push @options, "-U$option";
            $tag .= "-no$opt";
        }
    }

    eval {
        warn "*** Building $opt_name$tag\n";
        build_a_perl_variant($tag, \...@options);
        warn "\n";
    } unless $opt_n;
    $status{"$opt_name$tag"} = $@;
    
    last if $aborted;
}

foreach my $tag (sort keys %status) {
    printf "%s: %s\n", $tag, $status{$tag} || 'ok';
}


exit 0;


sub build_a_perl_variant {
    my ($tag, $options) = @_;

    my $name = "$opt_name$tag";
    my $prefix = "$root/$name";

    my $logfile = "build$tag.log";
    my $logit = ">> $logfile 2>&1";
    unlink $logfile;

    run("make distclean > /dev/null 2>&1 || true") if -f "Makefile";
    run("./Configure -des @$options -Dusedevel -Dprefix=$prefix $logit");
    run("make $logit");
    if ($opt_test) {
        local $ENV{TEST_JOBS} = $opt_jobs if $opt_jobs;
        run("make test $logit") if $opt_test;
    }
    # just install perl, not the docs
    run("make install.perl $logit");
}


sub run {
    my ($cmd) = @_;
    die "Aborted\n" if $aborted;
    warn "\t$cmd\n";
    system($cmd) == 0 or die "ERROR status returned from $cmd\n";
}


# mjd's powerset implementation.  See http://perl.plover.com/LOD/199803.html
# And http://search.cpan.org/perldoc?List::PowerSet
sub powerset {
  return [[]] if @_ == 0;
  my $first = shift;
  my $pow = &powerset;
  [ map { [$first, @$_ ], [ @$_] } @$pow ];
}

Reply via email to