1# please insert nothing before this line: -*- mode: cperl; cperl-indent-level: 4; cperl-continued-statement-offset: 4; indent-tabs-mode: nil -*-
2# Licensed to the Apache Software Foundation (ASF) under one or more
3# contributor license agreements.  See the NOTICE file distributed with
4# this work for additional information regarding copyright ownership.
5# The ASF licenses this file to You under the Apache License, Version 2.0
6# (the "License"); you may not use this file except in compliance with
7# the License.  You may obtain a copy of the License at
8#
9#     http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17package Apache2::Build;
18
19use 5.006;
20use strict;
21use warnings;
22
23use Config;
24use Cwd ();
25use File::Spec::Functions qw(catfile catdir canonpath rel2abs devnull
26                             catpath splitpath);
27use File::Basename;
28use ExtUtils::Embed ();
29use File::Copy ();
30
31BEGIN {				# check for a sane ExtUtils::Embed
32    unless ($ENV{MP_USE_MY_EXTUTILS_EMBED}) {
33	my ($version, $path)=(ExtUtils::Embed->VERSION,
34			      $INC{q{ExtUtils/Embed.pm}});
35	my $msg=<<"EOF";
36I have found ExtUtils::Embed $version at
37
38  $path
39
40This is probably not the right one for this perl version. Please make sure
41there is only one version of this module installed and that it is the one
42that comes with this perl version.
43
44If you insist on using the ExtUtils::Embed as is set the environment
45variable MP_USE_MY_EXTUTILS_EMBED=1 and try again.
46
47EOF
48	if (eval {require Module::CoreList}) {
49	    my $req=$Module::CoreList::version{$]}->{q/ExtUtils::Embed/};
50	    die "Please repair your Module::CoreList" unless $req;
51	    unless ($version eq $req) {
52		$msg.=("Details: expecting ExtUtils::Embed $req ".
53		       "(according to Module::CoreList)\n\n");
54		die $msg;
55	    }
56	}
57	else {
58	    my $req=$Config{privlib}.'/ExtUtils/Embed.pm';
59	    unless ($path eq $req) {
60		$msg.="Details: expecting ExtUtils::Embed at $req\n\n";
61		die $msg;
62	    }
63	}
64    }
65}
66
67use constant IS_MOD_PERL_BUILD => grep
68    { -e "$_/Makefile.PL" && -e "$_/lib/mod_perl2.pm" } qw(. ..);
69
70use constant AIX     => $^O eq 'aix';
71use constant DARWIN  => $^O eq 'darwin';
72use constant CYGWIN  => $^O eq 'cygwin';
73use constant IRIX    => $^O eq 'irix';
74use constant HPUX    => $^O eq 'hpux';
75use constant OPENBSD => $^O eq 'openbsd';
76use constant WIN32   => $^O eq 'MSWin32';
77
78use constant MSVC => WIN32() && ($Config{cc} eq 'cl');
79use constant DMAKE => WIN32() && ($Config{make} eq 'dmake');
80
81use constant REQUIRE_ITHREADS => grep { $^O eq $_ } qw(MSWin32);
82use constant PERL_HAS_ITHREADS =>
83    $Config{useithreads} && ($Config{useithreads} eq 'define');
84use constant BUILD_APREXT => WIN32() || CYGWIN();
85
86use ModPerl::Code ();
87use ModPerl::BuildOptions ();
88use Apache::TestTrace;
89use Apache::TestConfig ();
90
91our $VERSION = '0.01';
92our $AUTOLOAD;
93
94sub AUTOLOAD {
95    my $self = shift;
96    my $name = uc ((split '::', $AUTOLOAD)[-1]);
97    unless ($name =~ /^MP_/) {
98        die "no such method: $AUTOLOAD";
99    }
100    unless ($self->{$name}) {
101        return wantarray ? () : undef;
102    }
103    return wantarray ? (split /\s+/, $self->{$name}) : $self->{$name};
104}
105
106#--- apxs stuff ---
107
108our $APXS;
109
110my %apxs_query = (
111    INCLUDEDIR => 'include',
112    LIBEXECDIR => 'modules',
113    CFLAGS     => undef,
114    PREFIX     => '',
115);
116
117sub ap_prefix_invalid {
118    my $self = shift;
119
120    my $prefix = $self->{MP_AP_PREFIX};
121
122    unless (-d $prefix) {
123        return "$prefix: No such file or directory";
124    }
125
126    my $include_dir = $self->apxs(-q => 'INCLUDEDIR');
127
128    unless (-d $include_dir) {
129        return "include/ directory not found in $prefix";
130    }
131
132    return '';
133}
134
135sub httpd_is_source_tree {
136    my $self = shift;
137
138    return $self->{httpd_is_source_tree}
139        if exists $self->{httpd_is_source_tree};
140
141    my $prefix = $self->dir;
142    $self->{httpd_is_source_tree} =
143        defined $prefix && -d $prefix && -e "$prefix/CHANGES";
144}
145
146# try to find the apxs utility, set $self->{MP_APXS} to the path if found,
147# otherwise to ''
148sub find_apxs_util {
149    my $self = shift;
150
151    if (not defined $self->{MP_APXS}) {
152        $self->{MP_APXS} = ''; # not found
153    }
154
155    my @trys = ($Apache2::Build::APXS,
156                $self->{MP_APXS},
157                $ENV{MP_APXS});
158
159    push @trys, catfile $self->{MP_AP_PREFIX}, 'sbin', 'apxs'
160        if exists $self->{MP_AP_PREFIX};
161
162    if (WIN32) {
163        my $ext = '.bat';
164        for (@trys) {
165            $_ .= $ext if ($_ and $_ !~ /$ext$/);
166        }
167    }
168
169    unless (IS_MOD_PERL_BUILD) {
170        #if we are building mod_perl via apxs, apxs should already be known
171        #these extra tries are for things built outside of mod_perl
172        #e.g. libapreq
173        # XXX: this may pick a wrong apxs version!
174        push @trys,
175        Apache::TestConfig::which('apxs'),
176        '/usr/local/sbin/apxs';
177    }
178
179    my $apxs_try;
180    for (@trys) {
181        next unless ($apxs_try = $_);
182        chomp $apxs_try;
183        if (-x $apxs_try) {
184            $self->{MP_APXS} = $apxs_try;
185            last;
186        }
187    }
188}
189
190# if MP_AP_DESTDIR was specified this sub will prepend this path to
191# any Apache-specific installation path (that option is used only by
192# package maintainers).
193sub ap_destdir {
194    my $self = shift;
195    my $path = shift || '';
196    return $path unless $self->{MP_AP_DESTDIR};
197
198    if (WIN32) {
199        my ($dest_vol, $dest_dir) = splitpath $self->{MP_AP_DESTDIR}, 1;
200        my $real_dir = (splitpath $path)[1];
201
202        $path = catpath $dest_vol, catdir($dest_dir, $real_dir), '';
203    }
204    else {
205        $path = catdir $self->{MP_AP_DESTDIR}, $path;
206    }
207
208    return canonpath $path;
209}
210
211sub apxs {
212    my $self = shift;
213
214    $self->find_apxs_util() unless defined $self->{MP_APXS};
215
216    my $is_query = (@_ == 2) && ($_[0] eq '-q');
217
218    $self = $self->build_config unless ref $self;
219
220    my $query_key;
221    if ($is_query) {
222        $query_key = 'APXS_' . uc $_[1];
223        if (exists $self->{$query_key}) {
224            return $self->{$query_key};
225        }
226    }
227
228    unless ($self->{MP_APXS}) {
229        my $prefix = $self->{MP_AP_PREFIX} || "";
230        return '' unless -d $prefix and $is_query;
231        my $val = $apxs_query{$_[1]};
232        return defined $val ? ($val ? "$prefix/$val" : $prefix) : "";
233    }
234
235    my $devnull = devnull();
236    my $val = qx($self->{MP_APXS} @_ 2>$devnull);
237    chomp $val if defined $val;
238
239    unless ($val) {
240        # do we have an error or is it just an empty value?
241        my $error = qx($self->{MP_APXS} @_ 2>&1);
242        chomp $error if defined $error;
243        if ($error) {
244            error "'$self->{MP_APXS} @_' failed:";
245            error $error;
246        }
247        else {
248            $val = '';
249        }
250    }
251
252    $self->{$query_key} = $val;
253}
254
255sub apxs_cflags {
256    my $who = caller_package(shift);
257    my $cflags = $who->apxs('-q' => 'CFLAGS');
258    $cflags =~ s/\"/\\\"/g;
259    $cflags;
260}
261
262sub apxs_extra_cflags {
263    my $who = caller_package(shift);
264    my $flags = $who->apxs('-q' => 'EXTRA_CFLAGS');
265    $flags =~ s/\"/\\\"/g;
266    $flags;
267}
268
269sub apxs_extra_cppflags {
270    my $who = caller_package(shift);
271    my $flags = $who->apxs('-q' => 'EXTRA_CPPFLAGS') ." ".
272        $who->apxs('-q' => 'NOTEST_CPPFLAGS');
273    $flags =~ s/\"/\\\"/g;
274    $flags;
275}
276
277sub caller_package {
278    my $arg = shift;
279    return ($arg and ref($arg) eq __PACKAGE__) ? $arg : __PACKAGE__;
280}
281
282my %threaded_mpms = map { $_ => 1 }
283        qw(worker winnt beos mpmt_os2 netware leader perchild threadpool
284           dynamic);
285sub mpm_is_threaded {
286    my $self = shift;
287    my $mpm_name = $self->mpm_name();
288    return exists $threaded_mpms{$mpm_name} ? 1 : 0;
289}
290
291sub mpm_name {
292    my $self = shift;
293
294    return $self->{mpm_name} if $self->{mpm_name};
295
296    if ($self->httpd_version =~ /^(\d+)\.(\d+)\.(\d+)/) {
297	delete $threaded_mpms{dynamic} if $self->mp_nonthreaded_ok;
298	return $self->{mpm_name} = 'dynamic' if ($1*1000+$2)*1000+$3>=2003000;
299    }
300
301    # XXX: hopefully apxs will work on win32 one day
302    return $self->{mpm_name} = 'winnt' if WIN32;
303
304    my $mpm_name;
305
306    # httpd >= 2.3
307    if ($self->httpd_version_as_int =~ m/^2[3-9]\d+/) {
308        $mpm_name = 'dynamic';
309    }
310    else {
311        $mpm_name = $self->apxs('-q' => 'MPM_NAME');
312    }
313
314    # building against the httpd source dir
315    unless (($mpm_name and $self->httpd_is_source_tree)) {
316        if ($self->dir) {
317            my $config_vars_file = catfile $self->dir,
318                "build", "config_vars.mk";
319            if (open my $fh, $config_vars_file) {
320                while (<$fh>) {
321                    if (/MPM_NAME = (\w+)/) {
322                        $mpm_name = $1;
323                        last;
324                    }
325                }
326                close $fh;
327            }
328        }
329    }
330
331    unless ($mpm_name) {
332        my $msg = 'Failed to obtain the MPM name.';
333        $msg .= " Please specify MP_APXS=/full/path/to/apxs to solve " .
334            "this problem." unless exists $self->{MP_APXS};
335        error $msg;
336        die "\n";
337    }
338
339    return $self->{mpm_name} = $mpm_name;
340}
341
342sub should_build_apache {
343    my ($self) = @_;
344    return $self->{MP_USE_STATIC} ? 1 : 0;
345}
346
347sub configure_apache {
348    my ($self) = @_;
349
350    unless ($self->{MP_AP_CONFIGURE}) {
351        error "You specified MP_USE_STATIC but did not specify the " .
352              "arguments to httpd's ./configure with MP_AP_CONFIGURE";
353        exit 1;
354    }
355
356    unless ($self->{MP_AP_PREFIX}) {
357        error "You specified MP_USE_STATIC but did not speficy the " .
358              "location of httpd's source tree with MP_AP_PREFIX";
359        exit 1;
360    }
361
362    debug "Configuring httpd in $self->{MP_AP_PREFIX}";
363
364    my $httpd = File::Spec->catfile($self->{MP_AP_PREFIX}, 'httpd');
365    $self->{'httpd'} ||= $httpd;
366    push @Apache::TestMM::Argv, ('httpd' => $self->{'httpd'});
367
368    my $mplibpath = '';
369    my $ldopts = $self->ldopts;
370
371    if (CYGWIN) {
372        # Cygwin's httpd port links its modules into httpd2core.dll,
373        # instead of httpd.exe. In this case, we have a problem,
374        # because libtool doesn't want to include static libs (.a)
375        # into a dynamic lib (.dll). Workaround this by setting
376        # mod_perl.a as a linker argument (including all other flags
377        # and libs).
378        my $mplib  = "$self->{MP_LIBNAME}$Config{lib_ext}";
379
380        $ldopts = join ' ',
381            '--export-all-symbols',
382            '--enable-auto-image-base',
383            "$self->{cwd}/src/modules/perl/$mplib",
384            $ldopts;
385
386        $ldopts =~ s/(\S+)/-Wl,$1/g;
387
388    } else {
389        my $mplib  = "$self->{MP_LIBNAME}$Config{lib_ext}";
390        $mplibpath = catfile($self->{cwd}, qw(src modules perl), $mplib);
391    }
392
393    local $ENV{BUILTIN_LIBS} = $mplibpath;
394    local $ENV{AP_LIBS} = $ldopts;
395    local $ENV{MODLIST} = 'perl';
396
397    # XXX: -Wall and/or -Werror at httpd configure time breaks things
398    local $ENV{CFLAGS} = join ' ', grep { ! /\-Wall|\-Werror/ }
399        split /\s+/, $ENV{CFLAGS} || '';
400
401    my $cd = qq(cd $self->{MP_AP_PREFIX});
402
403    # We need to clean the httpd tree before configuring it
404    if (-f File::Spec->catfile($self->{MP_AP_PREFIX}, 'Makefile')) {
405        my $cmd = qq(make clean);
406        debug "Running $cmd";
407        system("$cd && $cmd") == 0 or die "httpd: $cmd failed";
408    }
409
410    my $cmd = qq(./configure $self->{MP_AP_CONFIGURE});
411    debug "Running $cmd";
412    system("$cd && $cmd") == 0 or die "httpd: $cmd failed";
413
414    # Got to build in srclib/* early to have generated files present.
415    my $srclib = File::Spec->catfile($self->{MP_AP_PREFIX}, 'srclib');
416    $cd = qq(cd $srclib);
417    $cmd = qq(make);
418    debug "Building srclib in $srclib";
419    system("$cd && $cmd") == 0 or die "srclib: $cmd failed";
420}
421
422#--- Perl Config stuff ---
423
424my %gtop_config = ();
425sub find_gtop {
426    my $self = shift;
427
428    return %gtop_config if %gtop_config;
429
430    if (%gtop_config = find_gtop_config()) {
431        return %gtop_config;
432    }
433
434    if ($self->find_dlfile('gtop')) {
435        $gtop_config{ldopts} = $self->gtop_ldopts_old();
436        $gtop_config{ccopts} = '';
437        return %gtop_config;
438    }
439
440    return ();
441}
442
443sub find_gtop_config {
444    my %c = ();
445
446    my $ver_2_5_plus = 0;
447    if (system('pkg-config --exists libgtop-2.0') == 0) {
448        # 2.x
449        chomp($c{ccopts} = qx|pkg-config --cflags libgtop-2.0|);
450        chomp($c{ldopts} = qx|pkg-config --libs   libgtop-2.0|);
451
452        # 2.0.0 bugfix
453        chomp(my $libdir = qx|pkg-config --variable=libdir libgtop-2.0|);
454        $c{ldopts} =~ s|\$\(libdir\)|$libdir|;
455
456        chomp($c{ver} = qx|pkg-config --modversion libgtop-2.0|);
457        ($c{ver_maj}, $c{ver_min}) = split /\./, $c{ver};
458        $ver_2_5_plus++ if $c{ver_maj} == 2 && $c{ver_min} >= 5;
459
460        if ($ver_2_5_plus) {
461            # some headers were removed in libgtop 2.5.0 so we need to
462            # be able to exclude them at compile time
463            $c{ccopts} .= ' -DGTOP_2_5_PLUS';
464        }
465
466    }
467    elsif (system('gnome-config --libs libgtop') == 0) {
468        chomp($c{ccopts} = qx|gnome-config --cflags libgtop|);
469        chomp($c{ldopts} = qx|gnome-config --libs   libgtop|);
470
471        # buggy ( < 1.0.9?) versions fixup
472        $c{ccopts} =~ s|^/|-I/|;
473        $c{ldopts} =~ s|^/|-L/|;
474    }
475
476    # starting from 2.5.0 'pkg-config --cflags libgtop-2.0' already
477    # gives us all the cflags that are needed
478    if ($c{ccopts} && !$ver_2_5_plus) {
479        chomp(my $ginc = `glib-config --cflags`);
480        $c{ccopts} .= " $ginc";
481    }
482
483    if (%c) {
484        $c{ccopts} = " $c{ccopts}";
485        $c{ldopts} = " $c{ldopts}";
486    }
487
488    return %c;
489}
490
491my @Xlib = qw(/usr/X11/lib /usr/X11R6/lib);
492
493sub gtop_ldopts_old {
494    my $self = shift;
495    my $xlibs = "";
496
497    my ($path) = $self->find_dlfile('Xau', @Xlib);
498    if ($path) {
499        $xlibs = "-L$path -lXau";
500    }
501
502    if ($self->find_dlfile('intl')) {
503        $xlibs .= ' -lintl';
504    }
505
506    return " -lgtop -lgtop_sysdeps -lgtop_common $xlibs";
507}
508
509sub gtop_ldopts {
510    exists $gtop_config{ldopts} ? $gtop_config{ldopts} : '';
511}
512
513sub gtop_ccopts {
514    exists $gtop_config{ccopts} ? $gtop_config{ccopts} : '';
515}
516
517sub ldopts {
518    my ($self) = @_;
519
520    my $config = tied %Config;
521    my $ldflags = $config->{ldflags};
522
523    if (WIN32) {
524        $config->{ldflags} = ''; #same as lddlflags
525    }
526    elsif (DARWIN) {
527        #not sure how this can happen, but it shouldn't
528        my @bogus_flags = ('flat_namespace', 'bundle', 'undefined suppress');
529        for my $flag (@bogus_flags) {
530            $config->{ldflags} =~ s/-$flag\s*//;
531        }
532    }
533
534    my $ldopts = ExtUtils::Embed::ldopts();
535    chomp $ldopts;
536
537    my $ld = $self->perl_config('ld');
538
539    if (HPUX && $ld eq 'ld') {
540        while ($ldopts =~ s/-Wl,(\S+)/$1/) {
541            my $cp = $1;
542            (my $repl = $cp) =~ s/,/ /g;
543            $ldopts =~ s/\Q$cp/$repl/;
544        }
545    }
546
547    if ($self->{MP_USE_GTOP}) {
548        $ldopts .= $self->gtop_ldopts;
549    }
550
551    $config->{ldflags} = $ldflags; #reset
552
553    # on Irix mod_perl.so needs to see the libperl.so symbols, which
554    # requires the -exports option immediately before -lperl.
555    if (IRIX) {
556        ($ldopts =~ s/-lperl\b/-exports -lperl/)
557            or warn "Failed to fix Irix symbol exporting\n";
558    }
559
560    $ldopts;
561}
562
563my $Wall =
564  "-Wall -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations";
565
566# perl v5.6.1 and earlier produces lots of warnings, so we can't use
567# -Werror with those versions.
568$Wall .= " -Werror" if $] >= 5.006002;
569
570sub ap_ccopts {
571    my ($self) = @_;
572    my $ccopts = "-DMOD_PERL";
573
574    if ($self->{MP_USE_GTOP}) {
575        $ccopts .= " -DMP_USE_GTOP";
576        $ccopts .= $self->gtop_ccopts;
577    }
578
579    if ($self->{MP_MAINTAINER}) {
580        $self->{MP_DEBUG} = 1;
581        if ($self->perl_config('gccversion')) {
582            #same as --with-maintainter-mode
583            $ccopts .= " $Wall";
584        }
585
586        if (!OPENBSD &&
587            $self->has_gcc_version('3.3.2') &&
588            $ccopts !~ /declaration-after-statement/) {
589            debug "Adding -Wdeclaration-after-statement to ccopts";
590            $ccopts .= " -Wdeclaration-after-statement";
591        }
592    }
593
594    if ($self->{MP_COMPAT_1X}) {
595        $ccopts .= " -DMP_COMPAT_1X";
596    }
597
598    if ($self->{MP_DEBUG}) {
599        $self->{MP_TRACE} = 1;
600        my $win32_flags = MSVC  ? '-Od -MD -Zi' : '';
601        my $debug_flags = WIN32 ? $win32_flags : '-g';
602        $ccopts .= " $debug_flags" unless $Config{optimize} =~ /$debug_flags/;
603        $ccopts .= ' -DMP_DEBUG';
604    }
605
606    if ($self->{MP_CCOPTS}) {
607        $ccopts .= " $self->{MP_CCOPTS}";
608    }
609
610    if ($self->{MP_TRACE}) {
611        $ccopts .= " -DMP_TRACE";
612    }
613
614    if ($self->has_gcc_version('5.0.0') && $ccopts !~ /-fgnu89-inline/) {
615        $ccopts .= " -fgnu89-inline";
616    }
617
618    if ($self->has_clang && $ccopts !~ /-std=gnu89/) {
619        $ccopts .= " -std=gnu89";
620    }
621
622    # make sure apr.h can be safely included
623    # for example Perl's included -D_GNU_SOURCE implies
624    # -D_LARGEFILE64_SOURCE on linux, but this won't happen on
625    # Solaris, so we need apr flags living in apxs' EXTRA_CPPFLAGS
626    my $extra_cppflags = $self->apxs_extra_cppflags;
627    $ccopts .= " " . $extra_cppflags;
628
629    # Make sure the evil AP_DEBUG is not defined when building mod_perl
630    $ccopts =~ s/ ?-DAP_DEBUG\b//;
631
632    $ccopts;
633}
634
635sub has_gcc_version {
636    my $self = shift;
637    my $requested_version = shift;
638
639    my $has_version = $self->perl_config('gccversion');
640
641    return 0 unless $has_version;
642
643    #Only interested in leading version digits
644    $has_version =~ s/^([0-9.]+).*/$1/;
645
646    my @tuples = split /\./, $has_version, 3;
647    my @r_tuples = split /\./, $requested_version, 3;
648
649    return cmp_tuples(\@tuples, \@r_tuples) == 1;
650}
651
652sub has_clang {
653    my $self = shift;
654
655    my $has_version = $self->perl_config('gccversion');
656
657    return 0 unless $has_version;
658
659    return $has_version =~ m/Clang/;
660}
661
662sub cmp_tuples {
663    my ($num_a, $num_b) = @_;
664
665    while (@$num_a && @$num_b) {
666        my $cmp = shift @$num_a <=> shift @$num_b;
667        return $cmp if $cmp;
668    }
669
670    return @$num_a <=> @$num_b;
671}
672
673sub perl_ccopts {
674    my $self = shift;
675
676    my $cflags = $self->strip_lfs(" $Config{ccflags} ");
677
678    my $fixup = \&{"ccopts_$^O"};
679    if (defined &$fixup) {
680        $fixup->(\$cflags);
681    }
682
683    if (WIN32 and $self->{MP_DEBUG}) {
684        #only win32 has -DDEBUGGING in both optimize and ccflags
685        my $optim = $Config{optimize};
686
687        unless ($optim =~ /-DDEBUGGING/) {
688            $cflags =~ s/$optim//;
689       }
690    }
691
692    if (CYGWIN) {
693        $cflags .= " -DCYGWIN ";
694    }
695
696    $cflags;
697}
698
699sub ccopts_hpux {
700    my $cflags = shift;
701    return if $Config{cc} eq 'gcc'; #XXX?
702    return if $$cflags =~ /(-Ae|\+e)/;
703    $$cflags .= " -Ae ";
704}
705
706# XXX: there could be more, but this is just for cosmetics
707my %cflags_dups = map { $_ => 1 } qw(-D_GNU_SOURCE -D_REENTRANT);
708sub ccopts {
709    my ($self) = @_;
710
711    my $cflags = $self->perl_ccopts . ExtUtils::Embed::perl_inc() .
712                 $self->ap_ccopts;
713
714    # remove duplicates of certain cflags coming from perl and ap/apr
715    my @cflags = ();
716    my %dups    = ();
717    for (split /\s+/, $cflags) {
718        if ($cflags_dups{$_}) {
719            next if $dups{$_};
720            $dups{$_}++;
721        }
722        push @cflags, $_;
723    }
724    $cflags = "@cflags";
725
726    $cflags;
727}
728
729sub ldopts_prefix {
730    my $self = shift;
731    $self->perl_config('ld') eq 'ld' ? '' : "-Wl,";
732}
733
734sub perl_config_optimize {
735    my ($self, $val) = @_;
736
737    $val ||= $Config{optimize};
738
739    if ($self->{MP_DEBUG}) {
740        return ' ' unless $Config{ccflags} =~ /-DDEBUGGING/;
741    }
742
743    $val;
744}
745
746sub perl_config_ld {
747    my ($self, $val) = @_;
748
749    $val ||= $Config{ld};
750
751    basename $val; #bleedperl hpux value is /usr/bin/ld !
752}
753
754sub perl_config_lddlflags {
755    my ($self, $val) = @_;
756
757    if ($self->{MP_DEBUG}) {
758        if (MSVC) {
759            unless ($val =~ s/-release/-debug/) {
760                $val .= ' -debug';
761            }
762        }
763    }
764
765    if (AIX) {
766        my $Wl = $self->ldopts_prefix;
767
768        # it's useless to import symbols from libperl.so this way,
769        # because perl.exp is incomplete. a better way is to link
770        # against -lperl which has all the symbols
771        $val =~ s|${Wl}-bI:\$\(PERL_INC\)/perl\.exp||;
772        # also in the case of Makefile.modperl PERL_INC is defined
773
774        # this works with at least ld(1) on powerpc-ibm-aix5.1.0.0:
775        # -berok ignores symbols resolution problems (they will be
776        #        resolved at run-time
777        # -brtl prepares the object for run-time loading
778        # LDFLAGS already inserts -brtl
779        $val .= " ${Wl}-berok";
780        # XXX: instead of -berok, could make sure that we have:
781        #   -Lpath/to/CORE -lperl
782        #   -bI:$path/apr.exp -bI:$path/aprutil.exp -bI:$path/httpd.exp
783        #   -bI:$path/modperl_*.exp
784        # - don't import modperl_*.exp in Makefile.modperl which
785        #   exports -bE:$path/modperl_*.exp
786        # - can't rely on -bI:$path/perl.exp, because it's incomplete,
787        #   use -lperl instead
788        # - the issue with using apr/aprutil/httpd.exp is to pick the
789        #   right path if httpd wasn't yet installed
790    }
791
792    $val;
793}
794
795sub perl_config {
796    my ($self, $key) = @_;
797
798    my $val = $Config{$key} || '';
799
800    my $method = \&{"perl_config_$key"};
801    if (defined &$method) {
802        return $method->($self, $val);
803    }
804
805    return $val;
806}
807
808sub find_in_inc {
809    my $name = shift;
810    for (@INC) {
811        my $file;
812        if (-e ($file = "$_/auto/Apache2/$name")) {
813            return $file;
814        }
815    }
816}
817
818sub libpth {
819    my $self = shift;
820    $self->{libpth} ||= [split /\s+/, $Config{libpth}];
821    return wantarray ? @{ $self->{libpth} } : $self->{libpth};
822}
823
824sub find_dlfile {
825    my ($self, $name) = (shift, shift);
826
827    require DynaLoader;
828    require AutoLoader; #eek
829
830    my $found = 0;
831    my $loc = "";
832    my (@path) = ($self->libpth, @_);
833
834    for (@path) {
835        if ($found = DynaLoader::dl_findfile($_, "-l$name")) {
836            $loc = $_;
837            last;
838        }
839    }
840
841    return wantarray ? ($loc, $found) : $found;
842}
843
844sub find_dlfile_maybe {
845    my ($self, $name) = @_;
846
847    my $path = $self->libpth;
848
849    my @maybe;
850    my $lib = 'lib' . $name;
851
852    for (@$path) {
853        push @maybe, grep { ! -l $_ } <$_/$lib.*>;
854    }
855
856    return \@maybe;
857}
858
859sub lib_check {
860    my ($self, $name) = @_;
861    return unless $self->perl_config('libs') =~ /$name/;
862
863    return if $self->find_dlfile($name);
864
865    my $maybe = $self->find_dlfile_maybe($name);
866    my $suggest = @$maybe ?
867        "You could just symlink it to $maybe->[0]" :
868        'You might need to install Perl from source';
869    $self->phat_warn(<<EOF);
870Your Perl is configured to link against lib$name,
871  but lib$name.so was not found.
872  $suggest
873EOF
874}
875
876#--- user interaction ---
877
878sub prompt {
879    my ($self, $q, $default) = @_;
880    return $default if $self->{MP_PROMPT_DEFAULT};
881    require ExtUtils::MakeMaker;
882    ExtUtils::MakeMaker::prompt($q, $default);
883}
884
885sub prompt_y {
886    my ($self, $q) = @_;
887    $self->prompt($q, 'y') =~ /^y/i;
888}
889
890sub prompt_n {
891    my ($self, $q) = @_;
892    $self->prompt($q, 'n') =~ /^n/i;
893}
894
895sub phat_warn {
896    my ($self, $msg, $abort) = @_;
897    my $level = $abort ? 'ERROR' : 'WARNING';
898    warn <<EOF;
899************* $level *************
900
901  $msg
902
903************* $level *************
904EOF
905    if ($abort) {
906        exit 1;
907    }
908    else {
909        sleep 5;
910    }
911}
912
913#--- constructors ---
914
915my $bpm = 'Apache2/BuildConfig.pm';
916
917sub build_config {
918    my $self = shift;
919    my $bpm_mtime = 0;
920
921    $bpm_mtime = (stat _)[9] if $INC{$bpm} && -e $INC{$bpm};
922
923    if (-e "lib/$bpm" and (stat _)[9] > $bpm_mtime) {
924        #reload if Makefile.PL has regenerated
925        unshift @INC, 'lib';
926        delete $INC{$bpm};
927        eval { require Apache2::BuildConfig; };
928        shift @INC;
929    }
930    else {
931        eval { require Apache2::BuildConfig; };
932    }
933
934    return bless {}, (ref($self) || $self) if $@;
935    return Apache2::BuildConfig->new;
936}
937
938sub new {
939    my $class = shift;
940
941    my $self = bless {
942        cwd        => Cwd::fastcwd(),
943        MP_LIBNAME => 'mod_perl',
944        MP_APXS    => undef, # so we know we haven't tried to set it yet
945        @_,
946    }, $class;
947
948    $self->{MP_APR_LIB} = 'aprext';
949
950    ModPerl::BuildOptions->init($self) if delete $self->{init};
951
952    $self;
953}
954
955sub DESTROY {}
956
957my %default_files = (
958    'build_config' => 'lib/Apache2/BuildConfig.pm',
959    'ldopts'       => 'src/modules/perl/ldopts',
960    'makefile'     => 'src/modules/perl/Makefile',
961);
962
963sub clean_files {
964    my $self = shift;
965    [sort map { $self->default_file($_) } keys %default_files];
966}
967
968sub default_file {
969    my ($self, $name, $override) = @_;
970    my $key = join '_', 'file', $name;
971    $self->{$key} ||= ($override || $default_files{$name});
972}
973
974sub file_path {
975    my $self = shift;
976
977    # work around when Apache2::BuildConfig has not been created yet
978    return unless $self && $self->{cwd};
979
980    my @files = map { m:^/: ? $_ : join('/', $self->{cwd}, $_) } @_;
981    return wantarray ? @files : $files[0];
982}
983
984sub freeze {
985    require Data::Dumper;
986    local $Data::Dumper::Terse    = 1;
987    local $Data::Dumper::Sortkeys = 1;
988    my $data = Data::Dumper::Dumper(shift);
989    chomp $data;
990    $data;
991}
992
993sub save_ldopts {
994    my ($self, $file) = @_;
995
996    $file ||= $self->default_file('ldopts', $file);
997    my $ldopts = $self->ldopts;
998
999    open my $fh, '>', $file or die "open $file: $!";
1000    print $fh "#!/bin/sh\n\necho $ldopts\n";
1001    close $fh;
1002    chmod 0755, $file;
1003}
1004
1005sub noedit_warning_hash {
1006    ModPerl::Code::noedit_warning_hash(__PACKAGE__);
1007}
1008
1009sub save {
1010    my ($self, $file) = @_;
1011
1012    delete $INC{$bpm};
1013
1014    $file ||= $self->default_file('build_config');
1015    $file = $self->file_path($file);
1016
1017    my $obj = $self->freeze;
1018    $obj =~ s/^\s{9}//mg;
1019    $obj =~ s/^/    /;
1020
1021    open my $fh, '>', $file or die "open $file: $!";
1022
1023    #work around autosplit braindeadness
1024    my $package = 'package Apache2::BuildConfig';
1025
1026    print $fh noedit_warning_hash();
1027
1028    print $fh <<EOF;
1029$package;
1030
1031use Apache2::Build ();
1032
1033sub new {
1034$obj;
1035}
1036
10371;
1038EOF
1039
1040    close $fh or die "failed to write $file: $!";
1041}
1042
1043sub rebuild {
1044    my $self = __PACKAGE__->build_config;
1045    my @opts = map { qq[$_='$self->{$_}'] } sort grep /^MP_/,  keys %$self;
1046    my $command = "perl Makefile.PL @opts";
1047    print "Running: $command\n";
1048    system $command;
1049}
1050# % perl -MApache2::Build -e rebuild
1051*main::rebuild = \&rebuild if $0 eq '-e';
1052
1053#--- attribute access ---
1054
1055sub is_dynamic { shift->{MP_USE_DSO} }
1056
1057sub default_dir {
1058    my $build = shift->build_config;
1059
1060    return $build->dir || '../apache_x.x/src';
1061}
1062
1063sub dir {
1064    my ($self, $dir) = @_;
1065
1066    if ($dir) {
1067        for (qw(ap_includedir)) {
1068            delete $self->{$_};
1069        }
1070        if ($dir =~ m:^\.\.[/\\]:) {
1071            $dir = "$self->{cwd}/$dir";
1072        }
1073        $self->{dir} = $dir;
1074    }
1075
1076    return $self->{dir} if $self->{dir};
1077
1078    # be careful with the guesswork, or may pick up some wrong headers
1079    if (IS_MOD_PERL_BUILD && $self->{MP_AP_PREFIX}) {
1080        my $build = $self->build_config;
1081
1082        if (my $bdir = $build->{'dir'}) {
1083            for ($bdir, "../$bdir", "../../$bdir") {
1084                if (-d $_) {
1085                    $dir = $_;
1086                    last;
1087                }
1088            }
1089        }
1090    }
1091
1092    $dir ||= $self->{MP_AP_PREFIX};
1093
1094# we no longer install Apache headers, so don't bother looking in @INC
1095# might end up finding 1.x headers anyhow
1096#    unless ($dir and -d $dir) {
1097#        for (@INC) {
1098#            last if -d ($dir = "$_/auto/Apache2/include");
1099#        }
1100#    }
1101    return $self->{dir} = $dir ? canonpath(rel2abs $dir) : undef;
1102}
1103
1104#--- finding apache *.h files ---
1105
1106sub find {
1107    my $self = shift;
1108    my %seen = ();
1109    my @dirs = ();
1110
1111    for my $src_dir ($self->dir,
1112                     $self->default_dir,
1113                     '../httpd-2.0')
1114      {
1115          next unless $src_dir;
1116          next unless (-d $src_dir || -l $src_dir);
1117          next if $seen{$src_dir}++;
1118          push @dirs, $src_dir;
1119          #$modified{$src_dir} = (stat($src_dir))[9];
1120      }
1121
1122    return @dirs;
1123}
1124
1125sub ap_includedir  {
1126    my ($self, $d) = @_;
1127
1128    return $self->{ap_includedir}
1129      if $self->{ap_includedir} and -d $self->{ap_includedir};
1130
1131    return unless $d ||= $self->apxs('-q' => 'INCLUDEDIR') || $self->dir;
1132
1133    if (-e "$d/include/ap_release.h") {
1134        return $self->{ap_includedir} = "$d/include";
1135    }
1136
1137    $self->{ap_includedir} = $d;
1138}
1139
1140# This is necessary for static builds that needs to make a
1141# difference between where the apache headers are (to build
1142# against) and where they will be installed (to install our
1143# own headers alongside)
1144#
1145# ap_exp_includedir is where apache is going to install its
1146# headers to
1147sub ap_exp_includedir {
1148    my ($self) = @_;
1149
1150    return $self->{ap_exp_includedir} if $self->{ap_exp_includedir};
1151
1152    my $build_vars = File::Spec->catfile($self->{MP_AP_PREFIX},
1153                                         qw(build config_vars.mk));
1154    open my $vars, "<$build_vars" or die "Couldn't open $build_vars $!";
1155    my $ap_exp_includedir;
1156    while (<$vars>) {
1157        if (/exp_includedir\s*=\s*(.*)/) {
1158            $ap_exp_includedir = $1;
1159            last;
1160        }
1161    }
1162
1163    $self->{ap_exp_includedir} = $ap_exp_includedir;
1164}
1165
1166sub install_headers_dir {
1167    my ($self) = @_;
1168    if ($self->should_build_apache) {
1169        return $self->ap_exp_includedir();
1170    }
1171    else {
1172        return $self->ap_includedir();
1173    }
1174}
1175
1176
1177# where apr-config and apu-config reside
1178sub apr_bindir {
1179    my ($self) = @_;
1180
1181    $self->apr_config_path unless $self->{apr_bindir};
1182    $self->{apr_bindir};
1183}
1184
1185sub apr_generation {
1186    my ($self) = @_;
1187    return $self->httpd_version_as_int =~ m/2[1-9]\d+/ ? 1 : 0;
1188}
1189
1190# returns an array of apr/apu linking flags (--link-ld --libs) if found
1191# an empty array otherwise
1192my @apru_link_flags = ();
1193sub apru_link_flags {
1194    my ($self) = @_;
1195
1196    return @apru_link_flags if @apru_link_flags;
1197
1198    # first use apu_config_path and then apr_config_path in order to
1199    # resolve the symbols right during linking
1200    for ($self->apu_config_path, $self->apr_config_path) {
1201        my $flags = '--link-ld --libs';
1202        $flags .= ' --ldflags' unless (WIN32);
1203        if (my $link = $_ && -x $_ && qx{$_ $flags}) {
1204            chomp $link;
1205
1206            # Change '/path/to/libanything.la' to '-L/path/to -lanything'
1207            if (CYGWIN) {
1208                $link =~ s|(\S*)/lib([^.\s]+)\.\S+|-L$1 -l$2|g;
1209            }
1210
1211            if ($self->httpd_is_source_tree) {
1212                my @libs;
1213                while ($link =~ m/-L(\S+)/g) {
1214                    my $dir = File::Spec->catfile($1, '.libs');
1215                    push @libs, $dir if -d $dir;
1216                }
1217                push @apru_link_flags, join ' ', map { "-L$_" } @libs;
1218            }
1219            push @apru_link_flags, $link;
1220        }
1221    }
1222
1223    return @apru_link_flags;
1224}
1225
1226sub apr_config_path {
1227    shift->apru_config_path("apr");
1228}
1229
1230sub apu_config_path {
1231    shift->apru_config_path("apu");
1232}
1233
1234sub apru_config_path {
1235    my ($self, $what) = @_;
1236
1237    my $key = "${what}_config_path"; # apr_config_path
1238    my $mp_key = "MP_" . uc($what) . "_CONFIG"; # MP_APR_CONFIG
1239    my $bindir = uc($what) . "_BINDIR"; # APR_BINDIR
1240
1241    return $self->{$key} if $self->{$key} and -x $self->{$key};
1242
1243    if (exists $self->{$mp_key} and -x $self->{$mp_key}) {
1244        $self->{$key} = $self->{$mp_key};
1245    }
1246
1247    my $config = $self->apr_generation ? "$what-1-config" : "$what-config";
1248
1249    if (!$self->{$key}) {
1250        my @tries = ();
1251        if ($self->httpd_is_source_tree) {
1252            for my $base (grep defined $_, $self->dir) {
1253                push @tries, grep -d $_,
1254                    map catdir($base, "srclib", $_), qw(apr apr-util);
1255            }
1256
1257            # Check for MP_AP_CONFIGURE="--with-apr[-util]=DIR|FILE"
1258            my $what_long = ($what eq 'apu') ? 'apr-util' : 'apr';
1259            if ($self->{MP_AP_CONFIGURE} &&
1260                $self->{MP_AP_CONFIGURE} =~ /--with-${what_long}=(\S+)/) {
1261                my $dir = $1;
1262                $dir = dirname $dir if -f $dir;
1263                push @tries, grep -d $_, $dir, catdir $dir, 'bin';
1264            }
1265        }
1266        else {
1267            push @tries, grep length,
1268                map $self->apxs(-q => $_), $bindir, "BINDIR";
1269            push @tries, catdir $self->{MP_AP_PREFIX}, "bin"
1270                if exists $self->{MP_AP_PREFIX} and -d $self->{MP_AP_PREFIX};
1271        }
1272
1273        @tries = map { catfile $_, $config } @tries;
1274        if (WIN32) {
1275            my $ext = '.bat';
1276            for (@tries) {
1277                $_ .= $ext if ($_ and $_ !~ /$ext$/);
1278            }
1279        }
1280
1281        for my $try (@tries) {
1282            next unless -x $try;
1283            $self->{$key} = $try;
1284        }
1285    }
1286
1287    $self->{$key} ||= Apache::TestConfig::which($config);
1288
1289    # apr_bindir makes sense only if httpd/apr is installed, if we are
1290    # building against the source tree we can't link against
1291    # apr/aprutil libs
1292    unless ($self->httpd_is_source_tree) {
1293        $self->{apr_bindir} = $self->{$key}
1294            ? dirname $self->{$key}
1295            : '';
1296        }
1297
1298    $self->{$key};
1299}
1300
1301sub apr_includedir {
1302    my ($self) = @_;
1303
1304    return $self->{apr_includedir}
1305        if $self->{apr_includedir} and -d $self->{apr_includedir};
1306
1307    my $incdir;
1308    my $apr_config_path = $self->apr_config_path;
1309
1310    if ($apr_config_path) {
1311        my $httpd_version = $self->httpd_version;
1312        chomp($incdir = `$apr_config_path --includedir`);
1313    }
1314
1315    unless ($incdir and -d $incdir) {
1316        # falling back to the default when apr header files are in the
1317        # same location as the httpd header files
1318        $incdir = $self->ap_includedir;
1319    }
1320
1321    my @tries = ($incdir);
1322    if ($self->httpd_is_source_tree) {
1323        my $path = catdir $self->dir, "srclib", "apr", "include";
1324        push @tries, $path if -d $path;
1325    }
1326
1327
1328    for (@tries) {
1329        next unless $_ && -e catfile $_, "apr.h";
1330        $self->{apr_includedir} = $_;
1331        last;
1332    }
1333
1334    unless ($self->{apr_includedir}) {
1335        error "Can't find apr include/ directory,",
1336            "use MP_APR_CONFIG=/path/to/apr-config";
1337        exit 1;
1338    }
1339
1340    $self->{apr_includedir};
1341}
1342
1343#--- parsing apache *.h files ---
1344
1345sub mmn_eq {
1346    my ($class, $dir) = @_;
1347
1348    return 1 if WIN32; #just assume, till Apache2::Build works under win32
1349
1350    my $instsrc;
1351    {
1352        local @INC = grep { !/blib/ } @INC;
1353        my $instdir;
1354        for (@INC) {
1355            last if -d ($instdir = "$_/auto/Apache2/include");
1356        }
1357        $instsrc = $class->new(dir => $instdir);
1358    }
1359    my $targsrc = $class->new($dir ? (dir => $dir) : ());
1360
1361    my $inst_mmn = $instsrc->module_magic_number;
1362    my $targ_mmn = $targsrc->module_magic_number;
1363
1364    unless ($inst_mmn && $targ_mmn) {
1365        return 0;
1366    }
1367    if ($inst_mmn == $targ_mmn) {
1368        return 1;
1369    }
1370    print "Installed MMN $inst_mmn does not match target $targ_mmn\n";
1371
1372    return 0;
1373}
1374
1375sub module_magic_number {
1376    my $self = shift;
1377
1378    return $self->{mmn} if $self->{mmn};
1379
1380    my $d = $self->ap_includedir;
1381
1382    return 0 unless $d;
1383
1384    #return $mcache{$d} if $mcache{$d};
1385    my $fh;
1386    for (qw(ap_mmn.h http_config.h)) {
1387        last if open $fh, "$d/$_";
1388    }
1389    return 0 unless $fh;
1390
1391    my $n;
1392    my $mmn_pat = join '|', qw(MODULE_MAGIC_NUMBER_MAJOR MODULE_MAGIC_NUMBER);
1393    while(<$fh>) {
1394        if(s/^\#define\s+($mmn_pat)\s+(\d+).*/$2/) {
1395           chomp($n = $_);
1396           last;
1397       }
1398    }
1399    close $fh;
1400
1401    $self->{mmn} = $n
1402}
1403
1404sub fold_dots {
1405    my $v = shift;
1406    $v =~ s/\.//g;
1407    $v .= '0' if length $v < 3;
1408    $v;
1409}
1410
1411sub httpd_version_as_int {
1412    my ($self, $dir) = @_;
1413    my $v = $self->httpd_version($dir);
1414    fold_dots($v);
1415}
1416
1417sub httpd_version_cache {
1418    my ($self, $dir, $v) = @_;
1419    return '' unless $dir;
1420    $self->{httpd_version}->{$dir} = $v if $v;
1421    $self->{httpd_version}->{$dir};
1422}
1423
1424sub httpd_version {
1425    my ($self, $dir) = @_;
1426
1427    return unless $dir = $self->ap_includedir($dir);
1428
1429    if (my $v = $self->httpd_version_cache($dir)) {
1430        return $v;
1431    }
1432
1433    my $header = "$dir/ap_release.h";
1434    open my $fh, $header or do {
1435        error "Unable to open $header: $!";
1436        return undef;
1437    };
1438
1439    my $version;
1440
1441    while (<$fh>) {
1442        #now taking bets on how many friggin times this will change
1443        #over the course of apache 2.0.  1.3 changed it at least a half
1444        #dozen times.  hopefully it'll stay in the same file at least.
1445        if (/^\#define\s+AP_SERVER_MAJORVERSION\s+\"(\d+)\"/) {
1446            #XXX could be more careful here.  whatever.  see above.
1447            my $major = $1;
1448            my $minor = (split /\s+/, scalar(<$fh>))[-1];
1449            my $patch = (split /\s+/, scalar(<$fh>))[-1];
1450            $version = join '.', $major, $minor, $patch;
1451            $version =~ s/\"//g;
1452            last;
1453        }
1454        elsif (/^\#define\s+AP_SERVER_BASEREVISION\s+\"(.*)\"/) {
1455            $version = $1;
1456            last;
1457        }
1458        elsif(/^\#define\s+AP_SERVER_MAJORVERSION_NUMBER\s+(\d+)/) {
1459            # new 2.1 config
1460            my $major = $1;
1461            my $minor = (split /\s+/, scalar(<$fh>))[-1];
1462            my $patch = (split /\s+/, scalar(<$fh>))[-1];
1463
1464            my ($define, $macro, $dev) = (split /\s+/, scalar(<$fh>));
1465
1466            if ($macro =~ /AP_SERVER_DEVBUILD_BOOLEAN/ && $dev eq '1') {
1467                $dev = "-dev";
1468            }
1469            else {
1470                $dev = "";
1471            }
1472
1473            $version = join '.', $major, $minor, "$patch$dev";
1474            $version =~ s/\"//g;
1475            last;
1476        }
1477    }
1478
1479    close $fh;
1480
1481    debug "parsed version $version from ap_release.h";
1482
1483    $self->httpd_version_cache($dir, $version);
1484}
1485
1486my %wanted_apr_config = map { $_, 1} qw(
1487    HAS_THREADS HAS_DSO HAS_MMAP HAS_RANDOM HAS_SENDFILE
1488    HAS_LARGE_FILES HAS_INLINE HAS_FORK
1489);
1490
1491sub get_apr_config {
1492    my $self = shift;
1493
1494    return $self->{apr_config} if $self->{apr_config};
1495
1496    my $header = catfile $self->apr_includedir, "apr.h";
1497    open my $fh, $header or do {
1498        error "Unable to open $header: $!";
1499        return undef;
1500    };
1501
1502    my %cfg;
1503    while (<$fh>) {
1504        next unless s/^\#define\s+APR_((HAVE|HAS|USE)_\w+)/$1/;
1505        chomp;
1506        my ($name, $val) = split /\s+/, $_, 2;
1507        next unless $wanted_apr_config{$name};
1508        $val =~ s/\s+$//;
1509        next unless $val =~ /^\d+$/;
1510        $cfg{$name} = $val;
1511    }
1512
1513    $self->{apr_config} = \%cfg;
1514}
1515
1516#--- generate Makefile ---
1517
1518sub canon_make_attr {
1519    my ($self, $name) = (shift, shift);
1520
1521    my $attr = join '_', 'MODPERL', uc $name;
1522    $self->{$attr} = "@_";
1523    "$attr = $self->{$attr}\n\n";
1524}
1525
1526sub xsubpp {
1527    my $self = shift;
1528    my $xsubpp = join ' ', '$(MODPERL_PERLPATH)',
1529      '$(MODPERL_PRIVLIBEXP)/ExtUtils/xsubpp',
1530        '-typemap', '$(MODPERL_PRIVLIBEXP)/ExtUtils/typemap';
1531
1532    my $typemap = $self->file_path('lib/typemap');
1533    if (-e $typemap) {
1534        $xsubpp .= join ' ',
1535          ' -typemap', $typemap;
1536    }
1537
1538    $xsubpp;
1539}
1540
1541sub make_xs {
1542    my ($self, $fh) = @_;
1543
1544    print $fh $self->canon_make_attr(xsubpp => $self->xsubpp);
1545
1546    return [] unless $self->{XS};
1547
1548    my @files;
1549    my @xs_targ;
1550
1551    foreach my $name (sort keys %{ $self->{XS} }) {
1552        my $xs = $self->{XS}->{$name};
1553        #Foo/Bar.xs => Foo_Bar.c
1554        (my $c = $xs) =~ s:.*?WrapXS/::;
1555        $c =~ s:/:_:g;
1556        $c =~ s:\.xs$:.c:;
1557
1558        push @files, $c;
1559
1560        push @xs_targ, <<EOF;
1561$c: $xs
1562\t\$(MODPERL_XSUBPP) $xs > \$*.xsc && \$(MODPERL_MV) \$*.xsc \$@
1563
1564EOF
1565    }
1566
1567    my %o = (xs_o_files => 'o', xs_o_pic_files => 'lo');
1568
1569    for my $ext (qw(xs_o_files xs_o_pic_files)) {
1570        print $fh $self->canon_make_attr($ext, map {
1571            (my $file = $_) =~ s/c$/$o{$ext}/; $file;
1572        } @files);
1573    }
1574
1575    print $fh $self->canon_make_attr(xs_clean_files => @files);
1576
1577    \@xs_targ;
1578}
1579
1580#when we use a bit of MakeMaker, make it use our values for these vars
1581my %perl_config_pm_alias = (
1582    ABSPERL      => 'perlpath',
1583    ABSPERLRUN   => 'perlpath',
1584    PERL         => 'perlpath',
1585    PERLRUN      => 'perlpath',
1586    PERL_LIB     => 'privlibexp',
1587    PERL_ARCHLIB => 'archlibexp',
1588);
1589
1590my $mm_replace = join '|', keys %perl_config_pm_alias;
1591
1592# get rid of dups
1593my %perl_config_pm_alias_values = reverse %perl_config_pm_alias;
1594my @perl_config_pm_alias_values = keys %perl_config_pm_alias_values;
1595
1596my @perl_config_pm = sort(@perl_config_pm_alias_values, qw(cc cpprun
1597    rm ranlib lib_ext obj_ext cccdlflags lddlflags optimize));
1598
1599sub mm_replace {
1600    my $val = shift;
1601    $$val =~ s/\(($mm_replace)\)/(MODPERL_\U$perl_config_pm_alias{$1})/g;
1602}
1603
1604#help prevent warnings
1605my @mm_init_vars = (BASEEXT => '');
1606
1607sub make_tools {
1608    my ($self, $fh) = @_;
1609
1610    for (@perl_config_pm) {
1611        print $fh $self->canon_make_attr($_, $self->perl_config($_));
1612    }
1613
1614    require ExtUtils::MakeMaker;
1615    my $mm = bless { @mm_init_vars }, 'MM';
1616
1617    # Fake initialize MakeMaker
1618    foreach my $m (qw(init_main init_others init_tools)) {
1619        $mm->$m() if $mm->can($m);
1620    }
1621
1622    for (qw(rm_f mv ld ar cp test_f)) {
1623        my $val = $mm->{"\U$_"};
1624        if ($val) {
1625            mm_replace(\$val);
1626        }
1627        else {
1628            $val = $Config{$_};
1629        }
1630        print $fh $self->canon_make_attr($_ => $val);
1631    }
1632}
1633
1634sub export_files_MSWin32 {
1635    my $self = shift;
1636    my $xs_dir = $self->file_path("xs");
1637    "-def:$xs_dir/modperl.def";
1638}
1639
1640sub export_files_aix {
1641    my $self = shift;
1642
1643    my $Wl = $self->ldopts_prefix;
1644    # there are several modperl_*.exp, not just $(BASEEXT).exp
1645    # $(BASEEXT).exp resolves to modperl_global.exp
1646    my $xs_dir = $self->file_path("xs");
1647    join " ", map "${Wl}-bE:$xs_dir/modperl_$_.exp", qw(inline ithreads);
1648}
1649
1650sub dynamic_link_header_default {
1651    return <<'EOF';
1652$(MODPERL_LIBNAME).$(MODPERL_DLEXT): $(MODPERL_PIC_OBJS)
1653	$(MODPERL_RM_F) $@
1654	$(MODPERL_LD) $(MODPERL_LDDLFLAGS) \
1655	$(MODPERL_AP_LIBS) \
1656	$(MODPERL_PIC_OBJS) $(MODPERL_LDOPTS) \
1657EOF
1658}
1659
1660sub dynamic_link_default {
1661    my $self = shift;
1662
1663    my $link = $self->dynamic_link_header_default . "\t" . '-o $@';
1664
1665    my $ranlib = "\t" . '$(MODPERL_RANLIB) $@' . "\n";
1666
1667    $link .= "\n" . $ranlib unless (DARWIN or OPENBSD);
1668
1669    $link;
1670}
1671
1672sub dynamic_link_MSWin32 {
1673    my $self = shift;
1674    my $defs = $self->export_files_MSWin32;
1675    my $symbols = $self->modperl_symbols_MSWin32;
1676    return $self->dynamic_link_header_default .
1677        "\t$defs" .
1678        ($symbols ? ' \\' . "\n\t-pdb:$symbols" : '') .
1679        ' -out:$@' . "\n\t" .
1680        'if exist $(MODPERL_MANIFEST_LOCATION)' . " \\\n\t" .
1681        'mt /nologo /manifest $(MODPERL_MANIFEST_LOCATION)' . " \\\n\t" .
1682        '/outputresource:$@;2' . "\n\n";
1683}
1684
1685sub dynamic_link_aix {
1686    my $self = shift;
1687    my $link = $self->dynamic_link_header_default .
1688        "\t" . $self->export_files_aix . " \\\n" .
1689        "\t" . '-o $@' . " \n" .
1690        "\t" . '$(MODPERL_RANLIB) $@';
1691}
1692
1693sub dynamic_link_cygwin {
1694    my $self = shift;
1695    return <<'EOF';
1696$(MODPERL_LIBNAME).$(MODPERL_DLEXT): $(MODPERL_PIC_OBJS)
1697	$(MODPERL_RM_F) $@
1698	$(MODPERL_CC) -shared -o $@ \
1699	-Wl,--out-implib=$(MODPERL_LIBNAME).dll.a \
1700	-Wl,--export-all-symbols -Wl,--enable-auto-import \
1701	-Wl,--enable-auto-image-base -Wl,--stack,8388608 \
1702	$(MODPERL_PIC_OBJS) \
1703	$(MODPERL_LDDLFLAGS) $(MODPERL_LDOPTS) \
1704	$(MODPERL_AP_LIBS)
1705	$(MODPERL_RANLIB) $@
1706EOF
1707}
1708
1709sub dynamic_link {
1710    my $self = shift;
1711    my $link = \&{"dynamic_link_$^O"};
1712    $link = \&dynamic_link_default unless defined &$link;
1713    $link->($self);
1714}
1715
1716# Returns the link flags for the apache shared core library
1717my $apache_corelib_cygwin;
1718sub apache_corelib_cygwin {
1719    return $apache_corelib_cygwin if $apache_corelib_cygwin;
1720
1721    my $self = shift;
1722    my $mp_src = "$self->{cwd}/src/modules/perl";
1723    my $core = 'httpd2core';
1724
1725    # There's a problem with user-installed perl on cygwin.
1726    # MakeMaker doesn't know about the .dll.a libs and warns
1727    # about missing -lhttpd2core. "Fix" it by copying
1728    # the lib and adding .a suffix.
1729    # For the static build create a soft link, because libhttpd2core.dll.a
1730    # doesn't exist at this time.
1731    if ($self->is_dynamic) {
1732        my $libpath = $self->apxs(-q => 'exp_libdir');
1733        File::Copy::copy("$libpath/lib$core.dll.a", "$mp_src/lib$core.a");
1734    } else {
1735        my $libpath = catdir($self->{MP_AP_PREFIX}, '.libs');
1736        mkdir $libpath unless -d $libpath;
1737        qx{touch $libpath/lib$core.dll.a && \
1738        ln -fs $libpath/lib$core.dll.a $mp_src/lib$core.a};
1739    }
1740
1741    $apache_corelib_cygwin = "-L$mp_src -l$core";
1742}
1743
1744sub apache_libs_MSWin32 {
1745    my $self = shift;
1746    my $prefix = $self->apxs(-q => 'PREFIX') || $self->dir;
1747    my $lib = catdir $prefix, 'lib';
1748    opendir(my $dir, $lib) or die qq{Cannot opendir $lib: $!};
1749    my @libs = map {catfile($lib, $_)}
1750        grep /^lib(apr|aprutil|httpd)\b\S*?\.lib$/, readdir $dir;
1751    closedir $dir;
1752    "@libs";
1753}
1754
1755sub apache_libs_cygwin {
1756    my $self = shift;
1757    join ' ', $self->apache_corelib_cygwin, $self->apru_link_flags;
1758}
1759
1760sub apache_libs {
1761    my $self = shift;
1762    my $libs = \&{"apache_libs_$^O"};
1763    return "" unless defined &$libs;
1764    $libs->($self);
1765}
1766
1767sub modperl_libs_MSWin32 {
1768    my $self = shift;
1769    "$self->{cwd}/src/modules/perl/$self->{MP_LIBNAME}.lib";
1770}
1771
1772sub modperl_libs_cygwin {
1773     my $self = shift;
1774     return '' unless $self->is_dynamic;
1775     return "-L$self->{cwd}/src/modules/perl -l$self->{MP_LIBNAME}";
1776}
1777
1778sub modperl_libs {
1779    my $self = shift;
1780    my $libs = \&{"modperl_libs_$^O"};
1781    return "" unless defined &$libs;
1782    $libs->($self);
1783}
1784
1785sub modperl_libpath_MSWin32 {
1786    my $self = shift;
1787    # mod_perl.lib will be installed into MP_AP_PREFIX/lib
1788    # for use by 3rd party xs modules
1789    "$self->{cwd}/src/modules/perl/$self->{MP_LIBNAME}.lib";
1790}
1791
1792sub modperl_libpath_cygwin {
1793    my $self = shift;
1794    "$self->{cwd}/src/modules/perl/$self->{MP_LIBNAME}.dll.a";
1795}
1796
1797sub modperl_libpath {
1798    my $self = shift;
1799    my $libpath = \&{"modperl_libpath_$^O"};
1800    return "" unless defined &$libpath;
1801    $libpath->($self);
1802}
1803
1804# returns the directory and name of the aprext lib built under blib/
1805sub mp_apr_blib {
1806    my $self = shift;
1807    return unless (my $mp_apr_lib = $self->{MP_APR_LIB});
1808    my $lib_mp_apr_lib = 'lib' . $mp_apr_lib;
1809    my @dirs = qw(blib arch auto);
1810    my $apr_blib = catdir $self->{cwd}, @dirs, $lib_mp_apr_lib;
1811    my $full_libname = $lib_mp_apr_lib . $Config{lib_ext};
1812    return ($apr_blib, $full_libname);
1813}
1814
1815sub mp_apr_lib_MSWin32 {
1816    my $self = shift;
1817    # The MP_APR_LIB will be installed into MP_AP_PREFIX/lib
1818    # for use by 3rd party xs modules
1819    my ($dir, $lib) = $self->mp_apr_blib();
1820    $lib =~ s[^lib(\w+)$Config{lib_ext}$][$1];
1821    $dir = Win32::GetShortPathName($dir);
1822    return qq{ -L$dir -l$lib };
1823}
1824
1825sub mp_apr_lib_cygwin {
1826    my $self = shift;
1827    my ($dir, $lib) = $self->mp_apr_blib();
1828    $lib =~ s[^lib(\w+)$Config{lib_ext}$][$1];
1829    my $libs = "-L$dir -l$lib";
1830
1831    # This is ugly, but is the only way to prevent the "undefined
1832    # symbols" error
1833    $libs .= join ' ', '',
1834        '-L' . catdir($self->perl_config('archlibexp'), 'CORE'), '-lperl';
1835
1836    $libs;
1837}
1838
1839# linking used for the aprext lib used to build APR/APR::*
1840sub mp_apr_lib {
1841    my $self = shift;
1842    my $libs = \&{"mp_apr_lib_$^O"};
1843    return "" unless defined &$libs;
1844    $libs->($self);
1845}
1846
1847sub modperl_symbols_MSWin32 {
1848    my $self = shift;
1849    return "" unless $self->{MP_DEBUG};
1850    "$self->{cwd}/src/modules/perl/$self->{MP_LIBNAME}.pdb";
1851}
1852
1853sub modperl_symbols {
1854    my $self = shift;
1855    my $symbols = \&{"modperl_symbols_$^O"};
1856    return "" unless defined &$symbols;
1857    $symbols->($self);
1858}
1859
1860sub write_src_makefile {
1861    my $self = shift;
1862    my $code = ModPerl::Code->new;
1863    my $path = $code->path;
1864
1865    my $install = <<'EOI';
1866install:
1867EOI
1868    if (!$self->should_build_apache) {
1869        $install .= <<'EOI';
1870# install mod_perl.so
1871	@$(MKPATH) $(DESTDIR)$(MODPERL_AP_LIBEXECDIR)
1872	$(MODPERL_TEST_F) $(MODPERL_LIB_DSO) && \
1873	$(MODPERL_CP) $(MODPERL_LIB_DSO) $(DESTDIR)$(MODPERL_AP_LIBEXECDIR)
1874EOI
1875    }
1876
1877    $install .= <<'EOI';
1878# install mod_perl .h files
1879	@$(MKPATH) $(DESTDIR)$(MODPERL_AP_INCLUDEDIR)
1880	$(MODPERL_CP) $(MODPERL_H_FILES) $(DESTDIR)$(MODPERL_AP_INCLUDEDIR)
1881EOI
1882
1883    my $mf = $self->default_file('makefile');
1884
1885    open my $fh, '>', $mf or die "open $mf: $!";
1886
1887    print $fh noedit_warning_hash();
1888
1889    print $fh $self->canon_make_attr('makefile', basename $mf);
1890
1891    $self->make_tools($fh);
1892
1893    print $fh $self->canon_make_attr('ap_libs', $self->apache_libs);
1894
1895    print $fh $self->canon_make_attr('libname', $self->{MP_LIBNAME});
1896    print $fh $self->canon_make_attr('dlext', 'so'); #always use .so
1897
1898    if (AIX) {
1899        my $xs_dir = $self->file_path("xs");
1900        print $fh "BASEEXT = $xs_dir/modperl_global\n\n";
1901    }
1902
1903    my %libs = (
1904        dso    => "$self->{MP_LIBNAME}.$self->{MODPERL_DLEXT}",
1905        static => "$self->{MP_LIBNAME}$self->{MODPERL_LIB_EXT}",
1906    );
1907
1908    #XXX short-term compat for Apache::TestConfigPerl
1909    $libs{shared} = $libs{dso};
1910
1911    foreach my $type (sort keys %libs) {
1912        my $lib = $libs{$type};
1913        print $fh $self->canon_make_attr("lib_$type", $libs{$type});
1914    }
1915
1916    if (my $symbols = $self->modperl_symbols) {
1917        print $fh $self->canon_make_attr('lib_symbols', $symbols);
1918        $install .= <<'EOI';
1919# install mod_perl symbol file
1920	@$(MKPATH) $(MODPERL_AP_LIBEXECDIR)
1921	$(MODPERL_TEST_F) $(MODPERL_LIB_SYMBOLS) && \
1922	$(MODPERL_CP) $(MODPERL_LIB_SYMBOLS) $(MODPERL_AP_LIBEXECDIR)
1923EOI
1924    }
1925
1926    if ($self->is_dynamic && (my $libs = $self->modperl_libpath)) {
1927        print $fh $self->canon_make_attr('lib_location', $libs);
1928
1929        # Visual Studio 8 on Win32 uses manifest files
1930        if (WIN32) {
1931            (my $manifest = $libs) =~ s/\.lib$/.so.manifest/;
1932            print $fh $self->canon_make_attr('manifest_location', $manifest);
1933        }
1934
1935        print $fh $self->canon_make_attr('ap_libdir',
1936            $self->ap_destdir(catdir $self->{MP_AP_PREFIX}, 'lib')
1937        );
1938
1939        $install .= <<'EOI';
1940# install mod_perl.lib
1941	@$(MKPATH) $(MODPERL_AP_LIBDIR)
1942	$(MODPERL_TEST_F) $(MODPERL_LIB_LOCATION) && \
1943	$(MODPERL_CP) $(MODPERL_LIB_LOCATION) $(MODPERL_AP_LIBDIR)
1944EOI
1945    }
1946
1947    my $libperl = join '/',
1948      $self->perl_config('archlibexp'), 'CORE', $self->perl_config('libperl');
1949
1950    #this is only used for deps, if libperl has changed, relink mod_perl.so
1951    #not all perl dists put libperl where it should be, so just leave this
1952    #out if it isn't in the proper place
1953    if (-e $libperl) {
1954        print $fh $self->canon_make_attr('libperl', $libperl);
1955    }
1956
1957    for my $method (qw(ccopts ldopts inc)) {
1958        print $fh $self->canon_make_attr($method, $self->$method());
1959    }
1960
1961    for my $method (qw(c_files o_files o_pic_files h_files)) {
1962        print $fh $self->canon_make_attr($method, @{ $code->$method() });
1963    }
1964
1965    my @libs;
1966    for my $type (sort map { uc } keys %libs) {
1967        next unless $self->{"MP_USE_$type"};
1968        # on win32 mod_perl.lib must come after mod_perl.so
1969        $type eq 'STATIC'
1970            ? push    @libs, $self->{"MODPERL_LIB_$type"}
1971            : unshift @libs, $self->{"MODPERL_LIB_$type"};
1972    }
1973
1974    print $fh $self->canon_make_attr('lib', "@libs");
1975
1976    print $fh $self->canon_make_attr('AP_INCLUDEDIR',
1977        $self->ap_destdir($self->install_headers_dir));
1978
1979    print $fh $self->canon_make_attr('AP_LIBEXECDIR',
1980        $self->ap_destdir($self->apxs(-q => 'LIBEXECDIR')));
1981
1982    my $xs_targ = $self->make_xs($fh);
1983
1984    print $fh <<'EOF';
1985MODPERL_CCFLAGS = $(MODPERL_INC) $(MODPERL_CCOPTS) $(MODPERL_OPTIMIZE)
1986
1987MODPERL_CCFLAGS_SHLIB = $(MODPERL_CCFLAGS) $(MODPERL_CCCDLFLAGS)
1988
1989MODPERL_OBJS = $(MODPERL_O_FILES) $(MODPERL_XS_O_FILES)
1990
1991MODPERL_PIC_OBJS = $(MODPERL_O_PIC_FILES) $(MODPERL_XS_O_PIC_FILES)
1992
1993MKPATH = $(MODPERL_PERLPATH) "-MExtUtils::Command" -e mkpath
1994
1995all: lib
1996
1997lib: $(MODPERL_LIB)
1998
1999EOF
2000
2001    print $fh $install;
2002
2003    print $fh <<'EOF' if DMAKE;
2004
2005.USESHELL :
2006EOF
2007
2008    print $fh <<'EOF';
2009
2010.SUFFIXES: .xs .c $(MODPERL_OBJ_EXT) .lo .i .s
2011
2012.c.lo:
2013	$(MODPERL_CC) $(MODPERL_CCFLAGS_SHLIB) \
2014	-c $< && $(MODPERL_MV) $*$(MODPERL_OBJ_EXT) $*.lo
2015
2016.c$(MODPERL_OBJ_EXT):
2017	$(MODPERL_CC) $(MODPERL_CCFLAGS) -c $<
2018
2019.c.i:
2020	$(MODPERL_CPPRUN) $(MODPERL_CCFLAGS) -c $< > $*.i
2021
2022.c.s:
2023	$(MODPERL_CC) -O -S $(MODPERL_CCFLAGS) -c $<
2024
2025.xs.c:
2026	$(MODPERL_XSUBPP) $*.xs >$@
2027
2028.xs$(MODPERL_OBJ_EXT):
2029	$(MODPERL_XSUBPP) $*.xs >$*.c
2030	$(MODPERL_CC) $(MODPERL_CCFLAGS) -c $*.c
2031
2032.xs.lo:
2033	$(MODPERL_XSUBPP) $*.xs >$*.c
2034	$(MODPERL_CC) $(MODPERL_CCFLAGS_SHLIB) \
2035	-c $*.c && $(MODPERL_MV) $*$(MODPERL_OBJ_EXT) $*.lo
2036
2037clean:
2038	$(MODPERL_RM_F) *.a *.so *.xsc \
2039	$(MODPERL_LIBNAME).exp $(MODPERL_LIBNAME).lib \
2040	*$(MODPERL_OBJ_EXT) *.lo *.i *.s *.pdb *.manifest \
2041	$(MODPERL_CLEAN_FILES) \
2042	$(MODPERL_XS_CLEAN_FILES)
2043
2044$(MODPERL_OBJS): $(MODPERL_H_FILES) $(MODPERL_MAKEFILE)
2045$(MODPERL_PIC_OBJS): $(MODPERL_H_FILES) $(MODPERL_MAKEFILE)
2046$(MODPERL_LIB): $(MODPERL_LIBPERL)
2047
2048$(MODPERL_LIBNAME)$(MODPERL_LIB_EXT): $(MODPERL_OBJS)
2049	$(MODPERL_RM_F) $@
2050	$(MODPERL_AR) crv $@ $(MODPERL_OBJS)
2051	$(MODPERL_RANLIB) $@
2052
2053EOF
2054
2055    print $fh $self->dynamic_link;
2056
2057    print $fh @$xs_targ;
2058
2059    print $fh "\n"; # Makefile must end with \n to avoid warnings
2060
2061    close $fh;
2062}
2063
2064#--- generate MakeMaker parameter values ---
2065
2066sub otherldflags_default {
2067    my $self = shift;
2068    # e.g. aix's V:ldflags feeds -brtl and other flags
2069    $self->perl_config('ldflags');
2070}
2071
2072sub otherldflags {
2073    my $self = shift;
2074    my $flags = \&{"otherldflags_$^O"};
2075    return $self->otherldflags_default unless defined &$flags;
2076    $flags->($self);
2077}
2078
2079sub otherldflags_MSWin32 {
2080    my $self = shift;
2081    my $flags = $self->otherldflags_default;
2082    $flags .= ' -pdb:$(INST_ARCHAUTODIR)\$(BASEEXT).pdb' if $self->{MP_DEBUG};
2083    $flags;
2084}
2085
2086sub typemaps {
2087    my $self = shift;
2088    my @typemaps = ();
2089
2090    # XXX: could move here the code from ModPerl::BuildMM
2091    return [] if IS_MOD_PERL_BUILD;
2092
2093    # for post install use
2094    for (@INC) {
2095        # make sure not to pick mod_perl 1.0 typemap
2096        my $file = "$_/auto/Apache2/typemap";
2097        push @typemaps, $file if -e $file;
2098    }
2099
2100    return \@typemaps;
2101}
2102
2103sub includes {
2104    my $self = shift;
2105
2106    my @inc = ();
2107
2108    unless (IS_MOD_PERL_BUILD) {
2109        # XXX: what if apxs is not available? win32?
2110        my $ap_inc = $self->apxs('-q' => 'INCLUDEDIR');
2111        if ($ap_inc && -d $ap_inc) {
2112            push @inc, $ap_inc;
2113            return \@inc;
2114        }
2115
2116        # this is fatal
2117        my $reason = $ap_inc
2118            ? "path $ap_inc doesn't exist"
2119            : "apxs -q INCLUDEDIR didn't return a value";
2120        die "Can't find the mod_perl include dir (reason: $reason)";
2121    }
2122
2123    my $os = WIN32 ? 'win32' : 'unix';
2124    push @inc, $self->file_path("src/modules/perl", "xs");
2125
2126    push @inc, $self->mp_include_dir;
2127
2128    unless ($self->httpd_is_source_tree) {
2129        push @inc, $self->apr_includedir;
2130
2131        my $apuc = $self->apu_config_path;
2132        if ($apuc && -x $apuc) {
2133            chomp(my $apuincs = qx($apuc --includes));
2134            # win32: /Ipath, elsewhere -Ipath
2135            $apuincs =~ s{^\s*(-|/)I}{};
2136            push @inc, $apuincs;
2137        }
2138
2139        my $ainc = $self->apxs('-q' => 'INCLUDEDIR');
2140        if (-d $ainc) {
2141            push @inc, $ainc;
2142            return \@inc;
2143        }
2144    }
2145
2146    if ($self->{MP_AP_PREFIX}) {
2147        my $src = $self->dir;
2148        for ("$src/modules/perl", "$src/include",
2149             "$src/srclib/apr/include",
2150             "$src/srclib/apr-util/include",
2151             "$src/os/$os")
2152            {
2153                push @inc, $_ if -d $_;
2154            }
2155    }
2156
2157    return \@inc;
2158}
2159
2160sub inc {
2161    local $_;
2162    my @includes = map { "-I$_" } @{ shift->includes };
2163    "@includes";
2164}
2165
2166### Picking the right LFS support flags for mod_perl, by Joe Orton ###
2167#
2168# on Unix systems where by default off_t is a "long", a 32-bit integer,
2169# there are two different ways to get "large file" support, i.e. the
2170# ability to manipulate files bigger than 2Gb:
2171#
2172# 1) you compile using -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64.  This
2173# makes sys/types.h expose off_t as a "long long", a 64-bit integer, and
2174# changes the size of a few other types too.  The C library headers
2175# automatically arrange to expose a correct implementation of functions
2176# like lseek() which take off_t parameters.
2177#
2178# 2) you compile using -D_LARGEFILE64_SOURCE, and use what is called the
2179# "transitional" interface.  This means that the system headers expose a
2180# new type, "off64_t", which is a long long, but the size of off_t is not
2181# changed.   A bunch of new functions like lseek64() are exposed by the C
2182# library headers, which take off64_t parameters in place of off_t.
2183#
2184# Perl built with -Duselargefiles uses approach (1).
2185#
2186# APR HEAD uses (2) by default. APR 0.9 does not by default use either
2187# approach, but random users can take a httpd-2.0.49 tarball, and do:
2188#
2189#   export CPPFLAGS="-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64"
2190#   ./configure
2191#
2192# to build a copy of apr/httpd which uses approach (1), though this
2193# isn't really a supported configuration.
2194#
2195# The problem that mod_perl has to work around is when you take a
2196# package built with approach (1), i.e. Perl, and any package which was
2197# *not* built with (1), i.e. APR, and want to interface between
2198# them. [1]
2199#
2200# So what you want to know is whether APR was built using approach (1)
2201# or not.  APR_HAS_LARGE_FILES in HEAD just tells you whether APR was
2202# built using approach (2) or not, which isn't useful in solving this
2203# problem.
2204#
2205# [1]: In some cases, it may be OK to interface between packages which
2206# use (1) and packages which use (2).  APR HEAD is currently not such a
2207# case, since the size of apr_ino_t is still changing when
2208# _FILE_OFFSET_BITS is defined.
2209#
2210# If you want to see how this matters, get some httpd function to do at
2211# the very beginning of main():
2212#
2213#   printf("sizeof(request_rec) = %lu, sizeof(apr_finfo_t) = %ul",
2214#          sizeof(request_rec), sizeof(apr_finfo_t));
2215#
2216# and then put the same printf in mod_perl somewhere, and see the
2217# differences. This is why it is a really terribly silly idea to ever
2218# use approach (1) in anything other than an entirely self-contained
2219# application.
2220#
2221# there is no conflict if both libraries either have or don't have
2222# large files support enabled
2223sub has_large_files_conflict {
2224    my $self = shift;
2225
2226    my $apxs_flags = join $self->apxs_extra_cflags, $self->apxs_extra_cppflags;
2227    my $apr_lfs64  = $apxs_flags      =~ /-D_FILE_OFFSET_BITS=64/;
2228    my $perl_lfs64 = $Config{ccflags} =~ /-D_FILE_OFFSET_BITS=64/;
2229
2230    # XXX: we don't really deal with the case where APR was built with
2231    # -D_FILE_OFFSET_BITS=64 but perl wasn't, since currently we strip
2232    # only perl's ccflags, not apr's flags. the reason we don't deal
2233    # with it is that we didn't have such a case yet, but may need to
2234    # deal with it later
2235
2236    return 0;
2237    # $perl_lfs64 ^ $apr_lfs64;
2238}
2239
2240# if perl is built with uselargefiles, but apr not, the build won't
2241# work together as it uses two binary incompatible libraries, so
2242# reduce the functionality to the greatest common denominator (C code
2243# will have to make sure to prevent any operations that may rely on
2244# effects created by uselargefiles, e.g. Off_t=8 instead of Off_t=4)
2245sub strip_lfs {
2246    my ($self, $cflags) = @_;
2247    return $cflags unless $self->has_large_files_conflict();
2248
2249    my $lf = $Config{ccflags_uselargefiles}
2250        || '-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64';
2251    $cflags =~ s/$lf//;
2252    $cflags;
2253}
2254
2255sub define {
2256    my $self = shift;
2257
2258    return "";
2259}
2260
22611;
2262
2263__END__
2264
2265=head1 NAME
2266
2267Apache2::Build - Methods for locating and parsing bits of Apache source code
2268
2269=head1 SYNOPSIS
2270
2271 use Apache2::Build ();
2272 my $build = Apache2::Build->new;
2273
2274 # rebuild mod_perl with build opts from the previous build
2275 % cd modperl-2.0
2276 % perl -MApache2::Build -e rebuild
2277
2278=head1 DESCRIPTION
2279
2280This module provides methods for locating and parsing bits of Apache
2281source code.
2282
2283Since mod_perl remembers what build options were used to build it, you
2284can use this knowledge to rebuild it using the same options. Simply
2285chdir to the mod_perl source directory and run:
2286
2287  % cd modperl-2.0
2288  % perl -MApache2::Build -e rebuild
2289
2290If you want to rebuild not yet installed, but already built mod_perl,
2291run from its root directory:
2292
2293  % perl -Ilib -MApache2::Build -e rebuild
2294
2295=head1 METHODS
2296
2297=over 4
2298
2299=item new
2300
2301Create an object blessed into the B<Apache2::Build> class.
2302
2303 my $build = Apache2::Build->new;
2304
2305=item dir
2306
2307Top level directory where source files are located.
2308
2309 my $dir = $build->dir;
2310 -d $dir or die "can't stat $dir $!\n";
2311
2312=item find
2313
2314Searches for apache source directories, return a list of those found.
2315
2316Example:
2317
2318 for my $dir ($build->find) {
2319    my $yn = prompt "Configure with $dir ?", "y";
2320    ...
2321 }
2322
2323=item inc
2324
2325Print include paths for MakeMaker's B<INC> argument to
2326C<WriteMakefile>.
2327
2328Example:
2329
2330 use ExtUtils::MakeMaker;
2331
2332 use Apache2::Build ();
2333
2334 WriteMakefile(
2335     'NAME'    => 'Apache2::Module',
2336     'VERSION' => '0.01',
2337     'INC'     => Apache2::Build->new->inc,
2338 );
2339
2340
2341=item module_magic_number
2342
2343Return the B<MODULE_MAGIC_NUMBER> defined in the apache source.
2344
2345Example:
2346
2347 my $mmn = $build->module_magic_number;
2348
2349=item httpd_version
2350
2351Return the server version.
2352
2353Example:
2354
2355 my $v = $build->httpd_version;
2356
2357=item otherldflags
2358
2359Return other ld flags for MakeMaker's B<dynamic_lib> argument to
2360C<WriteMakefile>. This might be needed on systems like AIX that need
2361special flags to the linker to be able to reference mod_perl or httpd
2362symbols.
2363
2364Example:
2365
2366 use ExtUtils::MakeMaker;
2367
2368 use Apache2::Build ();
2369
2370 WriteMakefile(
2371     'NAME'        => 'Apache2::Module',
2372     'VERSION'     => '0.01',
2373     'INC'         => Apache2::Build->new->inc,
2374     'dynamic_lib' => {
2375         'OTHERLDFLAGS' => Apache2::Build->new->otherldflags,
2376     },
2377 );
2378
2379=back
2380
2381
2382=head1 AUTHOR
2383
2384Doug MacEachern
2385
2386=cut
2387