699 lines
15 KiB
Perl
699 lines
15 KiB
Perl
# Licensed to the Apache Software Foundation (ASF) under one or more
|
|
# contributor license agreements. See the NOTICE file distributed with
|
|
# this work for additional information regarding copyright ownership.
|
|
# The ASF licenses this file to You under the Apache License, Version 2.0
|
|
# (the "License"); you may not use this file except in compliance with
|
|
# the License. You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
#
|
|
package Apache::TestBuild;
|
|
|
|
use strict;
|
|
use warnings FATAL => 'all';
|
|
|
|
use subs qw(system chdir
|
|
info warning);
|
|
|
|
use Config;
|
|
use File::Spec::Functions;
|
|
use File::Path ();
|
|
use Cwd ();
|
|
|
|
use constant DRYRUN => 0;
|
|
|
|
my @min_modules = qw(access auth log-config env mime setenvif
|
|
mime autoindex dir alias);
|
|
|
|
my %shared_modules = (
|
|
min => join(' ', @min_modules),
|
|
);
|
|
|
|
my %configs = (
|
|
all => {
|
|
'apache-1.3' => [],
|
|
'httpd-2.0' => enable20(qw(modules=all proxy)),
|
|
},
|
|
most => {
|
|
'apache-1.3' => [],
|
|
'httpd-2.0' => enable20(qw(modules=most)),
|
|
},
|
|
min => {
|
|
'apache-1.3' => [],
|
|
'httpd-2.0' => enable20(@min_modules),
|
|
},
|
|
exp => {
|
|
'apache-1.3' => [],
|
|
'httpd-2.0' => enable20(qw(example case_filter
|
|
case_filter_in cache
|
|
echo deflate bucketeer)),
|
|
},
|
|
);
|
|
|
|
my %builds = (
|
|
default => {
|
|
cflags => '-Wall',
|
|
config => {
|
|
'apache-1.3' => [],
|
|
'httpd-2.0' => [],
|
|
},
|
|
},
|
|
debug => {
|
|
cflags => '-g',
|
|
config => {
|
|
'apache-1.3' => [],
|
|
'httpd-2.0' => [qw(--enable-maintainer-mode)],
|
|
},
|
|
},
|
|
prof => {
|
|
cflags => '-pg -DGPROF',
|
|
},
|
|
shared => {
|
|
config => {
|
|
'apache-1.3' => [],
|
|
'httpd-2.0' => enable20_shared('all'),
|
|
},
|
|
},
|
|
mostshared => {
|
|
config => {
|
|
'apache-1.3' => [],
|
|
'httpd-2.0' => enable20_shared('most'),
|
|
},
|
|
},
|
|
minshared => {
|
|
config => {
|
|
'apache-1.3' => [],
|
|
'httpd-2.0' => enable20_shared('min'),
|
|
},
|
|
},
|
|
static => {
|
|
},
|
|
);
|
|
|
|
my %mpms = (
|
|
default => [qw(prefork worker)],
|
|
MSWin32 => [qw(winnt)],
|
|
);
|
|
|
|
my @cvs = qw(httpd-2.0 apache-1.3);
|
|
|
|
my @dirs = qw(build tar src install);
|
|
|
|
sub enable20 {
|
|
[ map { "--enable-$_" } @_ ];
|
|
}
|
|
|
|
sub enable20_shared {
|
|
my $name = shift;
|
|
my $modules = $shared_modules{$name} || $name;
|
|
enable20(qq(mods-shared="$modules"));
|
|
}
|
|
|
|
sub default_mpms {
|
|
$mpms{ $^O } || $mpms{'default'};
|
|
}
|
|
|
|
sub default_dir {
|
|
my($self, $dir) = @_;
|
|
$self->{$dir} ||= catdir $self->{prefix}, $dir,
|
|
}
|
|
|
|
sub new {
|
|
my $class = shift;
|
|
|
|
#XXX: not generating a BUILD script yet
|
|
#this way we can run:
|
|
#perl Apache-Test/lib/Apache/TestBuild.pm --cvsroot=anon --foo=...
|
|
|
|
require Apache::TestConfig;
|
|
require Apache::TestTrace;
|
|
Apache::TestTrace->import;
|
|
|
|
my $self = bless {
|
|
prefix => '/usr/local/apache',
|
|
cwd => Cwd::cwd(),
|
|
cvsroot => 'cvs.apache.org:/home/cvs',
|
|
cvs => \@cvs,
|
|
cvstag => "",
|
|
ssldir => "",
|
|
mpms => default_mpms(),
|
|
make => $Config{make},
|
|
builds => {},
|
|
name => "",
|
|
extra_config => {
|
|
'httpd-2.0' => [],
|
|
},
|
|
@_,
|
|
}, $class;
|
|
|
|
#XXX
|
|
if (my $c = $self->{extra_config}->{'2.0'}) {
|
|
$self->{extra_config}->{'httpd-2.0'} = $c;
|
|
}
|
|
|
|
for my $dir (@dirs) {
|
|
$self->default_dir($dir);
|
|
}
|
|
|
|
if ($self->{ssldir}) {
|
|
push @{ $self->{extra_config}->{'httpd-2.0'} },
|
|
'--enable-ssl', "--with-ssl=$self->{ssldir}";
|
|
}
|
|
|
|
$self;
|
|
}
|
|
|
|
sub init {
|
|
my $self = shift;
|
|
|
|
for my $dir (@dirs) {
|
|
mkpath($self->{$dir});
|
|
}
|
|
}
|
|
|
|
use subs qw(symlink unlink);
|
|
use File::Basename;
|
|
use File::Find;
|
|
|
|
sub symlink_tree {
|
|
my $self = shift;
|
|
|
|
my $httpd = 'httpd';
|
|
my $install = "$self->{install}/bin/$httpd";
|
|
my $source = "$self->{build}/.libs/$httpd";
|
|
|
|
unlink $install;
|
|
symlink $source, $install;
|
|
|
|
my %dir = (apr => 'apr',
|
|
aprutil => 'apr-util');
|
|
|
|
for my $libname (qw(apr aprutil)) {
|
|
my $lib = "lib$libname.so.0.0.0";
|
|
my $install = "$self->{install}/lib/$lib";
|
|
my $source = "$self->{build}/srclib/$dir{$libname}/.libs/$lib";
|
|
|
|
unlink $install;
|
|
symlink $source, $install;
|
|
}
|
|
|
|
$install = "$self->{install}/modules";
|
|
$source = "$self->{build}/modules";
|
|
|
|
for (<$install/*.so>) {
|
|
unlink $_;
|
|
}
|
|
|
|
finddepth(sub {
|
|
return unless /\.so$/;
|
|
my $file = "$File::Find::dir/$_";
|
|
symlink $file, "$install/$_";
|
|
}, $source);
|
|
}
|
|
|
|
sub unlink {
|
|
my $file = shift;
|
|
|
|
if (-e $file) {
|
|
print "unlink $file\n";
|
|
}
|
|
else {
|
|
print "$file does not exist\n";
|
|
}
|
|
CORE::unlink($file);
|
|
}
|
|
|
|
sub symlink {
|
|
my($from, $to) = @_;
|
|
print "symlink $from => $to\n";
|
|
unless (-e $from) {
|
|
print "source $from does not exist\n";
|
|
}
|
|
my $base = dirname $to;
|
|
unless (-e $base) {
|
|
print "target dir $base does not exist\n";
|
|
}
|
|
CORE::symlink($from, $to) or die $!;
|
|
}
|
|
|
|
sub cvs {
|
|
my $self = shift;
|
|
|
|
my $cmd = "cvs -d $self->{cvsroot} @_";
|
|
|
|
if (DRYRUN) {
|
|
info "$cmd";
|
|
}
|
|
else {
|
|
system $cmd;
|
|
}
|
|
}
|
|
|
|
my %cvs_names = (
|
|
'2.0' => 'httpd-2.0',
|
|
'1.3' => 'apache-1.3',
|
|
);
|
|
|
|
my %cvs_snames = (
|
|
'2.0' => 'httpd',
|
|
'1.3' => 'apache',
|
|
);
|
|
|
|
sub cvs_up {
|
|
my($self, $version) = @_;
|
|
|
|
my $name = $cvs_names{$version};
|
|
|
|
my $dir = $self->srcdir($version);
|
|
|
|
if ($self->{cvsroot} eq 'anon') {
|
|
$self->{cvsroot} = ':pserver:anoncvs@cvs.apache.org:/home/cvspublic';
|
|
unless (-d $dir) {
|
|
#XXX do something better than doesn't require prompt if
|
|
#we already have an entry in ~/.cvspass
|
|
#$self->cvs('login');
|
|
|
|
warning "may need to run the following command ",
|
|
"(password is 'anoncvs')";
|
|
warning "cvs -d $self->{cvsroot} login";
|
|
}
|
|
}
|
|
|
|
if (-d $dir) {
|
|
chdir $dir;
|
|
$self->cvs(up => "-dP $self->{cvstag}");
|
|
return;
|
|
}
|
|
|
|
my $co = checkout($name);
|
|
$self->$co($name, $dir);
|
|
|
|
my $post = post_checkout($name);
|
|
$self->$post($name, $dir);
|
|
}
|
|
|
|
sub checkout_httpd_2_0 {
|
|
my($self, $name, $dir) = @_;
|
|
|
|
my $tag = $self->{cvstag};
|
|
|
|
$self->cvs(co => "-d $dir $tag $name");
|
|
chdir "$dir/srclib";
|
|
$self->cvs(co => "$tag apr apr-util");
|
|
}
|
|
|
|
sub checkout_apache_1_3 {
|
|
my($self, $name, $dir) = @_;
|
|
|
|
$self->cvs(co => "-d $dir $self->{cvstag} $name");
|
|
}
|
|
|
|
sub post_checkout_httpd_2_0 {
|
|
my($self, $name, $dir) = @_;
|
|
}
|
|
|
|
sub post_checkout_apache_1_3 {
|
|
}
|
|
|
|
sub canon {
|
|
my $name = shift;
|
|
return $name unless $name;
|
|
$name =~ s/[.-]/_/g;
|
|
$name;
|
|
}
|
|
|
|
sub checkout {
|
|
my $name = canon(shift);
|
|
\&{"checkout_$name"};
|
|
}
|
|
|
|
sub post_checkout {
|
|
my $name = canon(shift);
|
|
\&{"post_checkout_$name"};
|
|
}
|
|
|
|
sub cvs_update {
|
|
my $self = shift;
|
|
|
|
my $cvs = shift || $self->{cvs};
|
|
|
|
chdir $self->{src};
|
|
|
|
for my $name (@$cvs) {
|
|
$self->cvs_up($name);
|
|
}
|
|
}
|
|
|
|
sub merge_build {
|
|
my($self, $version, $builds, $configs) = @_;
|
|
|
|
my $b = {
|
|
cflags => $builds{default}->{cflags},
|
|
config => [ @{ $builds{default}->{config}->{$version} } ],
|
|
};
|
|
|
|
for my $name (@$builds) {
|
|
next if $name eq 'default'; #already have this
|
|
|
|
if (my $flags = $builds{$name}->{cflags}) {
|
|
$b->{cflags} .= " $flags";
|
|
}
|
|
if (my $cfg = $builds{$name}->{config}) {
|
|
if (my $vcfg = $cfg->{$version}) {
|
|
push @{ $b->{config} }, @$vcfg;
|
|
}
|
|
}
|
|
}
|
|
|
|
for my $name (@$configs) {
|
|
my $cfg = $configs{$name}->{$version};
|
|
next unless $cfg;
|
|
push @{ $b->{config} }, @$cfg;
|
|
}
|
|
|
|
if (my $ex = $self->{extra_config}->{$version}) {
|
|
push @{ $b->{config} }, @$ex;
|
|
}
|
|
|
|
if (my $ex = $self->{extra_cflags}->{$version}) {
|
|
$b->{config} .= " $ex";
|
|
}
|
|
|
|
$b;
|
|
}
|
|
|
|
my @srclib_dirs = qw(
|
|
apr apr-util apr-util/xml/expat pcre
|
|
);
|
|
|
|
sub install_name {
|
|
my($self, $builds, $configs, $mpm) = @_;
|
|
|
|
return $self->{name} if $self->{name};
|
|
|
|
my $name = join '-', $mpm, @$builds, @$configs;
|
|
|
|
if (my $tag = $self->cvs_name) {
|
|
$name .= "-$tag";
|
|
}
|
|
|
|
$name;
|
|
}
|
|
|
|
#currently the httpd-2.0 build does not properly support static linking
|
|
#of ssl libs, force the issue
|
|
sub add_ssl_libs {
|
|
my $self = shift;
|
|
|
|
my $ssldir = $self->{ssldir};
|
|
|
|
return unless $ssldir and -d $ssldir;
|
|
|
|
my $name = $self->{current_install_name};
|
|
|
|
my $ssl_mod = "$name/modules/ssl";
|
|
info "editing $ssl_mod/modules.mk";
|
|
|
|
if (DRYRUN) {
|
|
return;
|
|
}
|
|
|
|
my $ssl_mk = "$self->{build}/$ssl_mod/modules.mk";
|
|
|
|
open my $fh, $ssl_mk or die "open $ssl_mk: $!";
|
|
my @lines = <$fh>;
|
|
close $fh;
|
|
|
|
for (@lines) {
|
|
next unless /SH_LINK/;
|
|
chomp;
|
|
$_ .= " -L$ssldir -lssl -lcrypto\n";
|
|
info 'added ssl libs';
|
|
last;
|
|
}
|
|
|
|
open $fh, '>', $ssl_mk or die $!;
|
|
print $fh join "\n", @lines;
|
|
close $fh;
|
|
}
|
|
|
|
sub cvs_name {
|
|
my $self = shift;
|
|
|
|
if (my $tag = $self->{cvstag}) {
|
|
$tag =~ s/^-[DAr]//;
|
|
$tag =~ s/\"//g;
|
|
$tag =~ s,[/ :],_,g; #-D"03/29/02 07:00pm"
|
|
return $tag;
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
sub srcdir {
|
|
my($self, $src) = @_;
|
|
|
|
my $prefix = "";
|
|
if ($src =~ s/^(apache|httpd)-//) {
|
|
$prefix = $1;
|
|
}
|
|
else {
|
|
$prefix = $cvs_snames{$src};
|
|
}
|
|
|
|
if ($src =~ /^\d\.\d$/) {
|
|
#release version will be \d\.\d\.\d+
|
|
if (my $tag = $self->cvs_name) {
|
|
$src .= "-$tag";
|
|
}
|
|
$src .= '-cvs';
|
|
}
|
|
|
|
join '-', $prefix, $src;
|
|
}
|
|
|
|
sub configure_httpd_2_0 {
|
|
my($self, $src, $builds, $configs, $mpm) = @_;
|
|
|
|
$src = $self->srcdir($src);
|
|
|
|
chdir $self->{build};
|
|
|
|
my $name = $self->install_name($builds, $configs, $mpm);
|
|
|
|
$self->{current_install_name} = $name;
|
|
|
|
$self->{builds}->{$name} = 1;
|
|
|
|
if ($self->{fresh}) {
|
|
rmtree($name);
|
|
}
|
|
else {
|
|
if (-e "$name/.DONE") {
|
|
warning "$name already configured";
|
|
warning "rm $name/.DONE to force";
|
|
return;
|
|
}
|
|
}
|
|
|
|
my $build = $self->merge_build('httpd-2.0', $builds, $configs);
|
|
|
|
$ENV{CFLAGS} = $build->{cflags};
|
|
info "CFLAGS=$ENV{CFLAGS}";
|
|
|
|
my $prefix = "$self->{install}/$name";
|
|
|
|
rmtree($prefix) if $self->{fresh};
|
|
|
|
my $source = "$self->{src}/$src";
|
|
|
|
my @args = ("--prefix=$prefix",
|
|
"--with-mpm=$mpm",
|
|
"--srcdir=$source",
|
|
@{ $build->{config} });
|
|
|
|
chdir $source;
|
|
system "./buildconf";
|
|
|
|
my $cmd = "$source/configure @args";
|
|
|
|
chdir $self->{build};
|
|
|
|
mkpath($name);
|
|
chdir $name;
|
|
|
|
for my $dir (@srclib_dirs) {
|
|
mkpath("srclib/$dir");
|
|
}
|
|
|
|
for my $dir (qw(build docs/conf)) {
|
|
mkpath($dir);
|
|
}
|
|
|
|
system $cmd;
|
|
|
|
open FH, ">.DONE" or die "open .DONE: $!";
|
|
print FH scalar localtime;
|
|
close FH;
|
|
|
|
chdir $self->{prefix};
|
|
|
|
$self->add_ssl_libs;
|
|
}
|
|
|
|
sub make {
|
|
my($self, @cmds) = @_;
|
|
|
|
push @cmds, 'all' unless @cmds;
|
|
|
|
for my $name (keys %{ $self->{builds} }) {
|
|
chdir "$self->{build}/$name";
|
|
for my $cmd (@cmds) {
|
|
system "$self->{make} $cmd";
|
|
}
|
|
}
|
|
}
|
|
|
|
sub system {
|
|
my $cmd = "@_";
|
|
|
|
info $cmd;
|
|
return if DRYRUN;
|
|
|
|
unless (CORE::system($cmd) == 0) {
|
|
my $status = $? >> 8;
|
|
die "system $cmd failed (exit status=$status)";
|
|
}
|
|
}
|
|
|
|
sub chdir {
|
|
my $dir = shift;
|
|
info "chdir $dir";
|
|
CORE::chdir $dir;
|
|
}
|
|
|
|
sub mkpath {
|
|
my $dir = shift;
|
|
|
|
return if -d $dir;
|
|
info "mkpath $dir";
|
|
|
|
return if DRYRUN;
|
|
File::Path::mkpath([$dir], 1, 0755);
|
|
}
|
|
|
|
sub rmtree {
|
|
my $dir = shift;
|
|
|
|
return unless -d $dir;
|
|
info "rmtree $dir";
|
|
|
|
return if DRYRUN;
|
|
File::Path::rmtree([$dir], 1, 1);
|
|
}
|
|
|
|
sub generate_script {
|
|
my($class, $file) = @_;
|
|
|
|
$file ||= catfile 't', 'BUILD';
|
|
|
|
my $content = join '', <DATA>;
|
|
|
|
Apache::Test::basic_config()->write_perlscript($file, $content);
|
|
}
|
|
|
|
unless (caller) {
|
|
$INC{'Apache/TestBuild.pm'} = __FILE__;
|
|
eval join '', <DATA>;
|
|
die $@ if $@;
|
|
}
|
|
|
|
1;
|
|
__DATA__
|
|
use strict;
|
|
use warnings FATAL => 'all';
|
|
|
|
use lib qw(Apache-Test/lib);
|
|
use Apache::TestBuild ();
|
|
use Getopt::Long qw(GetOptions);
|
|
use Cwd ();
|
|
|
|
my %options = (
|
|
prefix => "checkout/build/install prefix",
|
|
ssldir => "enable ssl with given directory",
|
|
cvstag => "checkout with given cvs tag",
|
|
cvsroot => "use 'anon' for anonymous cvs",
|
|
version => "apache version (e.g. '2.0')",
|
|
mpms => "MPMs to build (e.g. 'prefork')",
|
|
flavor => "build flavor (e.g. 'debug shared')",
|
|
modules => "enable modules (e.g. 'all exp')",
|
|
name => "change name of the build/install directory",
|
|
);
|
|
|
|
my %opts;
|
|
|
|
Getopt::Long::Configure(qw(pass_through));
|
|
#XXX: could be smarter here, being lazy for the moment
|
|
GetOptions(\%opts, map "$_=s", sort keys %options);
|
|
|
|
if (@ARGV) {
|
|
print "passing extra args to configure: @ARGV\n";
|
|
}
|
|
|
|
my $home = $ENV{HOME};
|
|
|
|
$opts{prefix} ||= join '/', Cwd::cwd(), 'farm';
|
|
#$opts{ssldir} ||= '';
|
|
#$opts{cvstag} ||= '';
|
|
#$opts{cvsroot} ||= '';
|
|
$opts{version} ||= '2.0';
|
|
$opts{mpms} ||= 'prefork';
|
|
$opts{flavor} ||= 'debug-shared';
|
|
$opts{modules} ||= 'all-exp';
|
|
|
|
#my @versions = qw(2.0);
|
|
|
|
#my @mpms = qw(prefork worker perchild);
|
|
|
|
#my @flavors = ([qw(debug shared)], [qw(prof shared)],
|
|
# [qw(debug static)], [qw(prof static)]);
|
|
|
|
#my @modules = ([qw(all exp)]);
|
|
|
|
my $split = sub { split '-', delete $opts{ $_[0] } };
|
|
|
|
my @versions = $opts{version};
|
|
|
|
my @mpms = $split->('mpms');
|
|
|
|
my @flavors = ([ $split->('flavor') ]);
|
|
|
|
my @modules = ([ $split->('modules') ]);
|
|
|
|
my $tb = Apache::TestBuild->new(fresh => 1,
|
|
%opts,
|
|
extra_config => {
|
|
$opts{version} => \@ARGV,
|
|
});
|
|
|
|
$tb->init;
|
|
|
|
for my $version (@versions) {
|
|
$tb->cvs_update([ $version ]);
|
|
|
|
for my $mpm (@mpms) {
|
|
for my $flavor (@flavors) {
|
|
for my $mods (@modules) {
|
|
$tb->configure_httpd_2_0($version, $flavor,
|
|
$mods, $mpm);
|
|
$tb->make(qw(all install));
|
|
}
|
|
}
|
|
}
|
|
}
|