blob: 849f35ea714d6a9fe9dbefdd1f0ec8af7fda467f [file] [log] [blame]
# please insert nothing before this line: -*- mode: cperl; cperl-indent-level: 4; cperl-continued-statement-offset: 4; indent-tabs-mode: nil -*-
# 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 ModPerl::BuildMM;
use strict;
use warnings;
use ExtUtils::MakeMaker ();
use Cwd ();
use File::Spec::Functions qw(catdir catfile splitdir);
use File::Basename;
use File::Find;
use Apache2::Build ();
use ModPerl::MM;
use constant WIN32 => Apache2::Build::WIN32;
use constant CYGWIN => Apache2::Build::CYGWIN;
our %PM; #add files to installation
# MM methods that this package overrides
no strict 'refs';
my $stash = \%{__PACKAGE__ . '::MY::'};
my @methods = grep *{$stash->{$_}}{CODE}, keys %$stash;
ModPerl::MM::override_eu_mm_mv_all_methods(@methods);
use strict 'refs';
my $apache_test_dir = catdir Cwd::getcwd(), "Apache-Test", "lib";
#to override MakeMaker MOD_INSTALL macro
sub mod_install {
q{$(PERL) -I$(INST_LIB) -I$(PERL_LIB) \\}."\n" .
qq{-I$apache_test_dir -MModPerl::BuildMM \\}."\n" .
q{-e "ExtUtils::Install::install({@ARGV},'$(VERBINST)',0,'$(UNINST)');"}."\n";
}
my $build;
sub build_config {
my $key = shift;
$build ||= Apache2::Build->build_config;
return $build unless $key;
$build->{$key};
}
#the parent WriteMakefile moves MY:: methods into a different class
#so alias them each time WriteMakefile is called in a subdir
sub my_import {
no strict 'refs';
my $stash = \%{__PACKAGE__ . '::MY::'};
for my $sym (keys %$stash) {
next unless *{$stash->{$sym}}{CODE};
my $name = "MY::$sym";
undef &$name if defined &$name;
*$name = *{$stash->{$sym}}{CODE};
}
}
sub WriteMakefile {
my %args = @_;
$build ||= build_config();
ModPerl::MM::my_import(__PACKAGE__);
my $inc = $args{INC} || '';
$inc = $args{INC} if $args{INC};
$inc .= " " . $build->inc;
if (my $glue_inc = $build->{MP_XS_GLUE_DIR}) {
for (split /\s+/, $glue_inc) {
$inc .= " -I$_";
}
}
my $libs;
my @libs = ();
push @libs, $args{LIBS} if $args{LIBS};
if (Apache2::Build::BUILD_APREXT) {
# in order to decouple APR/APR::* from mod_perl.so,
# link these modules against the static MP_APR_LIB lib,
# rather than the mod_perl lib (which would demand mod_perl.so
# be available). For other modules, use mod_perl.lib as
# usual. This is done for APR in xs/APR/APR/Makefile.PL.
my $name = $args{NAME};
if ($name =~ /^APR::\w+$/) {
# For cygwin compatibility, the order of the libs should be
# <mod_perl libs> <apache libs>
@libs = ($build->mp_apr_lib, $build->apache_libs);
}
else {
@libs = ($build->modperl_libs, $build->apache_libs);
}
}
else {
@libs = ($build->modperl_libs, $build->apache_libs);
}
$libs = join ' ', @libs;
my $ccflags;
$ccflags = $args{CCFLAGS} if $args{CCFLAGS};
$ccflags = " " . $build->perl_ccopts . $build->ap_ccopts;
my $optimize;
$optimize = $args{OPTIMIZE} if $args{OPTIMIZE};
$optimize = " " . $build->perl_config('optimize');
my $lddlflags;
$lddlflags = $args{LDDLFLAGS} if $args{LDDLFLAGS};
$lddlflags = " " . $build->perl_config('lddlflags');
my %dynamic_lib;
%dynamic_lib = %{ $args{dynamic_lib}||{} } if $args{dynamic_lib};
$dynamic_lib{OTHERLDFLAGS} = $build->otherldflags;
my @opts = (
INC => $inc,
CCFLAGS => $ccflags,
OPTIMIZE => $optimize,
LDDLFLAGS => $lddlflags,
LIBS => $libs,
dynamic_lib => \%dynamic_lib,
);
my @typemaps;
push @typemaps, $args{TYPEMAPS} if $args{TYPEMAPS};
my $pwd = Cwd::fastcwd();
for ('xs', $pwd, "$pwd/..") {
my $typemap = $build->file_path("$_/typemap");
if (-e $typemap) {
push @typemaps, $typemap;
}
}
push @opts, TYPEMAPS => \@typemaps if @typemaps;
my $clean_files = (exists $args{clean} && exists $args{clean}{FILES}) ?
$args{clean}{FILES} : '';
$clean_files .= " glue_pods"; # cleanup the dependency target
$args{clean}{FILES} = $clean_files;
ExtUtils::MakeMaker::WriteMakefile(@opts, %args);
}
my %always_dynamic = map { $_, 1 }
qw(ModPerl::Const Apache2::Const APR::Const APR APR::PerlIO);
sub ModPerl::BuildMM::MY::constants {
my $self = shift;
$build ||= build_config();
#"discover" xs modules. since there is no list hardwired
#any module can be unpacked in the mod_perl-2.xx directory
#and built static
#this stunt also make it possible to leave .xs files where
#they are, unlike 1.xx where *.xs live in src/modules/perl
#and are copied to subdir/ if DYNAMIC=1
if ($build->{MP_STATIC_EXTS}) {
#skip .xs -> .so if we are linking static
my $name = $self->{NAME};
unless ($always_dynamic{$name}) {
if (my ($xs) = keys %{ $self->{XS} }) {
$self->{HAS_LINK_CODE} = 0;
print "$name will be linked static\n";
#propagate static xs module to src/modules/perl/Makefile
$build->{XS}->{$name} =
join '/', Cwd::fastcwd(), $xs;
$build->save;
}
}
}
$self->MM::constants;
}
sub ModPerl::BuildMM::MY::top_targets {
my $self = shift;
my $string = $self->MM::top_targets;
return $string;
}
sub ModPerl::BuildMM::MY::postamble {
my $self = shift;
my $doc_root = catdir Cwd::getcwd(), "docs", "api";
my @targets = ();
# reasons for glueing pods to the respective .pm files:
# - manpages will get installed over the mp1 manpages and vice
# versa. glueing pods avoids creation of manpages, but may be we
# could just tell make to skip manpages creation?
# if pods are installed directly they need to be also redirected,
# some into Apache2/ others (e.g. Apache2) not
# add the code to glue the existing pods to the .pm files in blib.
# create a dependency on pm_to_blib subdirs linkext targets to
# allow 'make -j'
require ExtUtils::MakeMaker;
my $mm_ver = $ExtUtils::MakeMaker::VERSION;
$mm_ver =~ s/_.*//; # handle dev versions like 6.30_01
my $pm_to_blib = ($mm_ver >= 6.22 && $mm_ver <= 6.25)
? "pm_to_blib.ts"
: "pm_to_blib";
my @target = ("glue_pods: $pm_to_blib subdirs linkext");
if (-d $doc_root) {
my $build = build_config();
# those living in modperl-2.0/lib are already nicely mapped
my %pms = %{ $self->{PM} };
my $cwd = Cwd::getcwd();
my $blib_dir = catdir qw(blib lib);
# those autogenerated under WrapXS/
# those living under xs/
# those living under ModPerl-Registry/lib/
my @src = ('WrapXS', 'xs', catdir(qw(ModPerl-Registry lib)));
for my $base (@src) {
chdir $base;
my @files = ();
find({ no_chdir => 1,
wanted => sub { push @files, $_ if /.pm$/ },
}, ".");
chdir $cwd;
for (@files) {
my $pm = catfile $base, $_;
my $blib;
if ($base =~ /^(xs|WrapXS)/) {
my @segm = splitdir $_;
splice @segm, -2, 1; # xs/APR/Const/Const.pm
splice @segm, -2, 1 if /APR.pm/; # odd case
$blib = catfile $blib_dir, @segm;
}
else {
$blib = catfile $blib_dir, $_;
}
$pms{$pm} = $blib;
}
}
foreach my $pm (sort keys %pms) {
my $blib = $pms{$pm};
$pm =~ s|/\./|/|g; # clean the path
$blib =~ s|/\./|/|g; # clean the path
my @segm = splitdir $blib;
for my $i (1..2) {
# try APR.pm and APR/Bucket.pm
my $pod = catdir(@segm[-$i .. -1]);
$pod =~ s/\.pm/\.pod/;
my $podpath = catfile $doc_root, $pod;
next unless -r $podpath;
push @target,
'$(FULLPERL) -I$(INST_LIB) ' .
"-I$apache_test_dir -MModPerl::BuildMM " .
"-e ModPerl::BuildMM::glue_pod $pm $podpath $blib";
# Win32 doesn't normally install man pages
# and Cygwin doesn't allow '::' in file names
next if WIN32 || CYGWIN;
# manify while we're at it
my (undef, $man, undef) = $blib =~ m!(blib/lib/)(.*)(\.pm)!;
$man =~ s!/!::!g;
push @target,
'$(NOECHO) $(POD2MAN_EXE) --section=3 ' .
"$podpath \$(INST_MAN3DIR)/$man.\$(MAN3EXT)"
}
}
push @target, $self->{NOECHO} . '$(TOUCH) $@';
}
else {
# we don't have the docs sub-cvs repository extracted, skip
# the docs gluing
push @target, $self->{NOECHO} . '$(NOOP)';
}
push @targets, join "\n\t", @target;
# # next target: cleanup the dependency file
# @target = ('glue_pods_clean:');
# push @target, '$(RM_F) glue_pods';
# push @targets, join "\n\t", @target;
return join "\n\n", @targets, '';
}
sub glue_pod {
die "expecting 3 arguments: pm, pod, dst" unless @ARGV == 3;
my ($pm, $pod, $dst) = @ARGV;
# it's possible that the .pm file is not existing
# (e.g. ThreadMutex.pm is not created on unless
# $apr_config->{HAS_THREADS})
return unless -e $pm && -e $dst;
# have we already glued the doc?
exit 0 unless -s $pm == -s $dst;
# ExtUtils::Install::pm_to_blib removes the 'w' perms, so we can't
# just append the doc there
my $orig_mode = (stat $dst)[2];
my $rw_mode = 0666;
chmod $rw_mode, $dst or die "Can't chmod $rw_mode $dst: $!";
open my $pod_fh, "<$pod" or die "Can't open $pod: $!";
open my $dst_fh, ">>$dst" or die "Can't open $dst: $!";
print $dst_fh "\n"; # must add one line separation
print $dst_fh (<$pod_fh>);
close $pod_fh;
close $dst_fh;
# restore the perms
chmod $orig_mode, $dst or die "Can't chmod $orig_mode $dst: $!";
}
sub ModPerl::BuildMM::MY::post_initialize {
my $self = shift;
$build ||= build_config();
my $pm = $self->{PM};
while (my ($k, $v) = each %PM) {
if (-e $k) {
$pm->{$k} = $v;
}
}
# prefix typemap with Apache2/ so when installed in the
# perl-lib-tree it won't be picked by non-mod_perl modules
if (exists $pm->{'lib/typemap'} ) {
$pm->{'lib/typemap'} = '$(INST_ARCHLIB)/auto/Apache2/typemap';
}
'';
}
my $apr_config;
sub ModPerl::BuildMM::MY::libscan {
my ($self, $path) = @_;
$apr_config ||= $build->get_apr_config();
if ($path =~ m/(Thread|Global)(Mutex|RWLock)/) {
return unless $apr_config->{HAS_THREADS};
}
return '' if $path =~ /DummyVersions.pm/;
return '' if $path =~ m/\.pl$/;
return '' if $path =~ m/~$/;
return '' if $path =~ /\B\.svn\b/;
$path;
}
1;