1#!C:/Perl/bin/perl
2use strict;
3use warnings;
4use FindBin;
5use Getopt::Long;
6use File::Spec::Functions qw(devnull catfile catdir path);
7use Cwd;
8require Win32;
9use ExtUtils::MakeMaker;
10use File::Basename;
11use File::Path;
12my ($apache, $apxs, $debug, $help, $no_perl, $perl, $with_perl);
13my $VERSION = "2.09";
14my $result = GetOptions( 'with-apache2=s' => \$apache,
15			 'with-apache2-apxs=s' => \$apxs,
16			 'debug' => \$debug,
17			 'help' => \$help,
18                         'with-perl=s' => \$perl,
19                         'disable-perl-glue' => \$no_perl,
20                         'enable-perl-glue' => \$with_perl,
21                       );
22usage() if $help;
23
24my @path_ext;
25path_ext();
26$apache ||= search();
27my $apreq_home = Win32::GetShortPathName($FindBin::Bin);
28$apreq_home =~ s!/?win32$!!;
29$apreq_home =~ s!/!\\!g;
30
31my $doxygen = which('doxygen');
32my $doxysearch = which('doxysearch');
33my $cfg = $debug ? 'Debug' : 'Release';
34
35my @tests = qw(cookie parsers params version);
36my @test_files = map {catfile('library', 't', "$_.t")} @tests;
37generate_tests($apreq_home, \@tests);
38
39my %apr_libs;
40my $prog = apache_prog_name($apache);
41my @httpd_ver = httpd_version($prog);
42my $devnull = devnull();
43my %map = (
44    apr => $httpd_ver[1] == 2 ? 'libapr-1.lib' : 'libapr.lib',
45    apu => $httpd_ver[1] == 2 ? 'libaprutil-1.lib' : 'libaprutil.lib'
46);
47
48foreach my $what (qw(apr apu)) {
49    my $ap = ($httpd_ver[1] == 2) ?
50        "$what-1-config.bat" : "$what-config.bat";
51    my $cfg = catfile $apache, 'bin', $ap;
52    my $lib;
53    eval {$lib = qx{"$cfg" --$what-lib-file 2>$devnull;}};
54    if ($@ or not $lib or $lib =~ /usage/i) {
55        $apr_libs{$what} = catfile $apache, 'lib', $map{$what};
56    }
57    else {
58        chomp $lib;
59        $apr_libs{$what} = $lib;
60    }
61}
62
63my $version_check = catfile $apreq_home, 'build', 'version_check.pl';
64my $cmd = join ' ', ($^X, $version_check, 'perl_prereqs');
65chomp(my $prereq_string = qx{$cmd});
66
67open(my $make, '>Makefile') or die qq{Cannot open Makefile: $!};
68print $make <<"END";
69# Microsoft Developer Studio Generated NMAKE File.
70#   The following is a trick to get CPAN clients to follow prerequisites:
71#
72#    $prereq_string
73#
74
75# --- MakeMaker post_initialize section:
76
77APREQ_HOME=$apreq_home
78APR_LIB=$apr_libs{apr}
79APU_LIB=$apr_libs{apu}
80CFG=$cfg
81APACHE=$apache
82PERL=$^X
83RM_F=\$(PERL) -MExtUtils::Command -e rm_f
84DOXYGEN_CONF=\$(APREQ_HOME)\\build\\doxygen.conf.win32
85TEST_FILES = @test_files
86
87END
88
89print $make $_ while (<DATA>);
90
91unless (-x $apxs) {
92    my $apxs_trial = catfile $apache, 'bin', 'apxs.bat';
93    $apxs = (-e $apxs_trial) ? $apxs_trial : which('apxs');
94    unless ($apxs) {
95        $apxs = fetch_apxs() ? which('apxs') : '';
96    }
97}
98
99my $test = << 'END';
100TEST : TEST_APREQ2 PERL_TEST
101
102TEST_APREQ2: $(LIBAPREQ) $(MOD)
103	$(MAKE) /nologo /f $(CFG_HOME)\$(APREQ2_TEST).mak CFG="$(APREQ2_TEST) - Win32 $(CFG)" APACHE="$(APACHE)" APREQ_HOME="$(APREQ_HOME)" APR_LIB="$(APR_LIB)" APU_LIB="$(APU_LIB)"
104        set PATH=$(APREQ_HOME)\win32\libs;$(APACHE)\bin;$(PATH)
105        $(PERL) "-MExtUtils::Command::MM" "-e" "test_harness()" $(TEST_FILES)
106	cd $(APREQ_HOME)
107	$(MAKE) /nologo /f $(CFG_HOME)\$(CGITEST).mak CFG="$(CGITEST) - Win32 $(CFG)" APACHE="$(APACHE)" APREQ_HOME="$(APREQ_HOME)" APR_LIB="$(APR_LIB)" APU_LIB="$(APU_LIB)"
108        cd $(APREQ_HOME)
109END
110
111my $clean = << 'END';
112CLEAN:
113        cd $(LIBDIR)
114        $(RM_F) *.pch *.exe *.exp *.lib *.pdb *.ilk *.idb *.so *.dll *.obj *.manifest
115        cd $(TDIR)
116        $(RM_F) *.pch *.exe *.exp *.lib *.pdb *.ilk *.idb *.so *.dll *.obj *.manifest
117        cd $(APREQ_HOME)\module\t\c-modules
118        $(MAKE) clean
119        cd $(APREQ_HOME)
120!IF EXIST("$(PERLGLUE)\Makefile")
121        cd $(PERLGLUE)
122        $(MAKE) /nologo clean
123        cd $(APREQ_HOME)
124!ENDIF
125END
126
127if ($apxs) {
128    $test .= << "END";
129        cd \$(APREQ_MODULE)
130        \$(PERL) t\\TEST.PL -apxs $apxs
131        cd \$(APREQ_HOME)
132END
133    $clean .= << 'END';
134        cd $(APREQ_MODULE)
135        $(PERL) t\TEST.PL -clean
136        cd $(APREQ_HOME)
137END
138}
139
140print $make "\n", $test, "\n";
141print $make "\n", $clean, "\n";
142
143if ($doxygen and $doxysearch) {
144    print $make <<"END";
145
146docs:   \$(DOXYGEN_CONF)
147	cd \$(APREQ_HOME)
148        "$doxygen" \$(DOXYGEN_CONF)
149	cd \$(APREQ_HOME)
150
151END
152
153    my $bin_abspath = Win32::GetShortPathName(dirname($doxysearch));
154    open(my $conf, "$apreq_home/build/doxygen.conf.in")
155        or die "Cannot read $apreq_home/build/doxygen.conf.in: $!";
156    open(my $win32_conf, ">$apreq_home/build/doxygen.conf.win32")
157        or die "Cannot write to $apreq_home/build/doxygen.conf.win32: $!";
158    while (<$conf>) {
159        s/\@PERL\@/"$^X"/;
160        s/\@PACKAGE\@/libapreq2/;
161        s/\@VERSION\@/$VERSION/;
162        print $win32_conf $_;
163    }
164    close $conf;
165    close $win32_conf;
166}
167
168close $make;
169# generate_defs();
170
171if (not $no_perl and $] >= 5.008) {
172    my @args = ($^X, "$apreq_home/build/xsbuilder.pl", 'run', 'run');
173    chdir "$apreq_home/glue/perl";
174    system(@args) == 0 or die "system @args failed: $?";
175    chdir $apreq_home;
176}
177
178print << "END";
179
180A Makefile has been generated in $apreq_home.
181You can now run
182
183  nmake               - build the libapreq2 library and perl glue
184  nmake test          - run the supplied tests
185  nmake install       - install the C libraries and perl glue modules
186  nmake clean         - remove intermediate files
187  nmake docs          - build documents (requires doxygen)
188  nmake help          - list the nmake targets
189END
190    if ($doxygen) {
191print << 'END';
192  nmake docs          - builds documents
193
194END
195}
196
197my @args = ($^X, "$apreq_home/win32/apreq2_win32.pl",
198            "--with-apache2=$apache");
199system(@args) == 0 or warn "system @args failed: $?";
200
201sub usage {
202    print <<'END';
203
204 Usage: perl Configure.pl [--with-apache2=C:\Path\to\Apache2] [--debug]
205        perl Configure.pl --help
206
207Options:
208
209  --with-apache2=C:\Path\to\Apache2 : specify the top-level Apache2 directory
210  --debug                           : build a debug version
211  --disable-perl-glue               : skip building the perl glue
212  --help                            : print this help message
213
214With no options specified, an attempt will be made to find a suitable
215Apache2 directory, and if found, a non-debug version will be built.
216
217END
218    exit;
219}
220
221sub search {
222    my $apache;
223    if (my $bin = which('Apache')) {
224       (my $candidate = dirname($bin)) =~ s!bin$!!;
225        if (-d $candidate and check($candidate)) {
226            $apache = $candidate;
227        }
228    }
229    unless ($apache and -d $apache) {
230        $apache = prompt("Please give the path to your Apache2 installation:",
231                         $apache);
232    }
233    die "Can't find a suitable Apache2 installation!"
234        unless ($apache and -d $apache and check($apache));
235
236    $apache = Win32::GetShortPathName($apache);
237    $apache =~ s!\\!/!g;
238    $apache =~ s!/$!!;
239    my $ans = prompt(qq{\nUse "$apache" for your Apache2 directory?}, 'yes');
240    unless ($ans =~ /^y/i) {
241        die <<'END';
242
243Please run this configuration script again, and give
244the --with-apache2=C:\Path\to\Apache2 option to specify
245the desired top-level Apache2 directory.
246
247END
248    }
249    return $apache;
250}
251
252sub drives {
253    my @drives = ();
254    eval{require Win32API::File;};
255    return map {"$_:\\"} ('C' .. 'Z') if $@;
256    my @r = Win32API::File::getLogicalDrives();
257    return unless @r > 0;
258    for (@r) {
259        my $t = Win32API::File::GetDriveType($_);
260        push @drives, $_ if ($t == 3 or $t == 4);
261    }
262    return @drives > 0 ? @drives : undef;
263}
264
265sub check {
266    my $apache = shift;
267    die qq{No libhttpd library found under $apache/lib}
268        unless -e qq{$apache/lib/libhttpd.lib};
269    die qq{No httpd header found under $apache/include}
270        unless -e qq{$apache/include/httpd.h};
271    my $prog = apache_prog_name($apache);
272    my $vers = qx{$prog -v};
273    die qq{"$apache" does not appear to be version 2.x}
274        unless $vers =~ m!Apache/2.\d!;
275    return 1;
276}
277
278sub path_ext {
279    if ($ENV{PATHEXT}) {
280        push @path_ext, split ';', $ENV{PATHEXT};
281        for my $ext (@path_ext) {
282            $ext =~ s/^\.*(.+)$/$1/;
283        }
284    }
285    else {
286        #Win9X: doesn't have PATHEXT
287        push @path_ext, qw(com exe bat);
288    }
289}
290
291sub which {
292    my $program = shift;
293    return unless $program;
294    my @extras = ();
295    my @drives = drives();
296    (my $program_files = $ENV{ProgramFiles}) =~ s!^\w+:\\!!;
297    if (@drives > 0) {
298        for my $drive (@drives) {
299            for ('Apache2', "$program_files/Apache2",
300                 "$program_files/Apache Group/Apache2") {
301                my $bin = catdir $drive, $_, 'bin';
302                push @extras, $bin if (-d $bin);
303            }
304        }
305    }
306    my @a = map {catfile $_, $program}
307        (path(), @extras);
308    for my $base(@a) {
309        return $base if -x $base;
310        for my $ext (@path_ext) {
311            return "$base.$ext" if -x "$base.$ext";
312        }
313    }
314    return;
315}
316
317sub httpd_version {
318    my $prog = shift;
319    my $vers = qx{$prog -v};
320    die qq{Could not parse "$apache" version}
321        unless $vers =~ m!Apache/2.(\d).(\d)!;
322    return (2, $1, $2);
323}
324
325sub generate_defs {
326    my $preamble =<<'END';
327LIBRARY
328
329EXPORTS
330
331END
332    chdir "$apreq_home/env";
333    my $match = qr{^apreq_env};
334    my %fns = ();
335    open my $fh, "<mod_apreq.c"
336        or die "Cannot open env/mod_apreq.c: $!";
337    while (<$fh>) {
338        next unless /^APREQ_DECLARE\([^\)]+\)\s*(\w+)/;
339        my $fn = $1;
340        $fns{$fn}++ if $fn =~ /$match/;
341    }
342    close $fh;
343    open my $def, ">../win32/mod_apreq.def"
344        or die "Cannot open win32/mod_apreq.def: $!";
345    print $def $preamble;
346    print $def $_, "\n" for (sort keys %fns);
347    close $def;
348}
349
350sub generate_tests {
351  my ($top, $test_files) = @_;
352  my $t = catdir $top, 'library', 't';
353  foreach my $test(@$test_files) {
354    my $file = catfile $t, $test;
355    open my $fh, '>', "$file.t" || die "Cannot open $file.t: $!";
356    print $fh <<"EOT";
357#!$^X
358exec '$file';
359EOT
360    close $fh;
361  }
362}
363
364sub fetch_apxs {
365    eval {require Archive::Tar;};
366    if ($@) {
367        die "Need Archive::Tar installed in order to install apxs.";
368    }
369    eval {require LWP::Simple; import LWP::Simple qw(getstore is_success)};
370    if ($@) {
371        die "Need LWP::Simple installed in order to install apxs.";
372    }
373
374    print << 'END';
375
376I could not find an apxs utility on your system, which is
377needed to run tests in the env/ subdirectory. The apxs
378utiltity (and apr-config and apu-config utilties) have not
379yet been ported to Apache2 on Win32, but a development port
380is available, which I can install for you, if you like.
381
382END
383
384    my $ans = prompt('Install apxs?', 'yes');
385    return unless $ans =~ /^y/i;
386    my $file = 'apxs_win32.tar.gz';
387    my $remote = 'http://perl.apache.org/dist/win32-bin/' . $file;
388    print "Fetching $remote ... ";
389    unless (is_success(getstore($remote, $file))) {
390        warn "Download of $remote failed";
391        return;
392    }
393    print " done!\n";
394
395    my $arc = Archive::Tar->new($file, 1);
396    $arc->extract($arc->list_files());
397    my $dir = 'apxs';
398    unless (-d $dir) {
399        warn "Unpacking $file failed";
400        return;
401    }
402    print "chdir $dir\n";
403    chdir $dir or do {
404        warn "chdir to $dir failed: $!";
405        return;
406    };
407
408    my $prog = apache_prog_name($apache);
409    my @args = ($^X, 'Configure.pl',
410                "-with-apache2=$apache",
411                "--with-apache-prog=$prog");
412    print "@args\n\n";
413    system(@args) == 0 or do {
414         warn "system @args failed: $?";
415         return;
416     };
417    chdir '..';
418    rmtree($dir, 1, 1) or warn "rmtree of $dir failed: $!";
419    print "unlink $file\n";
420    unlink $file or warn "unlink of $file failed: $!";
421    return 1;
422}
423
424sub apache_prog_name {
425    my $apache = shift;
426    my $prog;
427    for my $trial(qw(Apache.exe httpd.exe)) {
428        my $path = catfile($apache, 'bin', $trial);
429        next unless -e $path;
430        $prog = $path;
431        last;
432    }
433    die "Could not determine the Apache2 binary name" unless $prog;
434    return $prog;
435}
436
437__DATA__
438
439LIBAPREQ=libapreq2
440APREQ2_TEST=apreq2_test
441CGITEST=test_cgi
442MOD=mod_apreq2
443
444!IF "$(CFG)" != "Release" && "$(CFG)" != "Debug"
445!MESSAGE Invalid configuration "$(CFG)" specified.
446!MESSAGE You can specify a configuration when running NMAKE
447!MESSAGE by defining the macro CFG on the command line. For example:
448!MESSAGE
449!MESSAGE NMAKE CFG="Release"
450!MESSAGE
451!MESSAGE Possible choices for configuration are:
452!MESSAGE
453!MESSAGE "Release" (based on "Win32 (x86) Console Application")
454!MESSAGE "Debug" (based on "Win32 (x86) Console Application")
455!MESSAGE
456!ERROR An invalid configuration is specified.
457!ENDIF
458
459!IF "$(APACHE)" == ""
460!MESSAGE No Apache directory was specified.
461!MESSAGE Please run Configure.bat to specify a valid Apache directory.
462!ERROR
463!ENDIF
464
465!IF "$(OS)" == "Windows_NT"
466NULL=
467!ELSE
468NULL=nul
469!ENDIF
470
471CFG_HOME=$(APREQ_HOME)\win32
472LIBDIR=$(CFG_HOME)\libs
473PERLGLUE=$(APREQ_HOME)\glue\perl
474APACHE_LIB=$(APACHE)\lib
475TDIR=$(APREQ_HOME)\library\t
476APREQ_MODULE=$(APREQ_HOME)\module
477
478ALL : MAKE_ALL
479
480MAKE_ALL : $(LIBAPREQ) $(MOD) PERL_GLUE
481
482$(LIBAPREQ):
483	$(MAKE) /nologo /f $(CFG_HOME)\$(LIBAPREQ).mak CFG="$(LIBAPREQ) - Win32 $(CFG)" APACHE="$(APACHE)" APREQ_HOME="$(APREQ_HOME)" APR_LIB="$(APR_LIB)" APU_LIB="$(APU_LIB)"
484
485$(MOD): $(LIBAPREQ)
486	$(MAKE) /nologo /f $(CFG_HOME)\$(MOD).mak CFG="$(MOD) - Win32 $(CFG)" APACHE="$(APACHE)" APREQ_HOME="$(APREQ_HOME)" APR_LIB="$(APR_LIB)" APU_LIB="$(APU_LIB)"
487
488PERL_GLUE: $(MOD)
489        cd $(PERLGLUE)
490	$(PERL) Makefile.PL
491        $(MAKE) /nologo
492        cd $(APREQ_HOME)
493
494PERL_TEST: $(MOD)
495        cd $(PERLGLUE)
496!IF !EXIST("$(PERLGLUE)\Makefile")
497	$(PERL) Makefile.PL
498!ENDIF
499        set PATH=$(APREQ_HOME)\win32\libs;$(APACHE)\bin;$(PATH)
500        $(MAKE) /nologo test
501        cd $(APREQ_HOME)
502
503INSTALL : INSTALL_LIBAPREQ2 PERL_INSTALL
504
505INSTALL_LIBAPREQ2: $(LIBAPREQ)
506        cd $(LIBDIR)
507!IF EXIST("$(LIBDIR)\$(MOD).so")
508	copy "$(MOD).so" "$(APACHE)\modules\$(MOD).so"
509	copy "$(MOD).lib" "$(APACHE_LIB)\$(MOD).lib"
510!ENDIF
511!IF EXIST("$(LIBDIR)\$(MOD).pdb")
512	copy "$(MOD).pdb" "$(APACHE)\modules\$(MOD).pdb"
513!ENDIF
514!IF EXIST("$(LIBDIR)\$(LIBAPREQ).lib")
515	copy "$(LIBAPREQ).lib" "$(APACHE_LIB)\$(LIBAPREQ).lib"
516!ENDIF
517!IF EXIST("$(LIBDIR)\$(LIBAPREQ).dll")
518        copy "$(LIBAPREQ).dll" "$(APACHE)\bin\$(LIBAPREQ).dll"
519!ENDIF
520!IF EXIST("$(LIBDIR)\$(LIBAPREQ).pdb")
521        copy "$(LIBAPREQ).pdb" "$(APACHE)\bin\$(LIBAPREQ).pdb"
522!ENDIF
523        cd $(APREQ_HOME)
524
525PERL_INSTALL: $(MOD)
526        cd $(PERLGLUE)
527!IF !EXIST("$(PERLGLUE)\Makefile")
528	$(PERL) Makefile.PL
529!ENDIF
530        $(MAKE) /nologo install
531        cd $(APREQ_HOME)
532
533HELP:
534        @echo nmake               - build the libapreq2 library and perl glue
535        @echo nmake test          - run the supplied tests
536	@echo nmake clean         - clean
537        @echo nmake install       - install the C libraries and perl modules
538        @echo nmake docs          - build documents (requires doxygen)
539