blob: 4afa2b9782fe83aa02bd742933041a7e020c5661 [file] [log] [blame]
use strict;
use Apache2;
use ModPerl::MM;
use 5.005;
use Apache::Test5005compat;
use Apache::TestMM qw(test clean);
use Apache::TestReport ();
use Apache::TestSmoke ();
use Apache::TestRun ();
use Apache::TestConfigPerl ();
use Apache::TestSmokePerl ();
use Apache::TestReportPerl ();
use File::Find qw(finddepth);
use File::Basename;
use Apache::Build;
use constant WIN32 => Apache::Build::WIN32;
use Cwd;
use ExtUtils::XSBuilder::ParseSource;
my $version = "2.XX-dev"; # DUMMY VALUE
my $cwd = WIN32 ?
Win32::GetLongPathName(cwd) : cwd;
$cwd =~ m{^(.+)/glue/perl$} or die "Can't find base directory";
my $base_dir = $1;
my $src_dir = "$base_dir/src";
my $xs_dir = "$base_dir/glue/perl/xsbuilder";
sub slurp($$)
{
open my $file, $_[1] or die "Can't open $_[1]: $!";
read $file, $_[0], -s $file;
}
my ($apache_includes, $apr_libs, $apreq_libname);
if (WIN32) {
# XXX May need fixing, Randy!
slurp my $config => "$base_dir/configure.ac";
$config =~ /^AC_INIT[^,]+,\s*([^,\s]+)/m or
die "Can't find version string";
$version = $1;
slurp my $make => "$base_dir/Makefile";
$make =~ /^APACHE=(\S+)/m or
die "Cannot find top-level Apache directory";
my $apache_dir = $1;
($apache_includes = "-I$apache_dir" . '/include') =~ s!\\!/!g;
($apr_libs = "-L$apache_dir" . '/lib') =~ s!\\!/!g;
$make =~ /^APR_LIB=(\S+)/m or
die "Cannot find apr lib";
$apr_libs .= ' -l' . basename($1, '.lib');
$make =~ /^APU_LIB=(\S+)/m or
die "Cannot find aprutil lib";
$apr_libs .= ' -l' . basename($1, '.lib');
$apreq_libname = 'apreq2';
}
else {
slurp my $config => "$base_dir/config.status";
$config =~ /^s,\@APACHE2_INCLUDES\@,([^,]+)/m or
die "Can't find apache include directory";
$apache_includes = $1;
$config =~ /^s,\@APR_INCLUDES\@,([^,]+)/m or
die "Can't find apache include directory";
$apache_includes .= " $1";
$config =~ /^s,\@APU_INCLUDES\@,([^,]+)/m or
die "Can't find apache include directory";
$apache_includes .= " $1";
$config =~ m/^s,\@APR_LDFLAGS\@,([^,]+)/m or
die "Can't find apr ldflags";
$apr_libs = $1;
$config =~ m/^s,\@APU_LDFLAGS\@,([^,]+)/m or
die "Can't find apu ldflags";
$apr_libs .= " $1";
# need -laprutil befpre -lapr
$config =~ m/^s,\@APU_LDLIBS\@,([^,]+)/m or
die "Can't find apu libraries";
$apr_libs = $1;
$config =~ m/^s,\@APR_LDLIBS\@,([^,]+)/m or
die "Can't find apr libraries";
$apr_libs .= " $1";
$config =~ m/^s,\@APREQ_LIBNAME\@,([^,]+)/m or
die "Can't find apreq libname";
$apreq_libname = $1;
$config =~ m/^s,\@PACKAGE_VERSION\@,([^,]+)/m or
die "Can't find package version";
$version = $1;
}
my $apreq_libs = WIN32 ?
qq{-L$base_dir/win32/libs -llib$apreq_libname } :
qq{-L$src_dir/.libs -l$apreq_libname};
my $mp2_typemaps = Apache::Build->new->typemaps;
package My::ParseSource;
use base qw/ExtUtils::XSBuilder::ParseSource/;
use constant WIN32 => ($^O =~ /Win32/i);
my @dirs = ("$base_dir/src");
sub package {'Apache::libapreq2'}
sub unwanted_includes {[qw/apreq_tables.h apreq_config.h/]}
# ParseSource.pm v 0.23 bug: line 214 should read
# my @dirs = @{$self->include_dirs};
# for now, we override it here just to work around the bug
sub find_includes {
my $self = shift;
return $self->{includes} if $self->{includes};
require File::Find;
my(@dirs) = @{$self->include_dirs};
unless (-d $dirs[0]) {
die "could not find include directory";
}
# print "Will search @dirs for include files...\n" if ($verbose) ;
my @includes;
my $unwanted = join '|', @{$self -> unwanted_includes} ;
for my $dir (@dirs) {
File::Find::finddepth({
wanted => sub {
return unless /\.h$/;
return if ($unwanted && (/^($unwanted)/o));
my $dir = $File::Find::dir;
push @includes, "$dir/$_";
},
follow => not WIN32,
}, $dir);
}
return $self->{includes} = $self -> sort_includes (\@includes) ;
}
sub include_dirs {\@dirs}
package My::WrapXS;
use base qw/ExtUtils::XSBuilder::WrapXS/;
our $VERSION = $version;
##################################################
# Finally, we get to the actual script...
__PACKAGE__ -> run;
my @scripts = ();
use File::Spec::Functions qw(catfile);
File::Find::finddepth(sub {
return unless /(.*?\.pl)\.PL$/;
push @scripts, "$File::Find::dir/$1";
}, '.');
Apache::TestMM::filter_args();
Apache::TestMM::generate_script("t/TEST");
Apache::TestSmokePerl->generate_script;
Apache::TestReportPerl->generate_script;
ModPerl::MM::WriteMakefile(
NAME => 'libapreq2',
DIR => [qw(xs)],
clean => { FILES => "xs t/logs t/TEST @scripts" },
realclean => { FILES => "xsbuilder/tables" },
);
# That's the whole script - below is just a bunch of local overrides
##################################################
sub copy_docs {
my @lines;
my $dfs = '$(DIRFILESEP)';
foreach my $file (@_) {
my @dirs;
$file =~ /(\w+\.pod)$/ or next;
if ($1 eq "Error.pod" or $1 eq "Table.pod") {
push @dirs, "Apache$dfs$_" for qw/Request Cookie Upload/;
push @dirs, join $dfs, qw/Apache Cookie Jar/ if $1 eq "Error.pod";
}
else {
push @dirs, "Apache";
}
push @lines, map <<EOT, @dirs;
subdirs :: \$(INST_LIBDIR)$dfs$_$dfs$1
\$(INST_LIBDIR)$dfs$_$dfs$1: $file
\$(NOECHO) \$(MKPATH) \$(INST_LIBDIR)$dfs$_
\$(CP) $file \$(INST_LIBDIR)$dfs$_$dfs$1
EOT
}
return join "", @lines;
}
sub test_docs {
my ($pods, $tests) = @_;
my $pod2test = Apache::TestConfig::which('pod2test');
unless ($pod2test) {
# try under the perl's bin
require Config;
my $bin = $Config::Config{bin};
$pod2test = catfile $bin, "pod2test";
}
return "" unless $pod2test and -e $pod2test;
return join "", map <<EOT, 0..$#$pods;
$$tests[$_]: $$pods[$_]
\$(FULLPERLRUN) $pod2test $$pods[$_] $$tests[$_]
EOT
}
sub MY::postamble {
my @docs = <docs/*.pod>;
my @tests = @docs;
s/pod$/t/ for @tests;
my $string = copy_docs(@docs);
my $test_docs = test_docs(\@docs, \@tests);
if ($test_docs) {
$string .= $test_docs;
$string .= <<EOT;
doc_test : @tests
\$(FULLPERLRUN) "-Mblib" "-MTest::Harness" "-e" "runtests(\@ARGV)" @tests
test :: doc_test
EOT
} else {
$string .= <<EOT;
test ::
\$(NOECHO) \$(ECHO) pod2test was not found, skipping inlined tests
EOT
}
return $string;
}
sub parsesource_objects {[My::ParseSource->new]}
sub new_typemap {My::TypeMap->new(shift)}
sub h_filename_prefix {'apreq_xs_'}
sub my_xs_prefix {'apreq_xs_'}
sub xs_include_dir { $xs_dir }
sub mod_pod {
my($self, $module, $complete) = @_;
my $dirname = $self->class_dirname($module);
my @parts = split '::', $module;
my $mod_pod = "$dirname/$parts[-1]_pod";
for ($self -> xs_incsrc_dir, @{ $self->{glue_dirs} }) {
my $file = "$_/$mod_pod";
$mod_pod = $file if $complete;
print "mod_pod $mod_pod $file $complete\n" ;
return $mod_pod if -e $file;
}
undef;
}
sub write_docs {
my ($self, $module, $functions) = @_;
my $podfile = $self->mod_pod($module, 1) or return;
my $fh = $self->open_class_file($module, '.pod');
open my $pod, "<", $podfile or die $!;
while (<$pod>) {
print $fh $_;
}
}
sub pm_text {
my($self, $module, $isa, $code) = @_;
my $text = <<"EOF";
$self->{noedit_warning_hash}
package $module;
require DynaLoader ;
use strict;
use warnings FATAL => 'all';
use vars qw{\$VERSION \@ISA} ;
$isa
push \@ISA, 'DynaLoader' ;
\$VERSION = '$version';
bootstrap $module \$VERSION ;
EOF
$text .= <<'EOF';
if ($ENV{MOD_PERL}) {
require mod_perl;
my $env = __PACKAGE__->env || '';
if ($mod_perl::VERSION > 1.99) {
die __PACKAGE__ . ": httpd must load mod_apreq.so first"
if $env ne "Apache::RequestRec";
}
else {
die "Unsupported mod_perl version number: $modperl::VERSION";
}
}
EOF
$text .= <<"EOF";
$code
1;
__END__
EOF
return $text;
}
sub makefilepl_text {
my($self, $class, $deps,$typemap) = @_;
my @parts = split (/::/, $class) ;
my $mmargspath = '../' x @parts ;
$mmargspath .= 'mmargs.pl' ;
my $txt = qq{
$self->{noedit_warning_hash}
use Apache2;
use ModPerl::MM;
local \$MMARGS ;
if (-f '$mmargspath')
{
do '$mmargspath' ;
die \$\@ if (\$\@) ;
}
\$MMARGS ||= {} ;
ModPerl::MM::WriteMakefile(
'NAME' => '$class',
'VERSION' => '$version',
'TYPEMAPS' => [qw(@$mp2_typemaps $typemap)],
'INC' => "-I$base_dir/glue/perl/xs -I$src_dir -I$xs_dir $apache_includes",
'LIBS' => "$apreq_libs $apr_libs",
} ;
$txt .= "'depend' => $deps,\n" if ($deps) ;
$txt .= qq{
\%\$MMARGS,
);
} ;
}
# another bug in WrapXS.pm -
# must insert a space before typemap definition
sub write_typemap
{
my $self = shift;
my $typemap = $self->typemap;
my $map = $typemap->get;
my %seen;
my $fh = $self->open_class_file('', 'typemap');
print $fh "$self->{noedit_warning_hash}\n";
while (my($type, $t) = each %$map) {
my $class = $t -> {class} ;
$class ||= $type;
next if $seen{$type}++ || $typemap->special($class);
my $typemap = $t -> {typemapid} ;
if ($class =~ /::/) {
next if $seen{$class}++ ;
$class =~ s/::$// ;
print $fh "$class\t$typemap\n";
}
else {
print $fh "$type\t$typemap\n";
}
}
my $typemap_code = $typemap -> typemap_code ;
foreach my $dir ('INPUT', 'OUTPUT') {
print $fh "\n$dir\n" ;
while (my($type, $code) = each %{$typemap_code}) {
print $fh "$type\n\t$code->{$dir}\n\n" if ($code->{$dir}) ;
}
}
close $fh;
}
package My::TypeMap;
use base 'ExtUtils::XSBuilder::TypeMap';
sub null_type {
my($self, $type) = @_;
my $t = $self->get->{$type};
my $class = $t -> {class} ;
if ($class =~ /APREQ_COOKIE_VERSION/) {
return 'APREQ_COOKIE_VERSION_DEFAULT';
}
else {
return $self->SUPER::null_type($type);
}
}
# XXX this needs serious work
sub typemap_code
{
{
T_APREQ_COOKIE => {
INPUT => '$var = apreq_xs_sv2(cookie,$arg)',
perl2c => 'apreq_xs_sv2(cookie,sv)',
OUTPUT => '$arg = apreq_xs_2sv($var,"\${ntype}\");',
c2perl => 'apreq_xs_2sv(ptr,\"$class\")',
},
T_APREQ_PARAM => {
INPUT => '$var = apreq_xs_sv2param($arg)',
perl2c => 'apreq_xs_sv2param(sv)',
OUTPUT => '$arg = apreq_xs_param2sv($var);',
c2perl => 'apreq_xs_param2sv(ptr)',
},
T_APREQ_REQUEST => {
INPUT => '$var = apreq_xs_sv2(request,$arg)',
perl2c => 'apreq_xs_sv2(request,sv)',
OUTPUT => '$arg = apreq_xs_2sv($var,\"${ntype}\");',
c2perl => 'apreq_xs_2sv(ptr,\"$class\")',
},
T_APREQ_JAR => {
INPUT => '$var = apreq_xs_sv2(jar,$arg)',
perl2c => 'apreq_xs_sv2(jar,sv)',
OUTPUT => '$arg = apreq_xs_2sv($var,\"${ntype}\");',
c2perl => 'apreq_xs_2sv(ptr,\"$class\")',
},
T_APREQ_COOKIE_VERSION => {
INPUT => '$var = ((apreq_cookie_version_t)SvTRUE($arg))',
OUTPUT => '$arg = boolSV((bool)$var);',
},
T_HASHOBJ => {
INPUT => <<'EOT', # '$var = modperl_hash_tied_object(aTHX_ \"${ntype}\", $arg)'
if (sv_derived_from($arg, \"${ntype}\")) {
if (SVt_PVHV == SvTYPE(SvRV($arg))) {
SV *hv = SvRV($arg);
MAGIC *mg;
if (SvMAGICAL(hv)) {
if ((mg = mg_find(hv, PERL_MAGIC_tied))) {
$var = (void *)MgObjIV(mg);
}
else {
Perl_warn(aTHX_ \"Not a tied hash: (magic=%c)\", mg);
$var = NULL;
}
}
else {
Perl_warn(aTHX_ \"SV is not tied\");
$var = NULL;
}
}
else {
$var = (void *)SvObjIV($arg);
}
}
else {
Perl_croak(aTHX_
\"argument is not a blessed reference \"
\"(expecting an %s derived object)\", \"${ntype}\");
}
EOT
OUTPUT => <<'EOT', # '$arg = modperl_hash_tie(aTHX_ \"${ntype}\", $arg, $var);'
{
SV *hv = (SV*)newHV();
SV *rsv = $arg;
sv_setref_pv(rsv, \"${ntype}\", $var);
sv_magic(hv, rsv, PERL_MAGIC_tied, Nullch, 0);
$arg = SvREFCNT_inc(sv_bless(sv_2mortal(newRV_noinc(hv)),
gv_stashpv(\"${ntype}\", TRUE)));
}
EOT
},
}
}