home *** CD-ROM | disk | FTP | other *** search
/ PC Professionell 2004 December / PCpro_2004_12.ISO / files / webserver / tsw / TSW_3.4.0.exe / Apache2 / perl / Build-old.pm < prev    next >
Encoding:
Perl POD Document  |  2003-12-15  |  42.2 KB  |  1,745 lines

  1. package Apache::Build;
  2.  
  3. use 5.006;
  4. use strict;
  5. use warnings;
  6.  
  7. use Config;
  8. use Cwd ();
  9. use File::Spec::Functions qw(catfile catdir canonpath rel2abs devnull);
  10. use File::Basename;
  11. use ExtUtils::Embed ();
  12.  
  13. use constant IS_MOD_PERL_BUILD => grep { -e "$_/lib/mod_perl.pm" } qw(. ..);
  14.  
  15. use constant AIX    => $^O eq 'aix';
  16. use constant DARWIN => $^O eq 'darwin';
  17. use constant HPUX   => $^O eq 'hpux';
  18. use constant OPENBSD => $^O eq 'openbsd';
  19. use constant WIN32  => $^O eq 'MSWin32';
  20.  
  21. use constant MSVC => WIN32() && ($Config{cc} eq 'cl');
  22.  
  23. use constant REQUIRE_ITHREADS => grep { $^O eq $_ } qw(MSWin32);
  24. use constant PERL_HAS_ITHREADS =>
  25.     $Config{useithreads} && ($Config{useithreads} eq 'define');
  26.  
  27. use ModPerl::Code ();
  28. use ModPerl::BuildOptions ();
  29. use Apache::TestTrace;
  30. use Apache::TestConfig ();
  31.  
  32. our $VERSION = '0.01';
  33. our $AUTOLOAD;
  34.  
  35. sub AUTOLOAD {
  36.     my $self = shift;
  37.     my $name = uc ((split '::', $AUTOLOAD)[-1]);
  38.     unless ($name =~ /^MP_/) {
  39.         die "no such method: $AUTOLOAD";
  40.     }
  41.     unless ($self->{$name}) {
  42.         return wantarray ? () : undef;
  43.     }
  44.     return wantarray ? (split /\s+/, $self->{$name}) : $self->{$name};
  45. }
  46.  
  47. #--- apxs stuff ---
  48.  
  49. our $APXS;
  50.  
  51. my %apxs_query = (
  52.     INCLUDEDIR => 'include',
  53.     LIBEXECDIR => 'modules',
  54.     CFLAGS     => undef,
  55.     PREFIX     => '',
  56. );
  57.  
  58. sub ap_prefix_invalid {
  59.     my $self = shift;
  60.  
  61.     my $prefix = $self->{MP_AP_PREFIX};
  62.  
  63.     unless (-d $prefix) {
  64.         return "$prefix: No such file or directory";
  65.     }
  66.  
  67.     my $include_dir = $self->apxs(-q => 'INCLUDEDIR');
  68.  
  69.     unless (-e $include_dir) {
  70.         return "include/ directory not found in $prefix";
  71.     }
  72.  
  73.     return '';
  74. }
  75.  
  76. sub httpd_is_source_tree {
  77.     my $self = shift;
  78.  
  79.     return $self->{httpd_is_source_tree}
  80.         if exists $self->{httpd_is_source_tree};
  81.  
  82.     my $prefix = $self->dir;
  83.     $self->{httpd_is_source_tree} = 
  84.         defined $prefix && -d $prefix && -e "$prefix/CHANGES";
  85. }
  86.  
  87. sub apxs {
  88.     my $self = shift;
  89.  
  90.     my $is_query = (@_ == 2) && ($_[0] eq '-q');
  91.  
  92.     $self = $self->build_config unless ref $self;
  93.  
  94.     my $query_key;
  95.     if ($is_query) {
  96.         $query_key = 'APXS_' . uc $_[1];
  97.         if ($self->{$query_key}) {
  98.             return $self->{$query_key};
  99.         }
  100.     }
  101.  
  102.     my $apxs;
  103.     my @trys = ($Apache::Build::APXS,
  104.                 $self->{MP_APXS},
  105.                 $ENV{MP_APXS},
  106.                 catfile $self->{MP_AP_PREFIX}, 'bin', 'apxs');
  107.  
  108.     unless (IS_MOD_PERL_BUILD) {
  109.         #if we are building mod_perl via apxs, apxs should already be known
  110.         #these extra tries are for things built outside of mod_perl
  111.         #e.g. libapreq
  112.         # XXX: this may pick a wrong apxs version!
  113.         push @trys,
  114.         Apache::TestConfig::which('apxs'),
  115.         '/usr/local/apache/bin/apxs';
  116.     }
  117.  
  118.     my $ext = WIN32 ? '.bat' : '';
  119.     for my $try (@trys) {
  120.         $try .= $ext if ($try and defined $ext and $try !~ /$ext$/);
  121.         next unless ($apxs = $try);
  122.         chomp $apxs;
  123.         last if -x $apxs;
  124.     }
  125.  
  126.     unless ($apxs and -x $apxs) {
  127.         my $prefix = $self->{MP_AP_PREFIX} || "";
  128.         return '' unless -d $prefix and $is_query;
  129.         my $val = $apxs_query{$_[1]};
  130.         return defined $val ? ($val ? "$prefix/$val" : $prefix) : "";
  131.     }
  132.  
  133.     my $devnull = devnull();
  134.     my $val = qx($apxs @_ 2>$devnull);
  135.     chomp $val if defined $val; # apxs post-2.0.40 adds a new line
  136.  
  137.     unless ($val) {
  138.         error "'$apxs @_' failed:";
  139.  
  140.         if (my $error = qx($apxs @_ 2>&1)) {
  141.             error $error;
  142.         }
  143.         else {
  144.             error 'unknown error';
  145.         }
  146.     }
  147.  
  148.     $self->{$query_key} = $val;
  149. }
  150.  
  151. sub apxs_cflags {
  152.     my $cflags = __PACKAGE__->apxs('-q' => 'CFLAGS');
  153.     $cflags =~ s/\"/\\\"/g;
  154.     $cflags;
  155. }
  156.  
  157. my %threaded_mpms = map { $_ => 1}
  158.         qw(worker winnt beos mpmt_os2 netware leader perchild threadpool);
  159. sub mpm_is_threaded {
  160.     my $self = shift;
  161.     my $mpm_name = $self->mpm_name();
  162.     return $threaded_mpms{$mpm_name};
  163. }
  164.  
  165. sub mpm_name {
  166.     my $self = shift;
  167.  
  168.     return $self->{mpm_name} if $self->{mpm_name};
  169.  
  170.     # XXX: hopefully apxs will work on win32 one day
  171.     return $self->{mpm_name} = 'winnt' if WIN32;
  172.  
  173.     my $mpm_name = $self->apxs('-q' => 'MPM_NAME');
  174.  
  175.     # building against the httpd source dir
  176.     unless ($mpm_name and $self->httpd_is_source_tree) {
  177.         my $config_vars_file = catfile $self->dir, "build", "config_vars.mk";
  178.         if (open my $fh, $config_vars_file) {
  179.             while (<$fh>) {
  180.                 if (/MPM_NAME = (\w+)/) {
  181.                     $mpm_name = $1;
  182.                     last;
  183.                 }
  184.             }
  185.             close $fh;
  186.         }
  187.     }
  188.  
  189.     unless ($mpm_name) {
  190.         my $msg = 'Failed to obtain the MPM name.';
  191.         $msg .= " Please specify MP_APXS=/full/path/to/apxs to solve " .
  192.             "this problem." unless exists $self->{MP_APXS};
  193.         error $msg;
  194.         exit 1;
  195.     }
  196.  
  197.     return $self->{mpm_name} = $mpm_name;
  198. }
  199.  
  200. #--- Perl Config stuff ---
  201.  
  202. my %gtop_config = ();
  203. sub find_gtop {
  204.     my $self = shift;
  205.  
  206.     return %gtop_config if %gtop_config;
  207.  
  208.     if (%gtop_config = find_gtop_config()) {
  209.         return %gtop_config;
  210.     }
  211.  
  212.     if ($self->find_dlfile('gtop')) {
  213.         $gtop_config{ldopts} = $self->gtop_ldopts_old();
  214.         $gtop_config{ccopts} = '';
  215.         return %gtop_config;
  216.     }
  217.  
  218.     return ();
  219. }
  220.  
  221. sub find_gtop_config {
  222.     my %c = ();
  223.  
  224.     if (system('pkg-config --exists libgtop-2.0') == 0) {
  225.         # 2.x
  226.         chomp($c{ccopts} = qx|pkg-config --cflags libgtop-2.0|);
  227.         chomp($c{ldopts} = qx|pkg-config --libs   libgtop-2.0|);
  228.  
  229.         # 2.0.0 bugfix
  230.         chomp(my $libdir = qx|pkg-config --variable=libdir libgtop-2.0|);
  231.         $c{ldopts} =~ s|\$\(libdir\)|$libdir|;
  232.     }
  233.     elsif (system('gnome-config --libs libgtop') == 0) {
  234.         chomp($c{ccopts} = qx|gnome-config --cflags libgtop|);
  235.         chomp($c{ldopts} = qx|gnome-config --libs   libgtop|);
  236.  
  237.         # buggy ( < 1.0.9?) versions fixup
  238.         $c{ccopts} =~ s|^/|-I/|;
  239.         $c{ldopts} =~ s|^/|-L/|;
  240.     }
  241.  
  242.     if ($c{ccopts}) {
  243.         chomp(my $ginc = `glib-config --cflags`);
  244.         $c{ccopts} .= " $ginc";
  245.     }
  246.  
  247.     if (%c) {
  248.         $c{ccopts} = " $c{ccopts}";
  249.         $c{ldopts} = " $c{ldopts}";
  250.     }
  251.  
  252.     return %c;
  253. }
  254.  
  255. my @Xlib = qw(/usr/X11/lib /usr/X11R6/lib);
  256.  
  257. sub gtop_ldopts_old {
  258.     my $self = shift;
  259.     my $xlibs = "";
  260.  
  261.     my($path) = $self->find_dlfile('Xau', @Xlib);
  262.     if ($path) {
  263.         $xlibs = "-L$path -lXau";
  264.     }
  265.  
  266.     if ($self->find_dlfile('intl')) {
  267.         $xlibs .= ' -lintl';
  268.     }
  269.  
  270.     return " -lgtop -lgtop_sysdeps -lgtop_common $xlibs";
  271. }
  272.  
  273. sub gtop_ldopts {
  274.     exists $gtop_config{ldopts} ? $gtop_config{ldopts} : '';
  275. }
  276.  
  277. sub gtop_ccopts {
  278.     exists $gtop_config{ccopts} ? $gtop_config{ccopts} : '';
  279. }
  280.  
  281. sub ldopts {
  282.     my($self) = @_;
  283.  
  284.     my $config = tied %Config;
  285.     my $ldflags = $config->{ldflags};
  286.  
  287.     if (WIN32) {
  288.         $config->{ldflags} = ''; #same as lddlflags
  289.     }
  290.     elsif (DARWIN) {
  291.         #not sure how this can happen, but it shouldn't
  292.         my @bogus_flags = ('flat_namespace', 'bundle', 'undefined suppress');
  293.         for my $flag (@bogus_flags) {
  294.             $config->{ldflags} =~ s/-$flag\s*//;
  295.         }
  296.     }
  297.  
  298.     my $ldopts = ExtUtils::Embed::ldopts();
  299.     chomp $ldopts;
  300.  
  301.     my $ld = $self->perl_config('ld');
  302.  
  303.     if (HPUX && $ld eq 'ld') {
  304.         while ($ldopts =~ s/-Wl,(\S+)/$1/) {
  305.             my $cp = $1;
  306.             (my $repl = $cp) =~ s/,/ /g;
  307.             $ldopts =~ s/\Q$cp/$repl/;
  308.         }
  309.     }
  310.  
  311.     if ($self->{MP_USE_GTOP}) {
  312.         $ldopts .= $self->gtop_ldopts;
  313.     }
  314.  
  315.     $config->{ldflags} = $ldflags; #reset
  316.  
  317.     $ldopts;
  318. }
  319.  
  320. my $Wall =
  321.   "-Wall -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations";
  322.  
  323. # perl v5.6.1 and earlier produces lots of warnings, so we can't use
  324. # -Werror with those versions.
  325. $Wall .= " -Werror" if $] >= 5.006002;
  326.  
  327. sub ap_ccopts {
  328.     my($self) = @_;
  329.     my $ccopts = "-DMOD_PERL";
  330.  
  331.     if ($self->{MP_USE_GTOP}) {
  332.         $ccopts .= " -DMP_USE_GTOP";
  333.         $ccopts .= $self->gtop_ccopts;
  334.     }
  335.  
  336.     if ($self->{MP_MAINTAINER}) {
  337.         $self->{MP_DEBUG} = 1;
  338.         if ($self->perl_config('gccversion')) {
  339.             #same as --with-maintainter-mode
  340.             $ccopts .= " $Wall -DAP_DEBUG";
  341.             $ccopts .= " -DAP_HAVE_DESIGNATED_INITIALIZER";
  342.         }
  343.     }
  344.  
  345.     if ($self->{MP_COMPAT_1X}) {
  346.         $ccopts .= " -DMP_COMPAT_1X";
  347.     }
  348.  
  349.     if ($self->{MP_DEBUG}) {
  350.         $self->{MP_TRACE} = 1;
  351.         my $win32_flags = MSVC  ? '-Od -MD -Zi' : '';
  352.         my $debug_flags = WIN32 ? $win32_flags : '-g';
  353.         $ccopts .= " $debug_flags" unless $Config{optimize} =~ /$debug_flags/;
  354.         $ccopts .= ' -DMP_DEBUG';
  355.     }
  356.  
  357.     if ($self->{MP_CCOPTS}) {
  358.         $ccopts .= " $self->{MP_CCOPTS}";
  359.     }
  360.  
  361.     if ($self->{MP_TRACE}) {
  362.         $ccopts .= " -DMP_TRACE";
  363.     }
  364.  
  365.     $ccopts;
  366. }
  367.  
  368. sub perl_ccopts {
  369.     my $self = shift;
  370.  
  371.     my $cflags = $self->strip_lfs(" $Config{ccflags} ");
  372.  
  373.     my $fixup = \&{"ccopts_$^O"};
  374.     if (defined &$fixup) {
  375.         $fixup->(\$cflags);
  376.     }
  377.  
  378.     if (WIN32 and $self->{MP_DEBUG}) {
  379.         #only win32 has -DDEBUGGING in both optimize and ccflags
  380.         my $optim = $Config{optimize};
  381.  
  382.         unless ($optim =~ /-DDEBUGGING/) {
  383.             $cflags =~ s/$optim//;
  384.        }
  385.     }
  386.  
  387.     $cflags;
  388. }
  389.  
  390. sub ccopts_hpux {
  391.     my $cflags = shift;
  392.     return if $Config{cc} eq 'gcc'; #XXX?
  393.     return if $$cflags =~ /(-Ae|\+e)/;
  394.     $$cflags .= " -Ae ";
  395. }
  396.  
  397. sub ccopts {
  398.     my($self) = @_;
  399.  
  400.     my $cflags = $self->perl_ccopts . ExtUtils::Embed::perl_inc() .
  401.                  $self->ap_ccopts;
  402.  
  403.     $cflags;
  404. }
  405.  
  406. sub ldopts_prefix {
  407.     my $self = shift;
  408.     $self->perl_config('ld') eq 'ld' ? '' : "-Wl,";
  409. }
  410.  
  411. sub perl_config_optimize {
  412.     my($self, $val) = @_;
  413.  
  414.     $val ||= $Config{optimize};
  415.  
  416.     if ($self->{MP_DEBUG}) {
  417.         return ' ' unless $Config{ccflags} =~ /-DDEBUGGING/;
  418.     }
  419.  
  420.     $val;
  421. }
  422.  
  423. sub perl_config_ld {
  424.     my($self, $val) = @_;
  425.  
  426.     $val ||= $Config{ld};
  427.  
  428.     basename $val; #bleedperl hpux value is /usr/bin/ld !
  429. }
  430.  
  431. sub perl_config_lddlflags {
  432.     my($self, $val) = @_;
  433.  
  434.     if ($self->{MP_DEBUG}) {
  435.         if (MSVC) {
  436.             unless ($val =~ s/-release/-debug/) {
  437.                 $val .= ' -debug';
  438.             }
  439.         }
  440.     }
  441.  
  442.     if (AIX) {
  443.         my $Wl = $self->ldopts_prefix;
  444.  
  445.         # it's useless to import symbols from libperl.so this way,
  446.         # because perl.exp is incomplete. a better way is to link
  447.         # against -lperl which has all the symbols
  448.         $val =~ s|${Wl}-bI:\$\(PERL_INC\)/perl\.exp||;
  449.         # also in the case of Makefile.modperl PERL_INC is defined
  450.  
  451.         # this works with at least ld(1) on powerpc-ibm-aix5.1.0.0:
  452.         # -berok ignores symbols resolution problems (they will be
  453.         #        resolved at run-time
  454.         # -brtl prepares the object for run-time loading
  455.         # LDFLAGS already inserts -brtl
  456.         $val .= " ${Wl}-berok";
  457.         # XXX: instead of -berok, could make sure that we have:
  458.         #   -Lpath/to/CORE -lperl
  459.         #   -bI:$path/apr.exp -bI:$path/aprutil.exp -bI:$path/httpd.exp
  460.         #   -bI:$path/modperl_*.exp 
  461.         # - don't import modperl_*.exp in Makefile.modperl which
  462.         #   exports -bE:$path/modperl_*.exp
  463.         # - can't rely on -bI:$path/perl.exp, because it's incomplete,
  464.         #   use -lperl instead
  465.         # - the issue with using apr/aprutil/httpd.exp is to pick the
  466.         #   right path if httpd wasn't yet installed
  467.     }
  468.  
  469.     $val;
  470. }
  471.  
  472. sub perl_config {
  473.     my($self, $key) = @_;
  474.  
  475.     my $val = $Config{$key} || '';
  476.  
  477.     my $method = \&{"perl_config_$key"};
  478.     if (defined &$method) {
  479.         return $method->($self, $val);
  480.     }
  481.  
  482.     return $val;
  483. }
  484.  
  485. sub find_in_inc {
  486.     my $name = shift;
  487.     for (@INC) {
  488.         my $file;
  489.         if (-e ($file = "$_/auto/Apache/$name")) {
  490.             return $file;
  491.         }
  492.     }
  493. }
  494.  
  495. sub libpth {
  496.     my $self = shift;
  497.     $self->{libpth} ||= [split /\s+/, $Config{libpth}];
  498.     return wantarray ? @{ $self->{libpth} } : $self->{libpth};
  499. }
  500.  
  501. sub find_dlfile {
  502.     my($self, $name) = (shift, shift);
  503.  
  504.     require DynaLoader;
  505.     require AutoLoader; #eek
  506.  
  507.     my $found = 0;
  508.     my $loc = "";
  509.     my(@path) = ($self->libpth, @_);
  510.  
  511.     for (@path) {
  512.         if ($found = DynaLoader::dl_findfile($_, "-l$name")) {
  513.             $loc = $_;
  514.             last;
  515.         }
  516.     }
  517.  
  518.     return wantarray ? ($loc, $found) : $found;
  519. }
  520.  
  521. sub find_dlfile_maybe {
  522.     my($self, $name) = @_;
  523.  
  524.     my $path = $self->libpth;
  525.  
  526.     my @maybe;
  527.     my $lib = 'lib' . $name;
  528.  
  529.     for (@$path) {
  530.         push @maybe, grep { ! -l $_ } <$_/$lib.*>;
  531.     }
  532.  
  533.     return \@maybe;
  534. }
  535.  
  536. sub lib_check {
  537.     my($self, $name) = @_;
  538.     return unless $self->perl_config('libs') =~ /$name/;
  539.  
  540.     return if $self->find_dlfile($name);
  541.  
  542.     my $maybe = $self->find_dlfile_maybe($name);
  543.     my $suggest = @$maybe ? 
  544.         "You could just symlink it to $maybe->[0]" :
  545.         'You might need to install Perl from source';
  546.     $self->phat_warn(<<EOF);
  547. Your Perl is configured to link against lib$name,
  548.   but lib$name.so was not found.
  549.   $suggest
  550. EOF
  551. }
  552.  
  553. #--- user interaction ---
  554.  
  555. sub prompt {
  556.     my($self, $q, $default) = @_;
  557.     return $default if $self->{MP_PROMPT_DEFAULT};
  558.     require ExtUtils::MakeMaker;
  559.     ExtUtils::MakeMaker::prompt($q, $default);
  560. }
  561.  
  562. sub prompt_y {
  563.     my($self, $q) = @_;
  564.     $self->prompt($q, 'y') =~ /^y/i;
  565. }
  566.  
  567. sub prompt_n {
  568.     my($self, $q) = @_;
  569.     $self->prompt($q, 'n') =~ /^n/i;
  570. }
  571.  
  572. sub phat_warn {
  573.     my($self, $msg, $abort) = @_;
  574.     my $level = $abort ? 'ERROR' : 'WARNING';
  575.     warn <<EOF;
  576. ************* $level *************
  577.  
  578.   $msg
  579.  
  580. ************* $level *************
  581. EOF
  582.     if ($abort) {
  583.         exit 1;
  584.     }
  585.     else {
  586.         sleep 5;
  587.     }
  588. }
  589.  
  590. #--- constructors ---
  591.  
  592. my $bpm = 'Apache/BuildConfig.pm';
  593.  
  594. sub build_config {
  595.     my $self = shift;
  596.     my $bpm_mtime = 0;
  597.  
  598.     $bpm_mtime = (stat $INC{$bpm})[9] if $INC{$bpm};
  599.  
  600.     if (-e "lib/$bpm" and (stat _)[9] > $bpm_mtime) {
  601.         #reload if Makefile.PL has regenerated
  602.         unshift @INC, 'lib';
  603.         delete $INC{$bpm};
  604.         eval { require Apache::BuildConfig; };
  605.         shift @INC;
  606.     }
  607.     else {
  608.         eval { require Apache::BuildConfig; };
  609.     }
  610.  
  611.     return bless {}, (ref($self) || $self) if $@;
  612.     return Apache::BuildConfig::->new;
  613. }
  614.  
  615. sub new {
  616.     my $class = shift;
  617.  
  618.     my $self = bless {
  619.         cwd => Cwd::fastcwd(),
  620.         MP_LIBNAME => 'mod_perl',
  621.         @_,
  622.     }, $class;
  623.  
  624.     ModPerl::BuildOptions->init($self) if delete $self->{init};
  625.  
  626.     $self;
  627. }
  628.  
  629. sub DESTROY {}
  630.  
  631. my %default_files = (
  632.     'build_config' => 'lib/Apache/BuildConfig.pm',
  633.     'ldopts' => 'src/modules/perl/ldopts',
  634.     'makefile' => 'src/modules/perl/Makefile.modperl',
  635. );
  636.  
  637. sub clean_files {
  638.     my $self = shift;
  639.     [map { $self->default_file($_) } keys %default_files];
  640. }
  641.  
  642. sub default_file {
  643.     my($self, $name, $override) = @_;
  644.     my $key = join '_', 'file', $name;
  645.     $self->{$key} ||= ($override || $default_files{$name});
  646. }
  647.  
  648. sub file_path {
  649.     my $self = shift;
  650.     my @files = map { m:^/: ? $_ : join('/', $self->{cwd}, $_) } @_;
  651.     return wantarray ? @files : $files[0];
  652. }
  653.  
  654. sub freeze {
  655.     require Data::Dumper;
  656.     local $Data::Dumper::Terse = 1;
  657.     my $data = Data::Dumper::Dumper(shift);
  658.     chomp $data;
  659.     $data;
  660. }
  661.  
  662. sub save_ldopts {
  663.     my($self, $file) = @_;
  664.  
  665.     $file ||= $self->default_file('ldopts', $file);
  666.     my $ldopts = $self->ldopts;
  667.  
  668.     open my $fh, '>', $file or die "open $file: $!";
  669.     print $fh "#!/bin/sh\n\necho $ldopts\n";
  670.     close $fh;
  671.     chmod 0755, $file;
  672. }
  673.  
  674. sub noedit_warning_hash {
  675.     ModPerl::Code::noedit_warning_hash(__PACKAGE__);
  676. }
  677.  
  678. sub save {
  679.     my($self, $file) = @_;
  680.  
  681.     delete $INC{$bpm};
  682.  
  683.     $file ||= $self->default_file('build_config');
  684.     $file = $self->file_path($file);
  685.  
  686.     (my $obj = $self->freeze) =~ s/^/    /;
  687.     open my $fh, '>', $file or die "open $file: $!";
  688.  
  689.     #work around autosplit braindeadness
  690.     my $package = 'package Apache::BuildConfig';
  691.  
  692.     print $fh noedit_warning_hash();
  693.  
  694.     print $fh <<EOF;
  695. $package;
  696.  
  697. use Apache::Build ();
  698.  
  699. sub new {
  700. $obj;
  701. }
  702.  
  703. 1;
  704. EOF
  705.  
  706.     close $fh or die "failed to write $file: $!";
  707. }
  708.  
  709. sub rebuild {
  710.     my $self = __PACKAGE__->build_config;
  711.     my @opts = map { qq[$_='$self->{$_}'] } sort grep /^MP_/,  keys %$self;
  712.     my $command = "perl Makefile.PL @opts";
  713.     print "Running: $command\n";
  714.     system $command;
  715. }
  716. # % perl -MApache::Build -e rebuild
  717. *main::rebuild = \&rebuild if $0 eq '-e';
  718.  
  719. #--- attribute access ---
  720.  
  721. sub is_dynamic { shift->{MP_USE_DSO} }
  722.  
  723. sub default_dir {
  724.     my $build = shift->build_config;
  725.  
  726.     return $build->dir || '../apache_x.x/src';
  727. }
  728.  
  729. sub dir {
  730.     my($self, $dir) = @_;
  731.  
  732.     if ($dir) {
  733.         for (qw(ap_includedir)) {
  734.             delete $self->{$_};
  735.         }
  736.         if ($dir =~ m:^../:) {
  737.             $dir = "$self->{cwd}/$dir";
  738.         }
  739.         $self->{dir} = $dir;
  740.     }
  741.  
  742.     return $self->{dir} if $self->{dir};
  743.  
  744.     if (IS_MOD_PERL_BUILD) {
  745.         my $build = $self->build_config;
  746.  
  747.         if ($dir = $build->{'dir'}) {
  748.             for ($dir, "../$dir", "../../$dir") {
  749.                 last if -d ($dir = $_);
  750.             }
  751.         }
  752.     }
  753.  
  754.     $dir ||= $self->{MP_AP_PREFIX};
  755.  
  756. # we no longer install Apache headers, so don't bother looking in @INC
  757. # might end up finding 1.x headers anyhow
  758. #    unless ($dir and -d $dir) {
  759. #        for (@INC) {
  760. #            last if -d ($dir = "$_/auto/Apache/include");
  761. #        }
  762. #    }
  763.     return $self->{dir} = $dir ? canonpath(rel2abs $dir) : undef;
  764. }
  765.  
  766. #--- finding apache *.h files ---
  767.  
  768. sub find {
  769.     my $self = shift;
  770.     my %seen = ();
  771.     my @dirs = ();
  772.  
  773.     for my $src_dir ($self->dir,
  774.                      $self->default_dir,
  775.                      '../httpd-2.0')
  776.       {
  777.           next unless $src_dir;
  778.           next unless (-d $src_dir || -l $src_dir);
  779.           next if $seen{$src_dir}++;
  780.           push @dirs, $src_dir;
  781.           #$modified{$src_dir} = (stat($src_dir))[9];
  782.       }
  783.  
  784.     return @dirs;
  785. }
  786.  
  787. sub ap_includedir  {
  788.     my($self, $d) = @_;
  789.  
  790.     return $self->{ap_includedir}
  791.       if $self->{ap_includedir} and -d $self->{ap_includedir};
  792.  
  793.     return unless $d ||= $self->apxs('-q' => 'INCLUDEDIR') || $self->dir;
  794.  
  795.     if (-e "$d/include/ap_release.h") {
  796.         return $self->{ap_includedir} = "$d/include";
  797.     }
  798.  
  799.     $self->{ap_includedir} = $d;
  800. }
  801.  
  802. # where apr-config and apu-config reside
  803. sub apr_bindir {
  804.     my ($self) = @_;
  805.  
  806.     $self->apr_config_path unless $self->{apr_bindir};
  807.     $self->{apr_bindir};
  808. }
  809.  
  810. # XXX: we assume that apr-config and apu-config reside in the same
  811. # directory
  812. sub apr_config_path {
  813.     my ($self) = @_;
  814.  
  815.     return $self->{apr_config_path}
  816.         if $self->{apr_config_path} and -x $self->{apr_config_path};
  817.  
  818.     if (exists $self->{MP_APR_CONFIG} and -x $self->{MP_APR_CONFIG}) {
  819.         $self->{apr_config_path} = $self->{MP_APR_CONFIG};
  820.     }
  821.  
  822.     if (!$self->{apr_config_path}) {
  823.         my @tries = ();
  824.         if ($self->httpd_is_source_tree) {
  825.             push @tries, grep { -d $_ }
  826.                 map catdir($_, "srclib", "apr"),
  827.                 grep defined $_, $self->dir;
  828.         }
  829.         else {
  830.             # APR_BINDIR was added only at httpd-2.0.46
  831.             push @tries, grep length,
  832.                 map $self->apxs(-q => $_), qw(APR_BINDIR BINDIR);
  833.             push @tries, catdir $self->{MP_AP_PREFIX}, "bin"
  834.                 if exists $self->{MP_AP_PREFIX} and -d $self->{MP_AP_PREFIX};
  835.         }
  836.  
  837.         my $ext = WIN32 ? '.bat' : '';
  838.         for (@tries) {
  839.             my $try = catfile $_, "apr-config";
  840.             $try .= $ext if ($try and defined $ext and $try !~ /$ext$/);
  841.             next unless -x $try;
  842.             $self->{apr_config_path} = $try;
  843.         }
  844.     }
  845.  
  846.     $self->{apr_config_path} ||= Apache::TestConfig::which('apr-config');
  847.  
  848.     # apr_bindir makes sense only if httpd/apr is installed, if we are
  849.     # building against the source tree we can't link against
  850.     # apr/aprutil libs
  851.     unless ($self->httpd_is_source_tree) {
  852.         $self->{apr_bindir} = $self->{apr_config_path}
  853.             ? dirname $self->{apr_config_path}
  854.             : '';
  855.         }
  856.  
  857.     $self->{apr_config_path};
  858. }
  859.  
  860. sub apr_includedir {
  861.     my ($self) = @_;
  862.  
  863.     return $self->{apr_includedir}
  864.         if $self->{apr_includedir} and -d $self->{apr_includedir};
  865.  
  866.     my $incdir;
  867.     my $apr_config_path = $self->apr_config_path;
  868.  
  869.     if ($apr_config_path) {
  870.         my $httpd_version = $self->httpd_version;
  871.         chomp($incdir = `$apr_config_path --includedir`);
  872.     }
  873.  
  874.     unless ($incdir and -d $incdir) {
  875.         # falling back to the default when apr header files are in the
  876.         # same location as the httpd header files
  877.         $incdir = $self->ap_includedir;
  878.     }
  879.  
  880.     my @tries = ($incdir);
  881.     if ($self->httpd_is_source_tree) {
  882.         my $path = catdir $self->dir, "srclib", "apr", "include";
  883.         push @tries, $path if -d $path;
  884.     }
  885.  
  886.     for (@tries) {
  887.         next unless $_ && -e catfile $_, "apr.h";
  888.         $self->{apr_includedir} = $_;
  889.         last;
  890.     }
  891.  
  892.     unless ($self->{apr_includedir}) {
  893.         error "Can't find apr include/ directory,",
  894.             "use MP_APR_CONFIG=/path/to/apr-config";
  895.         exit 1;
  896.     }
  897.  
  898.     $self->{apr_includedir};
  899. }
  900.  
  901. #--- parsing apache *.h files ---
  902.  
  903. sub mmn_eq {
  904.     my($class, $dir) = @_;
  905.  
  906.     return 1 if WIN32; #just assume, till Apache::Build works under win32
  907.  
  908.     my $instsrc;
  909.     {
  910.         local @INC = grep { !/blib/ } @INC;
  911.         my $instdir;
  912.         for (@INC) { 
  913.             last if -d ($instdir = "$_/auto/Apache/include");
  914.         }
  915.         $instsrc = $class->new(dir => $instdir);
  916.     }
  917.     my $targsrc = $class->new($dir ? (dir => $dir) : ());
  918.  
  919.     my $inst_mmn = $instsrc->module_magic_number;
  920.     my $targ_mmn = $targsrc->module_magic_number;
  921.  
  922.     unless ($inst_mmn && $targ_mmn) {
  923.         return 0;
  924.     }
  925.     if ($inst_mmn == $targ_mmn) {
  926.         return 1;
  927.     }
  928.     print "Installed MMN $inst_mmn does not match target $targ_mmn\n";
  929.  
  930.     return 0;
  931. }
  932.  
  933. sub module_magic_number {
  934.     my $self = shift;
  935.  
  936.     return $self->{mmn} if $self->{mmn};
  937.  
  938.     my $d = $self->ap_includedir;
  939.  
  940.     return 0 unless $d;
  941.  
  942.     #return $mcache{$d} if $mcache{$d};
  943.     my $fh;
  944.     for (qw(ap_mmn.h http_config.h)) {
  945.         last if open $fh, "$d/$_";
  946.     }
  947.     return 0 unless $fh;
  948.  
  949.     my $n;
  950.     my $mmn_pat = join '|', qw(MODULE_MAGIC_NUMBER_MAJOR MODULE_MAGIC_NUMBER);
  951.     while(<$fh>) {
  952.         if(s/^\#define\s+($mmn_pat)\s+(\d+).*/$2/) {
  953.            chomp($n = $_);
  954.            last;
  955.        }
  956.     }
  957.     close $fh;
  958.  
  959.     $self->{mmn} = $n
  960. }
  961.  
  962. sub fold_dots {
  963.     my $v = shift;
  964.     $v =~ s/\.//g;
  965.     $v .= '0' if length $v < 3;
  966.     $v;
  967. }
  968.  
  969. sub httpd_version_as_int {
  970.     my($self, $dir) = @_;
  971.     my $v = $self->httpd_version($dir);
  972.     fold_dots($v);
  973. }
  974.  
  975. sub httpd_version_cache {
  976.     my($self, $dir, $v) = @_;
  977.     return '' unless $dir;
  978.     $self->{httpd_version}->{$dir} = $v if $v;
  979.     $self->{httpd_version}->{$dir};
  980. }
  981.  
  982. sub httpd_version {
  983.     my($self, $dir) = @_;
  984.  
  985.     return unless $dir = $self->ap_includedir($dir);
  986.  
  987.     if (my $v = $self->httpd_version_cache($dir)) {
  988.         return $v;
  989.     }
  990.  
  991.     my $header = "$dir/ap_release.h";
  992.     open my $fh, $header or do {
  993.         error "Unable to open $header: $!";
  994.         return undef;
  995.     };
  996.  
  997.     my $version;
  998.  
  999.     while (<$fh>) {
  1000.         #now taking bets on how many friggin times this will change
  1001.         #over the course of apache 2.0.  1.3 changed it at least a half
  1002.         #dozen times.  hopefully it'll stay in the same file at least.
  1003.         if (/^\#define\s+AP_SERVER_MAJORVERSION\s+\"(\d+)\"/) {
  1004.             #XXX could be more careful here.  whatever.  see above.
  1005.             my $major = $1;
  1006.             my $minor = (split /\s+/, scalar(<$fh>))[-1];
  1007.             my $patch = (split /\s+/, scalar(<$fh>))[-1];
  1008.             $version = join '.', $major, $minor, $patch;
  1009.             $version =~ s/\"//g;
  1010.             last;
  1011.         }
  1012.         elsif (/^\#define\s+AP_SERVER_BASEREVISION\s+\"(.*)\"/) {
  1013.             $version = $1;
  1014.             last;
  1015.         }
  1016.     }
  1017.  
  1018.     close $fh;
  1019.  
  1020.     $self->httpd_version_cache($dir, $version);
  1021. }
  1022.  
  1023. my %wanted_apr_config = map { $_, 1} qw(
  1024.     HAS_THREADS HAS_DSO HAS_MMAP HAS_RANDOM HAS_SENDFILE
  1025.     HAS_LARGE_FILES HAS_INLINE HAS_FORK
  1026. );
  1027.  
  1028. sub get_apr_config {
  1029.     my $self = shift;
  1030.  
  1031.     return $self->{apr_config} if $self->{apr_config};
  1032.  
  1033.     my $header = catfile $self->apr_includedir, "apr.h";
  1034.     open my $fh, $header or do {
  1035.         error "Unable to open $header: $!";
  1036.         return undef;
  1037.     };
  1038.  
  1039.     my %cfg;
  1040.     while (<$fh>) {
  1041.         next unless s/^\#define\s+APR_((HAVE|HAS|USE)_\w+)/$1/;
  1042.         chomp;
  1043.         my($name, $val) = split /\s+/, $_, 2;
  1044.         next unless $wanted_apr_config{$name};
  1045.         $val =~ s/\s+$//;
  1046.         next unless $val =~ /^\d+$/;
  1047.         $cfg{$name} = $val;
  1048.     }
  1049.  
  1050.     $self->{apr_config} = \%cfg;
  1051. }
  1052.  
  1053. #--- generate Makefile ---
  1054.  
  1055. sub canon_make_attr {
  1056.     my($self, $name) = (shift, shift);
  1057.  
  1058.     my $attr = join '_', 'MODPERL', uc $name;
  1059.     $self->{$attr} = "@_";
  1060.     "$attr = $self->{$attr}\n\n";
  1061. }
  1062.  
  1063. sub xsubpp {
  1064.     my $self = shift;
  1065.     my $xsubpp = join ' ', '$(MODPERL_PERLPATH)',
  1066.       '$(MODPERL_PRIVLIBEXP)/ExtUtils/xsubpp',
  1067.         '-typemap', '$(MODPERL_PRIVLIBEXP)/ExtUtils/typemap';
  1068.  
  1069.     my $typemap = $self->file_path('lib/typemap');
  1070.     if (-e $typemap) {
  1071.         $xsubpp .= join ' ',
  1072.           ' -typemap', $typemap;
  1073.     }
  1074.  
  1075.     $xsubpp;
  1076. }
  1077.  
  1078. sub make_xs {
  1079.     my($self, $fh) = @_;
  1080.  
  1081.     print $fh $self->canon_make_attr(xsubpp => $self->xsubpp);
  1082.  
  1083.     return [] unless $self->{XS};
  1084.  
  1085.     my @files;
  1086.     my @xs_targ;
  1087.  
  1088.     while (my($name, $xs) = each %{ $self->{XS} }) {
  1089.         #Foo/Bar.xs => Foo_Bar.c
  1090.         (my $c = $xs) =~ s:.*?WrapXS/::;
  1091.         $c =~ s:/:_:g;
  1092.         $c =~ s:\.xs$:.c:;
  1093.  
  1094.         push @files, $c;
  1095.  
  1096.         push @xs_targ, <<EOF;
  1097. $c: $xs
  1098. \t\$(MODPERL_XSUBPP) $xs > \$*.xsc && \$(MODPERL_MV) \$*.xsc \$@
  1099.  
  1100. EOF
  1101.     }
  1102.  
  1103.     my %o = (xs_o_files => 'o', xs_o_pic_files => 'lo');
  1104.  
  1105.     for my $ext (qw(xs_o_files xs_o_pic_files)) {
  1106.         print $fh $self->canon_make_attr($ext, map {
  1107.             (my $file = $_) =~ s/c$/$o{$ext}/; $file;
  1108.         } @files);
  1109.     }
  1110.  
  1111.     print $fh $self->canon_make_attr(xs_clean_files => @files);
  1112.  
  1113.     \@xs_targ;
  1114. }
  1115.  
  1116. #when we use a bit of MakeMaker, make it use our values for these vars
  1117. my %perl_config_pm_alias = (
  1118.     PERL         => 'perlpath',
  1119.     PERLRUN      => 'perlpath',
  1120.     PERL_LIB     => 'privlibexp',
  1121.     PERL_ARCHLIB => 'archlibexp',
  1122. );
  1123.  
  1124. my $mm_replace = join '|', keys %perl_config_pm_alias;
  1125.  
  1126. my @perl_config_pm =
  1127.   (qw(cc cpprun rm ranlib lib_ext obj_ext cccdlflags lddlflags optimize),
  1128.    values %perl_config_pm_alias);
  1129.  
  1130. sub mm_replace {
  1131.     my $val = shift;
  1132.     $$val =~ s/\(($mm_replace)\)/(MODPERL_\U$perl_config_pm_alias{$1})/g;
  1133. }
  1134.  
  1135. #help prevent warnings
  1136. my @mm_init_vars = (BASEEXT => '');
  1137.  
  1138. sub make_tools {
  1139.     my($self, $fh) = @_;
  1140.  
  1141.     for (@perl_config_pm) {
  1142.         print $fh $self->canon_make_attr($_, $self->perl_config($_));
  1143.     }
  1144.  
  1145.     require ExtUtils::MakeMaker;
  1146.     my $mm = bless { @mm_init_vars }, 'MM';
  1147.     $mm->init_main;
  1148.     $mm->init_others;
  1149.  
  1150.     for (qw(rm_f mv ld ar cp test_f)) {
  1151.         my $val = $mm->{"\U$_"};
  1152.         if ($val) {
  1153.             mm_replace(\$val);
  1154.         }
  1155.         else {
  1156.             $val = $Config{$_};
  1157.         }
  1158.         print $fh $self->canon_make_attr($_ => $val);
  1159.     }
  1160. }
  1161.  
  1162. sub export_files_MSWin32 {
  1163.     my $self = shift;
  1164.     my $xs_dir = $self->file_path("xs");
  1165.     "-def:$xs_dir/modperl.def";
  1166. }
  1167.  
  1168. sub export_files_aix {
  1169.     my $self = shift;
  1170.  
  1171.     my $Wl = $self->ldopts_prefix;
  1172.     # there are several modperl_*.exp, not just $(BASEEXT).exp
  1173.     # $(BASEEXT).exp resolves to modperl_global.exp
  1174.     my $xs_dir = $self->file_path("xs");
  1175.     join " ", map "${Wl}-bE:$xs_dir/modperl_$_.exp", qw(inline ithreads);
  1176. }
  1177.  
  1178. sub dynamic_link_header_default {
  1179.     return <<'EOF';
  1180. $(MODPERL_LIBNAME).$(MODPERL_DLEXT): $(MODPERL_PIC_OBJS)
  1181.     $(MODPERL_RM_F) $@
  1182.     $(MODPERL_LD) $(MODPERL_LDDLFLAGS) \
  1183.     $(MODPERL_AP_LIBS) \
  1184.     $(MODPERL_PIC_OBJS) $(MODPERL_LDOPTS) \
  1185. EOF
  1186. }
  1187.  
  1188. sub dynamic_link_default {
  1189.     my $self = shift;
  1190.  
  1191.     my $link = $self->dynamic_link_header_default . "\t" . '-o $@';
  1192.  
  1193.     my $ranlib = "\t" . '$(MODPERL_RANLIB) $@';
  1194.  
  1195.     $link .= "\n" . $ranlib unless (DARWIN or OPENBSD);
  1196.  
  1197.     $link;
  1198. }
  1199.  
  1200. sub dynamic_link_MSWin32 {
  1201.     my $self = shift;
  1202.     my $defs = $self->export_files_MSWin32;
  1203.     my $symbols = $self->modperl_symbols_MSWin32;
  1204.     return $self->dynamic_link_header_default .
  1205.         "\t$defs" .
  1206.         ($symbols ? ' \\' . "\n\t-pdb:$symbols" : '') .
  1207.         ' -out:$@';
  1208. }
  1209.  
  1210. sub dynamic_link_aix {
  1211.     my $self = shift;
  1212.     my $link = $self->dynamic_link_header_default .
  1213.         "\t" . $self->export_files_aix . " \\\n" .
  1214.         "\t" . '-o $@' . " \n" .
  1215.         "\t" . '$(MODPERL_RANLIB) $@';
  1216. }
  1217.  
  1218. sub dynamic_link {
  1219.     my $self = shift;
  1220.     my $link = \&{"dynamic_link_$^O"};
  1221.     $link = \&dynamic_link_default unless defined &$link;
  1222.     $link->($self);
  1223. }
  1224.  
  1225. sub apache_libs_MSWin32 {
  1226.     my $self = shift;
  1227.     my $prefix = $self->apxs(-q => 'PREFIX');
  1228.     my @libs = map { "$prefix/lib/lib$_.lib" } qw(apr aprutil httpd);
  1229.     "@libs";
  1230. }
  1231.  
  1232. sub apache_libs {
  1233.     my $self = shift;
  1234.     my $libs = \&{"apache_libs_$^O"};
  1235.     return "" unless defined &$libs;
  1236.     $libs->($self);
  1237. }
  1238.  
  1239. sub modperl_libs_MSWin32 {
  1240.     my $self = shift;
  1241.     # mod_perl.lib will be installed into MP_AP_PREFIX/lib
  1242.     # for use by 3rd party xs modules
  1243.     "$self->{cwd}/src/modules/perl/$self->{MP_LIBNAME}.lib";
  1244. }
  1245.  
  1246. sub modperl_libs {
  1247.     my $self = shift;
  1248.     my $libs = \&{"modperl_libs_$^O"};
  1249.     return "" unless defined &$libs;
  1250.     $libs->($self);
  1251. }
  1252.  
  1253. sub modperl_symbols_MSWin32 {
  1254.     my $self = shift;
  1255.     return "" unless $self->{MP_DEBUG};
  1256.     "$self->{cwd}/src/modules/perl/$self->{MP_LIBNAME}.pdb";
  1257. }
  1258.  
  1259. sub modperl_symbols {
  1260.     my $self = shift;
  1261.     my $symbols = \&{"modperl_symbols_$^O"};
  1262.     return "" unless defined &$symbols;
  1263.     $symbols->($self);
  1264. }
  1265.  
  1266. sub write_src_makefile {
  1267.     my $self = shift;
  1268.     my $code = ModPerl::Code->new;
  1269.     my $path = $code->path;
  1270.  
  1271.     my $install = <<'EOI';
  1272. install:
  1273. # install mod_perl.so
  1274.     @$(MKPATH) $(MODPERL_AP_LIBEXECDIR)
  1275.     $(MODPERL_TEST_F) $(MODPERL_LIB_DSO) && \
  1276.     $(MODPERL_CP) $(MODPERL_LIB_DSO) $(MODPERL_AP_LIBEXECDIR)
  1277. # install mod_perl .h files
  1278.     @$(MKPATH) $(MODPERL_AP_INCLUDEDIR)
  1279.     $(MODPERL_CP) $(MODPERL_H_FILES) $(MODPERL_AP_INCLUDEDIR)
  1280. EOI
  1281.  
  1282.     my $mf = $self->default_file('makefile');
  1283.  
  1284.     open my $fh, '>', $mf or die "open $mf: $!";
  1285.  
  1286.     print $fh noedit_warning_hash();
  1287.  
  1288.     print $fh $self->canon_make_attr('makefile', basename $mf);
  1289.  
  1290.     $self->make_tools($fh);
  1291.  
  1292.     print $fh $self->canon_make_attr('ap_libs', $self->apache_libs);
  1293.  
  1294.     print $fh $self->canon_make_attr('libname', $self->{MP_LIBNAME});
  1295.     print $fh $self->canon_make_attr('dlext', 'so'); #always use .so
  1296.  
  1297.     if (AIX) {
  1298.         my $xs_dir = $self->file_path("xs");
  1299.         print $fh "BASEEXT = $xs_dir/modperl_global\n\n";
  1300.     }
  1301.  
  1302.     my %libs = (
  1303.         dso    => "$self->{MP_LIBNAME}.$self->{MODPERL_DLEXT}",
  1304.         static => "$self->{MP_LIBNAME}$self->{MODPERL_LIB_EXT}",
  1305.     );
  1306.  
  1307.     #XXX short-term compat for Apache::TestConfigPerl
  1308.     $libs{shared} = $libs{dso};
  1309.  
  1310.     while (my($type, $lib) = each %libs) {
  1311.         print $fh $self->canon_make_attr("lib_$type", $libs{$type});
  1312.     }
  1313.  
  1314.     if (my $symbols = $self->modperl_symbols) {
  1315.         print $fh $self->canon_make_attr('lib_symbols', $symbols);
  1316.         $install .= <<'EOI';
  1317. # install mod_perl symbol file
  1318.     @$(MKPATH) $(MODPERL_AP_LIBEXECDIR)
  1319.     $(MODPERL_TEST_F) $(MODPERL_LIB_SYMBOLS) && \
  1320.     $(MODPERL_CP) $(MODPERL_LIB_SYMBOLS) $(MODPERL_AP_LIBEXECDIR)
  1321. EOI
  1322.     }
  1323.  
  1324.     if (my $libs = $self->modperl_libs) {
  1325.         print $fh $self->canon_make_attr('lib_location', $libs);
  1326.         print $fh $self->canon_make_attr('ap_libdir', 
  1327.                                          "$self->{MP_AP_PREFIX}/lib");
  1328.         $install .= <<'EOI';
  1329. # install mod_perl.lib
  1330.     @$(MKPATH) $(MODPERL_AP_LIBDIR)
  1331.     $(MODPERL_TEST_F) $(MODPERL_LIB_LOCATION) && \
  1332.     $(MODPERL_CP) $(MODPERL_LIB_LOCATION) $(MODPERL_AP_LIBDIR)
  1333. EOI
  1334.     }
  1335.  
  1336.     my $libperl = join '/',
  1337.       $self->perl_config('archlibexp'), 'CORE', $self->perl_config('libperl');
  1338.  
  1339.     #this is only used for deps, if libperl has changed, relink mod_perl.so
  1340.     #not all perl dists put libperl where it should be, so just leave this
  1341.     #out if it isn't in the proper place
  1342.     if (-e $libperl) {
  1343.         print $fh $self->canon_make_attr('libperl', $libperl);
  1344.     }
  1345.  
  1346.     for my $method (qw(ccopts ldopts inc)) {
  1347.         print $fh $self->canon_make_attr($method, $self->$method());
  1348.     }
  1349.  
  1350.     for my $method (qw(c_files o_files o_pic_files h_files)) {
  1351.         print $fh $self->canon_make_attr($method, @{ $code->$method() });
  1352.     }
  1353.  
  1354.     my @libs;
  1355.     for my $type (map { uc } keys %libs) {
  1356.         next unless $self->{"MP_USE_$type"};
  1357.         # on win32 mod_perl.lib must come after mod_perl.so
  1358.         $type eq 'STATIC'
  1359.             ? push    @libs, $self->{"MODPERL_LIB_$type"}
  1360.             : unshift @libs, $self->{"MODPERL_LIB_$type"};
  1361.     }
  1362.  
  1363.     print $fh $self->canon_make_attr('lib', "@libs");
  1364.  
  1365.     for my $q (qw(LIBEXECDIR INCLUDEDIR)) {
  1366.         print $fh $self->canon_make_attr("AP_$q",
  1367.                                          $self->apxs(-q => $q));
  1368.     }
  1369.  
  1370.     my $xs_targ = $self->make_xs($fh);
  1371.  
  1372.     print $fh <<'EOF';
  1373. MODPERL_CCFLAGS = $(MODPERL_INC) $(MODPERL_CCOPTS) $(MODPERL_OPTIMIZE)
  1374.  
  1375. MODPERL_CCFLAGS_SHLIB = $(MODPERL_CCFLAGS) $(MODPERL_CCCDLFLAGS)
  1376.  
  1377. MODPERL_OBJS = $(MODPERL_O_FILES) $(MODPERL_XS_O_FILES)
  1378.  
  1379. MODPERL_PIC_OBJS = $(MODPERL_O_PIC_FILES) $(MODPERL_XS_O_PIC_FILES)
  1380.  
  1381. MKPATH = $(MODPERL_PERLPATH) "-MExtUtils::Command" -e mkpath
  1382.  
  1383. all: lib
  1384.  
  1385. lib: $(MODPERL_LIB)
  1386.  
  1387. EOF
  1388.  
  1389.     print $fh $install;
  1390.  
  1391.     print $fh <<'EOF';
  1392.  
  1393. .SUFFIXES: .xs .c $(MODPERL_OBJ_EXT) .lo .i .s
  1394.  
  1395. .c.lo:
  1396.     $(MODPERL_CC) $(MODPERL_CCFLAGS_SHLIB) \
  1397.     -c $< && $(MODPERL_MV) $*$(MODPERL_OBJ_EXT) $*.lo
  1398.  
  1399. .c$(MODPERL_OBJ_EXT):
  1400.     $(MODPERL_CC) $(MODPERL_CCFLAGS) -c $<
  1401.  
  1402. .c.i:
  1403.     $(MODPERL_CPPRUN) $(MODPERL_CCFLAGS) -c $< > $*.i
  1404.  
  1405. .c.s:
  1406.     $(MODPERL_CC) -O -S $(MODPERL_CCFLAGS) -c $<
  1407.  
  1408. .xs.c:
  1409.     $(MODPERL_XSUBPP) $*.xs >$@
  1410.  
  1411. .xs$(MODPERL_OBJ_EXT):
  1412.     $(MODPERL_XSUBPP) $*.xs >$*.c
  1413.     $(MODPERL_CC) $(MODPERL_CCFLAGS) -c $*.c
  1414.  
  1415. .xs.lo:
  1416.     $(MODPERL_XSUBPP) $*.xs >$*.c
  1417.     $(MODPERL_CC) $(MODPERL_CCFLAGS_SHLIB) \
  1418.     -c $*.c && $(MODPERL_MV) $*$(MODPERL_OBJ_EXT) $*.lo
  1419.  
  1420. clean:
  1421.     $(MODPERL_RM_F) *.a *.so *.xsc \
  1422.     $(MODPERL_LIBNAME).exp $(MODPERL_LIBNAME).lib \
  1423.     *$(MODPERL_OBJ_EXT) *.lo *.i *.s *.pdb \
  1424.     $(MODPERL_CLEAN_FILES) \
  1425.     $(MODPERL_XS_CLEAN_FILES)
  1426.  
  1427. $(MODPERL_OBJS): $(MODPERL_H_FILES) $(MODPERL_MAKEFILE)
  1428. $(MODPERL_PIC_OBJS): $(MODPERL_H_FILES) $(MODPERL_MAKEFILE)
  1429. $(MODPERL_LIB): $(MODPERL_LIBPERL)
  1430.  
  1431. $(MODPERL_LIBNAME)$(MODPERL_LIB_EXT): $(MODPERL_OBJS)
  1432.     $(MODPERL_RM_F) $@
  1433.     $(MODPERL_AR) crv $@ $(MODPERL_OBJS)
  1434.     $(MODPERL_RANLIB) $@
  1435.  
  1436. EOF
  1437.  
  1438.     print $fh $self->dynamic_link;
  1439.  
  1440.     print $fh @$xs_targ;
  1441.  
  1442.     print $fh "\n"; # Makefile must end with \n to avoid warnings
  1443.  
  1444.     close $fh;
  1445. }
  1446.  
  1447. #--- generate MakeMaker parameter values ---
  1448.  
  1449. sub otherldflags_default {
  1450.     my $self = shift;
  1451.     # e.g. aix's V:ldflags feeds -brtl and other flags
  1452.     $self->perl_config('ldflags');
  1453. }
  1454.  
  1455. sub otherldflags {
  1456.     my $self = shift;
  1457.     my $flags = \&{"otherldflags_$^O"};
  1458.     return $self->otherldflags_default unless defined &$flags;
  1459.     $flags->($self);
  1460. }
  1461.  
  1462. sub otherldflags_MSWin32 {
  1463.     my $self = shift;
  1464.     my $flags = $self->otherldflags_default;
  1465.     $flags .= ' -pdb:$(INST_ARCHAUTODIR)\$(BASEEXT).pdb' if $self->{MP_DEBUG};
  1466.     $flags;
  1467. }
  1468.  
  1469. sub typemaps {
  1470.     my $self = shift;
  1471.     my @typemaps = ();
  1472.  
  1473.     # XXX: could move here the code from ModPerl::BuildMM
  1474.     return [] if IS_MOD_PERL_BUILD;
  1475.  
  1476.     # for post install use
  1477.     for (@INC) {
  1478.         # make sure not to pick mod_perl 1.0 typemap
  1479.         next if $self->{MP_INST_APACHE2} && $_ !~ /Apache2$/;
  1480.         my $file = "$_/auto/Apache/typemap";
  1481.         push @typemaps, $file if -e $file;
  1482.     }
  1483.  
  1484.     return \@typemaps;
  1485. }
  1486.  
  1487. sub includes {
  1488.     my $self = shift;
  1489.  
  1490.     my @inc = ();
  1491.  
  1492.     unless (IS_MOD_PERL_BUILD) {
  1493.         # XXX: what if apxs is not available? win32?
  1494.         my $ap_inc = $self->apxs('-q' => 'INCLUDEDIR');
  1495.         if ($ap_inc && -d $ap_inc) {
  1496.             push @inc, $ap_inc;
  1497.         } else {
  1498.             # this is fatal
  1499.             die "Can't find the mod_perl include dir";
  1500.         }
  1501.  
  1502.         return \@inc;
  1503.     }
  1504.  
  1505.     my $src = $self->dir;
  1506.     my $os = WIN32 ? 'win32' : 'unix';
  1507.     push @inc, $self->file_path("src/modules/perl", "xs");
  1508.  
  1509.     push @inc, $self->mp_include_dir;
  1510.  
  1511.     unless ($self->httpd_is_source_tree) {
  1512.         push @inc, $self->apr_includedir;
  1513.  
  1514.         my $ainc = $self->apxs('-q' => 'INCLUDEDIR');
  1515.         if (-d $ainc) {
  1516.             push @inc, $ainc;
  1517.             return \@inc;
  1518.         }
  1519.     }
  1520.  
  1521.     for ("$src/modules/perl", "$src/include",
  1522.          "$src/srclib/apr/include",
  1523.          "$src/srclib/apr-util/include",
  1524.          "$src/os/$os")
  1525.       {
  1526.           push @inc, $_ if -d $_;
  1527.       }
  1528.  
  1529.     return \@inc;
  1530. }
  1531.  
  1532. sub inc {
  1533.     my @includes = map { "-I$_" } @{ shift->includes };
  1534.     "@includes";
  1535. }
  1536.  
  1537. # there is no conflict if both libraries either have or don't have
  1538. # large files support enabled
  1539. sub has_large_files_conflict {
  1540.     my $self = shift;
  1541.     my $apr_config = $self->get_apr_config();
  1542.  
  1543.     my $perl = $Config{uselargefiles} ? 1 : 0;
  1544.     my $apr  = $apr_config->{HAS_LARGE_FILES} ? 1 : 0;
  1545.  
  1546.     return $perl ^ $apr;
  1547. }
  1548.  
  1549. # if perl is built with uselargefiles, but apr not, the build won't
  1550. # work together as it uses two binary incompatible libraries, so
  1551. # reduce the functionality to the greatest common denominator (C code
  1552. # will have to make sure to prevent any operations that may rely on
  1553. # effects created by uselargefiles, e.g. Off_t=8 instead of Off_t=4)
  1554. sub strip_lfs {
  1555.     my($self, $cflags) = @_;
  1556.     return $cflags unless $self->has_large_files_conflict();
  1557.  
  1558.     my $lf = $Config{ccflags_uselargefiles}
  1559.         || '-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64';
  1560.     $cflags =~ s/$lf//;
  1561.     $cflags;
  1562. }
  1563.  
  1564. sub define {
  1565.     my $self = shift;
  1566.  
  1567.     return "";
  1568. }
  1569.  
  1570. # in case MP_INST_APACHE2=0 we shouldn't try to adjust @INC
  1571. # because it may pick older Apache2 from the previous install
  1572. sub generate_apache2_pm {
  1573.     my $self = shift;
  1574.  
  1575.     my $fixup = !$self->{MP_INST_APACHE2} 
  1576.         ? '# MP_INST_APACHE2=0, do nothing'
  1577.         : <<'EOF';
  1578. BEGIN {
  1579.     my @dirs = ();
  1580.  
  1581.     for my $path (@INC) {
  1582.         my $dir = "$path/Apache2";
  1583.         next unless -d $dir;
  1584.         push @dirs, $dir;
  1585.     }
  1586.  
  1587.     if (@dirs) {
  1588.         unshift @INC, @dirs;
  1589.     }
  1590.  
  1591.     # now re-org the libs to have first devel libs, then blib libs,
  1592.     # and only then perl core libs
  1593.     use File::Basename qw(dirname);
  1594.     my $project_root = $blib ? dirname(dirname($blib)) : '';
  1595.     if ($project_root) {
  1596.         my (@a, @b, @c);
  1597.         for (@INC) {
  1598.             if (m|^\Q$project_root\E|) {
  1599.                 m|blib| ? push @b, $_ : push @a, $_;
  1600.             }
  1601.             else {
  1602.                 push @c, $_;
  1603.             }
  1604.         }
  1605.         @INC = (@a, @b, @c);
  1606.     }
  1607.  
  1608. }
  1609. EOF
  1610.  
  1611.     my $content = join "\n\n", 'package Apache2;', $fixup, "1;";
  1612.     my $file = catfile qw(lib Apache2.pm);
  1613.     open my $fh, '>', $file or die "Can't open $file: $!";
  1614.     print $fh $content;
  1615.     close $fh;
  1616.  
  1617. }
  1618.  
  1619. 1;
  1620.  
  1621. __END__
  1622.  
  1623. =head1 NAME
  1624.  
  1625. Apache::Build - Methods for locating and parsing bits of Apache source code
  1626.  
  1627. =head1 SYNOPSIS
  1628.  
  1629.  use Apache::Build ();
  1630.  my $build = Apache::Build->new;
  1631.  
  1632.  # rebuild mod_perl with build opts from the previous build
  1633.  % cd modperl-2.0
  1634.  % perl -MApache::Build -e rebuild
  1635.  
  1636. =head1 DESCRIPTION
  1637.  
  1638. This module provides methods for locating and parsing bits of Apache
  1639. source code.
  1640.  
  1641. Since mod_perl remembers what build options were used to build it, you
  1642. can use this knowledge to rebuild it using the same options. Simply
  1643. chdir to the mod_perl source directory and run:
  1644.  
  1645.   % cd modperl-2.0
  1646.   % perl -MApache::Build -e rebuild
  1647.  
  1648. If you want to rebuild not yet installed, but already built mod_perl,
  1649. run from its root directory:
  1650.  
  1651.   % perl -Ilib -MApache::Build -e rebuild
  1652.  
  1653. =head1 METHODS
  1654.  
  1655. =over 4
  1656.  
  1657. =item new
  1658.  
  1659. Create an object blessed into the B<Apache::Build> class.
  1660.  
  1661.  my $build = Apache::Build->new;
  1662.  
  1663. =item dir
  1664.  
  1665. Top level directory where source files are located.
  1666.  
  1667.  my $dir = $build->dir;
  1668.  -d $dir or die "can't stat $dir $!\n";
  1669.  
  1670. =item find
  1671.  
  1672. Searches for apache source directories, return a list of those found.
  1673.  
  1674. Example:
  1675.  
  1676.  for my $dir ($build->find) {
  1677.     my $yn = prompt "Configure with $dir ?", "y";
  1678.     ...
  1679.  }
  1680.  
  1681. =item inc
  1682.  
  1683. Print include paths for MakeMaker's B<INC> argument to
  1684. C<WriteMakefile>.
  1685.  
  1686. Example:
  1687.  
  1688.  use ExtUtils::MakeMaker;
  1689.  
  1690.  use Apache::Build ();
  1691.  
  1692.  WriteMakefile(
  1693.      'NAME'    => 'Apache::Module',
  1694.      'VERSION' => '0.01',
  1695.      'INC'     => Apache::Build->new->inc,
  1696.  );
  1697.  
  1698.  
  1699. =item module_magic_number
  1700.  
  1701. Return the B<MODULE_MAGIC_NUMBER> defined in the apache source.
  1702.  
  1703. Example:
  1704.  
  1705.  my $mmn = $build->module_magic_number;
  1706.  
  1707. =item httpd_version
  1708.  
  1709. Return the server version.
  1710.  
  1711. Example:
  1712.  
  1713.  my $v = $build->httpd_version;
  1714.  
  1715. =item otherldflags
  1716.  
  1717. Return other ld flags for MakeMaker's B<dynamic_lib> argument to
  1718. C<WriteMakefile>. This might be needed on systems like AIX that need
  1719. special flags to the linker to be able to reference mod_perl or httpd
  1720. symbols.
  1721.  
  1722. Example:
  1723.  
  1724.  use ExtUtils::MakeMaker;
  1725.  
  1726.  use Apache::Build ();
  1727.  
  1728.  WriteMakefile(
  1729.      'NAME'        => 'Apache::Module',
  1730.      'VERSION'     => '0.01', 
  1731.      'INC'         => Apache::Build->new->inc,
  1732.      'dynamic_lib' => {
  1733.          'OTHERLDFLAGS' => Apache::Build->new->otherldflags,
  1734.      },
  1735.  );
  1736.  
  1737. =back
  1738.  
  1739.  
  1740. =head1 AUTHOR
  1741.  
  1742. Doug MacEachern
  1743.  
  1744. =cut
  1745.