Every remaining (HV *) cast in *.c
[p5sagit/p5-mst-13.2.git] / lib / Module / Build / Base.pm
1 # -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*-
2 # vim:ts=8:sw=2:et:sta:sts=2
3 package Module::Build::Base;
4
5 use strict;
6 use vars qw($VERSION);
7 $VERSION = '0.30';
8 $VERSION = eval $VERSION;
9 BEGIN { require 5.00503 }
10
11 use Carp;
12 use Cwd ();
13 use File::Copy ();
14 use File::Find ();
15 use File::Path ();
16 use File::Basename ();
17 use File::Spec 0.82 ();
18 use File::Compare ();
19 use Module::Build::Dumper ();
20 use IO::File ();
21 use Text::ParseWords ();
22
23 use Module::Build::ModuleInfo;
24 use Module::Build::Notes;
25 use Module::Build::Config;
26
27
28 #################### Constructors ###########################
29 sub new {
30   my $self = shift()->_construct(@_);
31
32   $self->{invoked_action} = $self->{action} ||= 'Build_PL';
33   $self->cull_args(@ARGV);
34   
35   die "Too early to specify a build action '$self->{action}'.  Do 'Build $self->{action}' instead.\n"
36     if $self->{action} && $self->{action} ne 'Build_PL';
37
38   $self->check_manifest;
39   $self->check_prereq;
40   $self->check_autofeatures;
41
42   $self->dist_name;
43   $self->dist_version;
44
45   $self->_set_install_paths;
46   $self->_find_nested_builds;
47
48   return $self;
49 }
50
51 sub resume {
52   my $package = shift;
53   my $self = $package->_construct(@_);
54   $self->read_config;
55
56   # If someone called Module::Build->current() or
57   # Module::Build->new_from_context() and the correct class to use is
58   # actually a *subclass* of Module::Build, we may need to load that
59   # subclass here and re-delegate the resume() method to it.
60   unless ( UNIVERSAL::isa($package, $self->build_class) ) {
61     my $build_class = $self->build_class;
62     my $config_dir = $self->config_dir || '_build';
63     my $build_lib = File::Spec->catdir( $config_dir, 'lib' );
64     unshift( @INC, $build_lib );
65     unless ( $build_class->can('new') ) {
66       eval "require $build_class; 1" or die "Failed to re-load '$build_class': $@";
67     }
68     return $build_class->resume(@_);
69   }
70
71   unless ($self->_perl_is_same($self->{properties}{perl})) {
72     my $perl = $self->find_perl_interpreter;
73     $self->log_warn(" * WARNING: Configuration was initially created with '$self->{properties}{perl}',\n".
74                     "   but we are now using '$perl'.\n");
75   }
76   
77   $self->cull_args(@ARGV);
78
79   unless ($self->allow_mb_mismatch) {
80     my $mb_version = $Module::Build::VERSION;
81     die(" * ERROR: Configuration was initially created with Module::Build version '$self->{properties}{mb_version}',\n".
82         "   but we are now using version '$mb_version'.  Please re-run the Build.PL or Makefile.PL script,\n".
83         "   or use --allow_mb_mismatch 1 to skip this version check.\n")
84     if $mb_version ne $self->{properties}{mb_version};
85   }
86   
87   $self->{invoked_action} = $self->{action} ||= 'build';
88
89   $self->_set_install_paths;
90   
91   return $self;
92 }
93
94 sub new_from_context {
95   my ($package, %args) = @_;
96   
97   # XXX Read the META.yml and see whether we need to run the Build.PL?
98   
99   # Run the Build.PL.  We use do() rather than run_perl_script() so
100   # that it runs in this process rather than a subprocess, because we
101   # need to make sure that the environment is the same during Build.PL
102   # as it is during resume() (and thereafter).
103   {
104     local @ARGV = $package->unparse_args(\%args);
105     do './Build.PL';
106     die $@ if $@;
107   }
108   return $package->resume;
109 }
110
111 sub current {
112   # hmm, wonder what the right thing to do here is
113   local @ARGV;
114   return shift()->resume;
115 }
116
117 sub _construct {
118   my ($package, %input) = @_;
119
120   my $args   = delete $input{args}   || {};
121   my $config = delete $input{config} || {};
122
123   my $self = bless {
124                     args => {%$args},
125                     config => Module::Build::Config->new(values => $config),
126                     properties => {
127                                    base_dir        => $package->cwd,
128                                    mb_version      => $Module::Build::VERSION,
129                                    %input,
130                                   },
131                     phash => {},
132                    }, $package;
133
134   $self->_set_defaults;
135   my ($p, $ph) = ($self->{properties}, $self->{phash});
136
137   foreach (qw(notes config_data features runtime_params cleanup auto_features)) {
138     my $file = File::Spec->catfile($self->config_dir, $_);
139     $ph->{$_} = Module::Build::Notes->new(file => $file);
140     $ph->{$_}->restore if -e $file;
141     if (exists $p->{$_}) {
142       my $vals = delete $p->{$_};
143       while (my ($k, $v) = each %$vals) {
144         $self->$_($k, $v);
145       }
146     }
147   }
148
149   # The following warning could be unnecessary if the user is running
150   # an embedded perl, but there aren't too many of those around, and
151   # embedded perls aren't usually used to install modules, and the
152   # installation process sometimes needs to run external scripts
153   # (e.g. to run tests).
154   $p->{perl} = $self->find_perl_interpreter
155     or $self->log_warn("Warning: Can't locate your perl binary");
156
157   my $blibdir = sub { File::Spec->catdir($p->{blib}, @_) };
158   $p->{bindoc_dirs} ||= [ $blibdir->("script") ];
159   $p->{libdoc_dirs} ||= [ $blibdir->("lib"), $blibdir->("arch") ];
160
161   $p->{dist_author} = [ $p->{dist_author} ] if defined $p->{dist_author} and not ref $p->{dist_author};
162
163   # Synonyms
164   $p->{requires} = delete $p->{prereq} if defined $p->{prereq};
165   $p->{script_files} = delete $p->{scripts} if defined $p->{scripts};
166
167   # Convert to arrays
168   for ('extra_compiler_flags', 'extra_linker_flags') {
169     $p->{$_} = [ $self->split_like_shell($p->{$_}) ] if exists $p->{$_};
170   }
171
172   $self->add_to_cleanup( @{delete $p->{add_to_cleanup}} )
173     if $p->{add_to_cleanup};
174
175   return $self;
176 }
177
178 ################## End constructors #########################
179
180 sub log_info { print @_ unless shift()->quiet }
181 sub log_verbose { shift()->log_info(@_) if $_[0]->verbose }
182 sub log_warn {
183   # Try to make our call stack invisible
184   shift;
185   if (@_ and $_[-1] !~ /\n$/) {
186     my (undef, $file, $line) = caller();
187     warn @_, " at $file line $line.\n";
188   } else {
189     warn @_;
190   }
191 }
192
193
194 sub _set_install_paths {
195   my $self = shift;
196   my $c = $self->{config};
197   my $p = $self->{properties};
198
199   my @libstyle = $c->get('installstyle') ?
200       File::Spec->splitdir($c->get('installstyle')) : qw(lib perl5);
201   my $arch     = $c->get('archname');
202   my $version  = $c->get('version');
203
204   my $bindoc  = $c->get('installman1dir') || undef;
205   my $libdoc  = $c->get('installman3dir') || undef;
206
207   my $binhtml = $c->get('installhtml1dir') || $c->get('installhtmldir') || undef;
208   my $libhtml = $c->get('installhtml3dir') || $c->get('installhtmldir') || undef;
209
210   $p->{install_sets} =
211     {
212      core   => {
213                 lib     => $c->get('installprivlib'),
214                 arch    => $c->get('installarchlib'),
215                 bin     => $c->get('installbin'),
216                 script  => $c->get('installscript'),
217                 bindoc  => $bindoc,
218                 libdoc  => $libdoc,
219                 binhtml => $binhtml,
220                 libhtml => $libhtml,
221                },
222      site   => {
223                 lib     => $c->get('installsitelib'),
224                 arch    => $c->get('installsitearch'),
225                 bin     => $c->get('installsitebin') || $c->get('installbin'),
226                 script  => $c->get('installsitescript') ||
227                            $c->get('installsitebin') || $c->get('installscript'),
228                 bindoc  => $c->get('installsiteman1dir') || $bindoc,
229                 libdoc  => $c->get('installsiteman3dir') || $libdoc,
230                 binhtml => $c->get('installsitehtml1dir') || $binhtml,
231                 libhtml => $c->get('installsitehtml3dir') || $libhtml,
232                },
233      vendor => {
234                 lib     => $c->get('installvendorlib'),
235                 arch    => $c->get('installvendorarch'),
236                 bin     => $c->get('installvendorbin') || $c->get('installbin'),
237                 script  => $c->get('installvendorscript') ||
238                            $c->get('installvendorbin') || $c->get('installscript'),
239                 bindoc  => $c->get('installvendorman1dir') || $bindoc,
240                 libdoc  => $c->get('installvendorman3dir') || $libdoc,
241                 binhtml => $c->get('installvendorhtml1dir') || $binhtml,
242                 libhtml => $c->get('installvendorhtml3dir') || $libhtml,
243                },
244     };
245
246   $p->{original_prefix} =
247     {
248      core   => $c->get('installprefixexp') || $c->get('installprefix') ||
249                $c->get('prefixexp')        || $c->get('prefix') || '',
250      site   => $c->get('siteprefixexp'),
251      vendor => $c->get('usevendorprefix') ? $c->get('vendorprefixexp') : '',
252     };
253   $p->{original_prefix}{site} ||= $p->{original_prefix}{core};
254
255   # Note: you might be tempted to use $Config{installstyle} here
256   # instead of hard-coding lib/perl5, but that's been considered and
257   # (at least for now) rejected.  `perldoc Config` has some wisdom
258   # about it.
259   $p->{install_base_relpaths} =
260     {
261      lib     => ['lib', 'perl5'],
262      arch    => ['lib', 'perl5', $arch],
263      bin     => ['bin'],
264      script  => ['bin'],
265      bindoc  => ['man', 'man1'],
266      libdoc  => ['man', 'man3'],
267      binhtml => ['html'],
268      libhtml => ['html'],
269     };
270
271   $p->{prefix_relpaths} =
272     {
273      core => {
274               lib        => [@libstyle],
275               arch       => [@libstyle, $version, $arch],
276               bin        => ['bin'],
277               script     => ['bin'],
278               bindoc     => ['man', 'man1'],
279               libdoc     => ['man', 'man3'],
280               binhtml    => ['html'],
281               libhtml    => ['html'],
282              },
283      vendor => {
284                 lib        => [@libstyle],
285                 arch       => [@libstyle, $version, $arch],
286                 bin        => ['bin'],
287                 script     => ['bin'],
288                 bindoc     => ['man', 'man1'],
289                 libdoc     => ['man', 'man3'],
290                 binhtml    => ['html'],
291                 libhtml    => ['html'],
292                },
293      site => {
294               lib        => [@libstyle, 'site_perl'],
295               arch       => [@libstyle, 'site_perl', $version, $arch],
296               bin        => ['bin'],
297               script     => ['bin'],
298               bindoc     => ['man', 'man1'],
299               libdoc     => ['man', 'man3'],
300               binhtml    => ['html'],
301               libhtml    => ['html'],
302              },
303     };
304
305 }
306
307 sub _find_nested_builds {
308   my $self = shift;
309   my $r = $self->recurse_into or return;
310
311   my ($file, @r);
312   if (!ref($r) && $r eq 'auto') {
313     local *DH;
314     opendir DH, $self->base_dir
315       or die "Can't scan directory " . $self->base_dir . " for nested builds: $!";
316     while (defined($file = readdir DH)) {
317       my $subdir = File::Spec->catdir( $self->base_dir, $file );
318       next unless -d $subdir;
319       push @r, $subdir if -e File::Spec->catfile( $subdir, 'Build.PL' );
320     }
321   }
322
323   $self->recurse_into(\@r);
324 }
325
326 sub cwd {
327   return Cwd::cwd();
328 }
329
330 sub _quote_args {
331   # Returns a string that can become [part of] a command line with
332   # proper quoting so that the subprocess sees this same list of args.
333   my ($self, @args) = @_;
334
335   my @quoted;
336
337   for (@args) {
338     if ( /^[^\s*?!\$<>;\\|'"\[\]\{\}]+$/ ) {
339       # Looks pretty safe
340       push @quoted, $_;
341     } else {
342       # XXX this will obviously have to improve - is there already a
343       # core module lying around that does proper quoting?
344       s/('+)/'"$1"'/g;
345       push @quoted, qq('$_');
346     }
347   }
348
349   return join " ", @quoted;
350 }
351
352 sub _backticks {
353   my ($self, @cmd) = @_;
354   if ($self->have_forkpipe) {
355     local *FH;
356     my $pid = open *FH, "-|";
357     if ($pid) {
358       return wantarray ? <FH> : join '', <FH>;
359     } else {
360       die "Can't execute @cmd: $!\n" unless defined $pid;
361       exec { $cmd[0] } @cmd;
362     }
363   } else {
364     my $cmd = $self->_quote_args(@cmd);
365     return `$cmd`;
366   }
367 }
368
369 # Tells us whether the construct open($fh, '-|', @command) is
370 # supported.  It would probably be better to dynamically sense this.
371 sub have_forkpipe { 1 }
372
373 # Determine whether a given binary is the same as the perl
374 # (configuration) that started this process.
375 sub _perl_is_same {
376   my ($self, $perl) = @_;
377
378   my @cmd = ($perl);
379
380   # When run from the perl core, @INC will include the directories
381   # where perl is yet to be installed. We need to reference the
382   # absolute path within the source distribution where it can find
383   # it's Config.pm This also prevents us from picking up a Config.pm
384   # from a different configuration that happens to be already
385   # installed in @INC.
386   if ($ENV{PERL_CORE}) {
387     push @cmd, '-I' . File::Spec->catdir(File::Basename::dirname($perl), 'lib');
388   }
389
390   push @cmd, qw(-MConfig=myconfig -e print -e myconfig);
391   return $self->_backticks(@cmd) eq Config->myconfig;
392 }
393
394 # cache _discover_perl_interpreter() results
395 {
396   my $known_perl;
397   sub find_perl_interpreter {
398     my $self = shift;
399
400     return $known_perl if defined($known_perl);
401     return $known_perl = $self->_discover_perl_interpreter;
402   }
403 }
404
405 # Returns the absolute path of the perl interperter used to invoke
406 # this process. The path is derived from $^X or $Config{perlpath}. On
407 # some platforms $^X contains the complete absolute path of the
408 # interpreter, on other it may contain a relative path, or simply
409 # 'perl'. This can also vary depending on whether a path was supplied
410 # when perl was invoked. Additionally, the value in $^X may omit the
411 # executable extension on platforms that use one. It's a fatal error
412 # if the interpreter can't be found because it can result in undefined
413 # behavior by routines that depend on it (generating errors or
414 # invoking the wrong perl.)
415 sub _discover_perl_interpreter {
416   my $proto = shift;
417   my $c     = ref($proto) ? $proto->{config} : 'Module::Build::Config';
418
419   my $perl  = $^X;
420   my $perl_basename = File::Basename::basename($perl);
421
422   my @potential_perls;
423
424   # Try 1, Check $^X for absolute path
425   push( @potential_perls, $perl )
426       if File::Spec->file_name_is_absolute($perl);
427
428   # Try 2, Check $^X for a valid relative path
429   my $abs_perl = File::Spec->rel2abs($perl);
430   push( @potential_perls, $abs_perl );
431
432   # Try 3, Last ditch effort: These two option use hackery to try to locate
433   # a suitable perl. The hack varies depending on whether we are running
434   # from an installed perl or an uninstalled perl in the perl source dist.
435   if ($ENV{PERL_CORE}) {
436
437     # Try 3.A, If we are in a perl source tree, running an uninstalled
438     # perl, we can keep moving up the directory tree until we find our
439     # binary. We wouldn't do this under any other circumstances.
440
441     # CBuilder is also in the core, so it should be available here
442     require ExtUtils::CBuilder;
443     my $perl_src = Cwd::realpath( ExtUtils::CBuilder->perl_src );
444     if ( defined($perl_src) && length($perl_src) ) {
445       my $uninstperl =
446         File::Spec->rel2abs(File::Spec->catfile( $perl_src, $perl_basename ));
447       push( @potential_perls, $uninstperl );
448     }
449
450   } else {
451
452     # Try 3.B, First look in $Config{perlpath}, then search the user's
453     # PATH. We do not want to do either if we are running from an
454     # uninstalled perl in a perl source tree.
455
456     push( @potential_perls, $c->get('perlpath') );
457
458     push( @potential_perls,
459           map File::Spec->catfile($_, $perl_basename), File::Spec->path() );
460   }
461
462   # Now that we've enumerated the potential perls, it's time to test
463   # them to see if any of them match our configuration, returning the
464   # absolute path of the first successful match.
465   my $exe = $c->get('exe_ext');
466   foreach my $thisperl ( @potential_perls ) {
467
468     if (defined $exe) {
469       $thisperl .= $exe unless $thisperl =~ m/$exe$/i;
470     }
471
472     if ( -f $thisperl && $proto->_perl_is_same($thisperl) ) {
473       return $thisperl;
474     }
475   }
476
477   # We've tried all alternatives, and didn't find a perl that matches
478   # our configuration. Throw an exception, and list alternatives we tried.
479   my @paths = map File::Basename::dirname($_), @potential_perls;
480   die "Can't locate the perl binary used to run this script " .
481       "in (@paths)\n";
482 }
483
484 sub _is_interactive {
485   return -t STDIN && (-t STDOUT || !(-f STDOUT || -c STDOUT)) ;   # Pipe?
486 }
487
488 # NOTE this is a blocking operation if(-t STDIN)
489 sub _is_unattended {
490   my $self = shift;
491   return $ENV{PERL_MM_USE_DEFAULT} ||
492     ( !$self->_is_interactive && eof STDIN );
493 }
494
495 sub _readline {
496   my $self = shift;
497   return undef if $self->_is_unattended;
498
499   my $answer = <STDIN>;
500   chomp $answer if defined $answer;
501   return $answer;
502 }
503
504 sub prompt {
505   my $self = shift;
506   my $mess = shift
507     or die "prompt() called without a prompt message";
508
509   # use a list to distinguish a default of undef() from no default
510   my @def;
511   @def = (shift) if @_;
512   # use dispdef for output
513   my @dispdef = scalar(@def) ?
514     ('[', (defined($def[0]) ? $def[0] . ' ' : ''), ']') :
515     (' ', '');
516
517   local $|=1;
518   print "$mess ", @dispdef;
519
520   if ( $self->_is_unattended && !@def ) {
521     die <<EOF;
522 ERROR: This build seems to be unattended, but there is no default value
523 for this question.  Aborting.
524 EOF
525   }
526
527   my $ans = $self->_readline();
528
529   if ( !defined($ans)        # Ctrl-D or unattended
530        or !length($ans) ) {  # User hit return
531     print "$dispdef[1]\n";
532     $ans = scalar(@def) ? $def[0] : '';
533   }
534
535   return $ans;
536 }
537
538 sub y_n {
539   my $self = shift;
540   my ($mess, $def)  = @_;
541
542   die "y_n() called without a prompt message" unless $mess;
543   die "Invalid default value: y_n() default must be 'y' or 'n'"
544     if $def && $def !~ /^[yn]/i;
545
546   my $answer;
547   while (1) { # XXX Infinite or a large number followed by an exception ?
548     $answer = $self->prompt(@_);
549     return 1 if $answer =~ /^y/i;
550     return 0 if $answer =~ /^n/i;
551     local $|=1;
552     print "Please answer 'y' or 'n'.\n";
553   }
554 }
555
556 sub current_action { shift->{action} }
557 sub invoked_action { shift->{invoked_action} }
558
559 sub notes        { shift()->{phash}{notes}->access(@_) }
560 sub config_data  { shift()->{phash}{config_data}->access(@_) }
561 sub runtime_params { shift->{phash}{runtime_params}->read( @_ ? shift : () ) }  # Read-only
562 sub auto_features  { shift()->{phash}{auto_features}->access(@_) }
563
564 sub features     {
565   my $self = shift;
566   my $ph = $self->{phash};
567
568   if (@_) {
569     my $key = shift;
570     if ($ph->{features}->exists($key)) {
571       return $ph->{features}->access($key, @_);
572     }
573
574     if (my $info = $ph->{auto_features}->access($key)) {
575       my $failures = $self->prereq_failures($info);
576       my $disabled = grep( /^(?:\w+_)?(?:requires|conflicts)$/,
577                            keys %$failures ) ? 1 : 0;
578       return !$disabled;
579     }
580
581     return $ph->{features}->access($key, @_);
582   }
583
584   # No args - get the auto_features & overlay the regular features
585   my %features;
586   my %auto_features = $ph->{auto_features}->access();
587   while (my ($name, $info) = each %auto_features) {
588     my $failures = $self->prereq_failures($info);
589     my $disabled = grep( /^(?:\w+_)?(?:requires|conflicts)$/,
590                          keys %$failures ) ? 1 : 0;
591     $features{$name} = $disabled ? 0 : 1;
592   }
593   %features = (%features, $ph->{features}->access());
594
595   return wantarray ? %features : \%features;
596 }
597 BEGIN { *feature = \&features } # Alias
598
599 sub _mb_feature {
600   my $self = shift;
601   
602   if (($self->module_name || '') eq 'Module::Build') {
603     # We're building Module::Build itself, so ...::ConfigData isn't
604     # valid, but $self->features() should be.
605     return $self->feature(@_);
606   } else {
607     require Module::Build::ConfigData;
608     return Module::Build::ConfigData->feature(@_);
609   }
610 }
611
612
613 sub add_build_element {
614     my ($self, $elem) = @_;
615     my $elems = $self->build_elements;
616     push @$elems, $elem unless grep { $_ eq $elem } @$elems;
617 }
618
619 sub ACTION_config_data {
620   my $self = shift;
621   return unless $self->has_config_data;
622   
623   my $module_name = $self->module_name
624     or die "The config_data feature requires that 'module_name' be set";
625   my $notes_name = $module_name . '::ConfigData'; # TODO: Customize name ???
626   my $notes_pm = File::Spec->catfile($self->blib, 'lib', split /::/, "$notes_name.pm");
627
628   return if $self->up_to_date(['Build.PL',
629                                $self->config_file('config_data'),
630                                $self->config_file('features')
631                               ], $notes_pm);
632
633   $self->log_info("Writing config notes to $notes_pm\n");
634   File::Path::mkpath(File::Basename::dirname($notes_pm));
635
636   Module::Build::Notes->write_config_data
637       (
638        file => $notes_pm,
639        module => $module_name,
640        config_module => $notes_name,
641        config_data => scalar $self->config_data,
642        feature => scalar $self->{phash}{features}->access(),
643        auto_features => scalar $self->auto_features,
644       );
645 }
646
647 {
648     my %valid_properties = ( __PACKAGE__,  {} );
649     my %additive_properties;
650
651     sub _mb_classes {
652       my $class = ref($_[0]) || $_[0];
653       return ($class, $class->mb_parents);
654     }
655
656     sub valid_property {
657       my ($class, $prop) = @_;
658       return grep exists( $valid_properties{$_}{$prop} ), $class->_mb_classes;
659     }
660
661     sub valid_properties {
662       return keys %{ shift->valid_properties_defaults() };
663     }
664
665     sub valid_properties_defaults {
666       my %out;
667       for (reverse shift->_mb_classes) {
668         @out{ keys %{ $valid_properties{$_} } } = values %{ $valid_properties{$_} };
669       }
670       return \%out;
671     }
672
673     sub array_properties {
674       for (shift->_mb_classes) {
675         return @{$additive_properties{$_}->{ARRAY}}
676           if exists $additive_properties{$_}->{ARRAY};
677       }
678     }
679
680     sub hash_properties {
681       for (shift->_mb_classes) {
682         return @{$additive_properties{$_}->{'HASH'}}
683           if exists $additive_properties{$_}->{'HASH'};
684       }
685     }
686
687     sub add_property {
688       my ($class, $property, $default) = @_;
689       die "Property '$property' already exists" if $class->valid_property($property);
690
691       $valid_properties{$class}{$property} = $default;
692
693       my $type = ref $default;
694       if ($type) {
695         push @{$additive_properties{$class}->{$type}}, $property;
696       }
697
698       unless ($class->can($property)) {
699         no strict 'refs';
700         if ( $type eq 'HASH' ) {
701           *{"$class\::$property"} = sub {
702             # XXX this needs 'use strict' again
703             my $self = shift;
704             my $x = $self->{properties};
705             return $x->{$property} unless @_;
706
707             if ( defined($_[0]) && !ref($_[0]) ) {
708               if ( @_ == 1 ) {
709                 return exists( $x->{$property}{$_[0]} ) ?
710                          $x->{$property}{$_[0]} : undef;
711               } elsif ( @_ % 2 == 0 ) {
712                 my %args = @_;
713                 while ( my($k, $v) = each %args ) {
714                   $x->{$property}{$k} = $v;
715                 }
716               } else {
717                 die "Unexpected arguments for property '$property'\n";
718               }
719             } else {
720               $x->{$property} = $_[0];
721             }
722           };
723
724         } else {
725           *{"$class\::$property"} = sub {
726             # XXX this needs 'use strict' again
727             my $self = shift;
728             $self->{properties}{$property} = shift if @_;
729             return $self->{properties}{$property};
730           }
731         }
732
733       }
734       return $class;
735     }
736
737     sub _set_defaults {
738       my $self = shift;
739
740       # Set the build class.
741       $self->{properties}{build_class} ||= ref $self;
742
743       # If there was no orig_dir, set to the same as base_dir
744       $self->{properties}{orig_dir} ||= $self->{properties}{base_dir};
745
746       my $defaults = $self->valid_properties_defaults;
747       
748       foreach my $prop (keys %$defaults) {
749         $self->{properties}{$prop} = $defaults->{$prop}
750           unless exists $self->{properties}{$prop};
751       }
752       
753       # Copy defaults for arrays any arrays.
754       for my $prop ($self->array_properties) {
755         $self->{properties}{$prop} = [@{$defaults->{$prop}}]
756           unless exists $self->{properties}{$prop};
757       }
758       # Copy defaults for arrays any hashes.
759       for my $prop ($self->hash_properties) {
760         $self->{properties}{$prop} = {%{$defaults->{$prop}}}
761           unless exists $self->{properties}{$prop};
762       }
763     }
764
765 }
766
767 # Add the default properties.
768 __PACKAGE__->add_property(blib => 'blib');
769 __PACKAGE__->add_property(build_class => 'Module::Build');
770 __PACKAGE__->add_property(build_elements => [qw(PL support pm xs pod script)]);
771 __PACKAGE__->add_property(build_script => 'Build');
772 __PACKAGE__->add_property(build_bat => 0);
773 __PACKAGE__->add_property(config_dir => '_build');
774 __PACKAGE__->add_property(include_dirs => []);
775 __PACKAGE__->add_property(installdirs => 'site');
776 __PACKAGE__->add_property(metafile => 'META.yml');
777 __PACKAGE__->add_property(recurse_into => []);
778 __PACKAGE__->add_property(use_rcfile => 1);
779 __PACKAGE__->add_property(create_packlist => 1);
780 __PACKAGE__->add_property(allow_mb_mismatch => 0);
781 __PACKAGE__->add_property(config => undef);
782 __PACKAGE__->add_property(test_file_exts => ['.t']);
783 __PACKAGE__->add_property(use_tap_harness => 0);
784 __PACKAGE__->add_property(tap_harness_args => {});
785
786 {
787   my $Is_ActivePerl = eval {require ActivePerl::DocTools};
788   __PACKAGE__->add_property(html_css => $Is_ActivePerl ? 'Active.css' : '');
789 }
790
791 {
792   my @prereq_action_types = qw(requires build_requires conflicts recommends);
793   foreach my $type (@prereq_action_types) {
794     __PACKAGE__->add_property($type => {});
795   }
796   __PACKAGE__->add_property(prereq_action_types => \@prereq_action_types);
797 }
798
799 __PACKAGE__->add_property($_ => {}) for qw(
800   get_options
801   install_base_relpaths
802   install_path
803   install_sets
804   meta_add
805   meta_merge
806   original_prefix
807   prefix_relpaths
808   configure_requires
809 );
810
811 __PACKAGE__->add_property($_) for qw(
812   PL_files
813   autosplit
814   base_dir
815   bindoc_dirs
816   c_source
817   create_makefile_pl
818   create_readme
819   debugger
820   destdir
821   dist_abstract
822   dist_author
823   dist_name
824   dist_version
825   dist_version_from
826   extra_compiler_flags
827   extra_linker_flags
828   has_config_data
829   install_base
830   libdoc_dirs
831   license
832   magic_number
833   mb_version
834   module_name
835   orig_dir
836   perl
837   pm_files
838   pod_files
839   pollute
840   prefix
841   program_name
842   quiet
843   recursive_test_files
844   script_files
845   scripts
846   sign
847   test_files
848   verbose
849   xs_files
850 );
851
852 sub config {
853   my $self = shift;
854   my $c = ref($self) ? $self->{config} : 'Module::Build::Config';
855   return $c->all_config unless @_;
856
857   my $key = shift;
858   return $c->get($key) unless @_;
859
860   my $val = shift;
861   return $c->set($key => $val);
862 }
863
864 sub mb_parents {
865     # Code borrowed from Class::ISA.
866     my @in_stack = (shift);
867     my %seen = ($in_stack[0] => 1);
868
869     my ($current, @out);
870     while (@in_stack) {
871         next unless defined($current = shift @in_stack)
872           && $current->isa('Module::Build::Base');
873         push @out, $current;
874         next if $current eq 'Module::Build::Base';
875         no strict 'refs';
876         unshift @in_stack,
877           map {
878               my $c = $_; # copy, to avoid being destructive
879               substr($c,0,2) = "main::" if substr($c,0,2) eq '::';
880               # Canonize the :: -> main::, ::foo -> main::foo thing.
881               # Should I ever canonize the Foo'Bar = Foo::Bar thing?
882               $seen{$c}++ ? () : $c;
883           } @{"$current\::ISA"};
884
885         # I.e., if this class has any parents (at least, ones I've never seen
886         # before), push them, in order, onto the stack of classes I need to
887         # explore.
888     }
889     shift @out;
890     return @out;
891 }
892
893 sub extra_linker_flags   { shift->_list_accessor('extra_linker_flags',   @_) }
894 sub extra_compiler_flags { shift->_list_accessor('extra_compiler_flags', @_) }
895
896 sub _list_accessor {
897   (my $self, local $_) = (shift, shift);
898   my $p = $self->{properties};
899   $p->{$_} = [@_] if @_;
900   $p->{$_} = [] unless exists $p->{$_};
901   return ref($p->{$_}) ? $p->{$_} : [$p->{$_}];
902 }
903
904 # XXX Problem - if Module::Build is loaded from a different directory,
905 # it'll look for (and perhaps destroy/create) a _build directory.
906 sub subclass {
907   my ($pack, %opts) = @_;
908
909   my $build_dir = '_build'; # XXX The _build directory is ostensibly settable by the user.  Shouldn't hard-code here.
910   $pack->delete_filetree($build_dir) if -e $build_dir;
911
912   die "Must provide 'code' or 'class' option to subclass()\n"
913     unless $opts{code} or $opts{class};
914
915   $opts{code}  ||= '';
916   $opts{class} ||= 'MyModuleBuilder';
917   
918   my $filename = File::Spec->catfile($build_dir, 'lib', split '::', $opts{class}) . '.pm';
919   my $filedir  = File::Basename::dirname($filename);
920   $pack->log_info("Creating custom builder $filename in $filedir\n");
921   
922   File::Path::mkpath($filedir);
923   die "Can't create directory $filedir: $!" unless -d $filedir;
924   
925   my $fh = IO::File->new("> $filename") or die "Can't create $filename: $!";
926   print $fh <<EOF;
927 package $opts{class};
928 use $pack;
929 \@ISA = qw($pack);
930 $opts{code}
931 1;
932 EOF
933   close $fh;
934   
935   unshift @INC, File::Spec->catdir(File::Spec->rel2abs($build_dir), 'lib');
936   eval "use $opts{class}";
937   die $@ if $@;
938
939   return $opts{class};
940 }
941
942 sub dist_name {
943   my $self = shift;
944   my $p = $self->{properties};
945   return $p->{dist_name} if defined $p->{dist_name};
946   
947   die "Can't determine distribution name, must supply either 'dist_name' or 'module_name' parameter"
948     unless $self->module_name;
949   
950   ($p->{dist_name} = $self->module_name) =~ s/::/-/g;
951   
952   return $p->{dist_name};
953 }
954
955 sub dist_version_from {
956   my ($self) = @_;
957   my $p = $self->{properties};
958   if ($self->module_name) {
959     $p->{dist_version_from} ||=
960         join( '/', 'lib', split(/::/, $self->module_name) ) . '.pm';
961   }
962   return $p->{dist_version_from} || undef;
963 }
964
965 sub dist_version {
966   my ($self) = @_;
967   my $p = $self->{properties};
968
969   return $p->{dist_version} if defined $p->{dist_version};
970
971   if ( my $dist_version_from = $self->dist_version_from ) {
972     my $version_from = File::Spec->catfile( split( qr{/}, $dist_version_from ) );
973     my $pm_info = Module::Build::ModuleInfo->new_from_file( $version_from )
974       or die "Can't find file $version_from to determine version";
975     $p->{dist_version} = $pm_info->version();
976   }
977
978   die ("Can't determine distribution version, must supply either 'dist_version',\n".
979        "'dist_version_from', or 'module_name' parameter")
980     unless defined $p->{dist_version};
981
982   return $p->{dist_version};
983 }
984
985 sub dist_author   { shift->_pod_parse('author')   }
986 sub dist_abstract { shift->_pod_parse('abstract') }
987
988 sub _pod_parse {
989   my ($self, $part) = @_;
990   my $p = $self->{properties};
991   my $member = "dist_$part";
992   return $p->{$member} if defined $p->{$member};
993   
994   my $docfile = $self->_main_docfile
995     or return;
996   my $fh = IO::File->new($docfile)
997     or return;
998   
999   require Module::Build::PodParser;
1000   my $parser = Module::Build::PodParser->new(fh => $fh);
1001   my $method = "get_$part";
1002   return $p->{$member} = $parser->$method();
1003 }
1004
1005 sub version_from_file { # Method provided for backwards compatability
1006   return Module::Build::ModuleInfo->new_from_file($_[1])->version();
1007 }
1008
1009 sub find_module_by_name { # Method provided for backwards compatability
1010   return Module::Build::ModuleInfo->find_module_by_name(@_[1,2]);
1011 }
1012
1013 sub add_to_cleanup {
1014   my $self = shift;
1015   my %files = map {$self->localize_file_path($_), 1} @_;
1016   $self->{phash}{cleanup}->write(\%files);
1017 }
1018
1019 sub cleanup {
1020   my $self = shift;
1021   my $all = $self->{phash}{cleanup}->read;
1022   return keys %$all;
1023 }
1024
1025 sub config_file {
1026   my $self = shift;
1027   return unless -d $self->config_dir;
1028   return File::Spec->catfile($self->config_dir, @_);
1029 }
1030
1031 sub read_config {
1032   my ($self) = @_;
1033   
1034   my $file = $self->config_file('build_params')
1035     or die "Can't find 'build_params' in " . $self->config_dir;
1036   my $fh = IO::File->new($file) or die "Can't read '$file': $!";
1037   my $ref = eval do {local $/; <$fh>};
1038   die if $@;
1039   my $c;
1040   ($self->{args}, $c, $self->{properties}) = @$ref;
1041   $self->{config} = Module::Build::Config->new(values => $c);
1042   close $fh;
1043 }
1044
1045 sub has_config_data {
1046   my $self = shift;
1047   return scalar grep $self->{phash}{$_}->has_data(), qw(config_data features auto_features);
1048 }
1049
1050 sub _write_data {
1051   my ($self, $filename, $data) = @_;
1052   
1053   my $file = $self->config_file($filename);
1054   my $fh = IO::File->new("> $file") or die "Can't create '$file': $!";
1055   unless (ref($data)) {  # e.g. magicnum
1056     print $fh $data;
1057     return;
1058   }
1059
1060   print {$fh} Module::Build::Dumper->_data_dump($data);
1061 }
1062
1063 sub write_config {
1064   my ($self) = @_;
1065   
1066   File::Path::mkpath($self->{properties}{config_dir});
1067   -d $self->{properties}{config_dir} or die "Can't mkdir $self->{properties}{config_dir}: $!";
1068   
1069   my @items = @{ $self->prereq_action_types };
1070   $self->_write_data('prereqs', { map { $_, $self->$_() } @items });
1071   $self->_write_data('build_params', [$self->{args}, $self->{config}->values_set, $self->{properties}]);
1072
1073   # Set a new magic number and write it to a file
1074   $self->_write_data('magicnum', $self->magic_number(int rand 1_000_000));
1075
1076   $self->{phash}{$_}->write() foreach qw(notes cleanup features auto_features config_data runtime_params);
1077 }
1078
1079 sub check_autofeatures {
1080   my ($self) = @_;
1081   my $features = $self->auto_features;
1082   
1083   return unless %$features;
1084
1085   $self->log_info("Checking features:\n");
1086
1087   my $max_name_len = 0;
1088   $max_name_len = ( length($_) > $max_name_len ) ?
1089                     length($_) : $max_name_len
1090     for keys %$features;
1091
1092   while (my ($name, $info) = each %$features) {
1093     $self->log_info("  $name" . '.' x ($max_name_len - length($name) + 4));
1094
1095     if ( my $failures = $self->prereq_failures($info) ) {
1096       my $disabled = grep( /^(?:\w+_)?(?:requires|conflicts)$/,
1097                            keys %$failures ) ? 1 : 0;
1098       $self->log_info( $disabled ? "disabled\n" : "enabled\n" );
1099
1100       my $log_text;
1101       while (my ($type, $prereqs) = each %$failures) {
1102         while (my ($module, $status) = each %$prereqs) {
1103           my $required =
1104             ($type =~ /^(?:\w+_)?(?:requires|conflicts)$/) ? 1 : 0;
1105           my $prefix = ($required) ? '-' : '*';
1106           $log_text .= "    $prefix $status->{message}\n";
1107         }
1108       }
1109       $self->log_warn("$log_text") unless $self->quiet;
1110     } else {
1111       $self->log_info("enabled\n");
1112     }
1113   }
1114
1115   $self->log_warn("\n");
1116 }
1117
1118 sub prereq_failures {
1119   my ($self, $info) = @_;
1120
1121   my @types = @{ $self->prereq_action_types };
1122   $info ||= {map {$_, $self->$_()} @types};
1123
1124   my $out;
1125
1126   foreach my $type (@types) {
1127     my $prereqs = $info->{$type};
1128     while ( my ($modname, $spec) = each %$prereqs ) {
1129       my $status = $self->check_installed_status($modname, $spec);
1130
1131       if ($type =~ /^(?:\w+_)?conflicts$/) {
1132         next if !$status->{ok};
1133         $status->{conflicts} = delete $status->{need};
1134         $status->{message} = "$modname ($status->{have}) conflicts with this distribution";
1135
1136       } elsif ($type =~ /^(?:\w+_)?recommends$/) {
1137         next if $status->{ok};
1138         $status->{message} = (!ref($status->{have}) && $status->{have} eq '<none>'
1139                               ? "Optional prerequisite $modname is not installed"
1140                               : "$modname ($status->{have}) is installed, but we prefer to have $spec");
1141       } else {
1142         next if $status->{ok};
1143       }
1144
1145       $out->{$type}{$modname} = $status;
1146     }
1147   }
1148
1149   return $out;
1150 }
1151
1152 # returns a hash of defined prerequisites; i.e. only prereq types with values
1153 sub _enum_prereqs {
1154   my $self = shift;
1155   my %prereqs;
1156   foreach my $type ( @{ $self->prereq_action_types } ) {
1157     if ( $self->can( $type ) ) {
1158       my $prereq = $self->$type() || {};
1159       $prereqs{$type} = $prereq if %$prereq;
1160     }
1161   }
1162   return \%prereqs;
1163 }
1164
1165 sub check_prereq {
1166   my $self = shift;
1167
1168   # If we have XS files, make sure we can process them.
1169   my $xs_files = $self->find_xs_files;
1170   if (keys %$xs_files && !$self->_mb_feature('C_support')) {
1171     $self->log_warn("Warning: this distribution contains XS files, ".
1172                     "but Module::Build is not configured with C_support.  ".
1173                     "Please install ExtUtils::CBuilder to enable C_support.\n");
1174   }
1175
1176   # Check to see if there are any prereqs to check
1177   my $info = $self->_enum_prereqs;
1178   return 1 unless $info;
1179
1180   $self->log_info("Checking prerequisites...\n");
1181
1182   my $failures = $self->prereq_failures($info);
1183
1184   if ( $failures ) {
1185
1186     while (my ($type, $prereqs) = each %$failures) {
1187       while (my ($module, $status) = each %$prereqs) {
1188         my $prefix = ($type =~ /^(?:\w+_)?recommends$/) ? '*' : '- ERROR:';
1189         $self->log_warn(" $prefix $status->{message}\n");
1190       }
1191     }
1192
1193     $self->log_warn(<<EOF);
1194
1195 ERRORS/WARNINGS FOUND IN PREREQUISITES.  You may wish to install the versions
1196 of the modules indicated above before proceeding with this installation
1197
1198 EOF
1199     return 0;
1200
1201   } else {
1202
1203     $self->log_info("Looks good\n\n");
1204     return 1;
1205
1206   }
1207 }
1208
1209 sub perl_version {
1210   my ($self) = @_;
1211   # Check the current perl interpreter
1212   # It's much more convenient to use $] here than $^V, but 'man
1213   # perlvar' says I'm not supposed to.  Bloody tyrant.
1214   return $^V ? $self->perl_version_to_float(sprintf "%vd", $^V) : $];
1215 }
1216
1217 sub perl_version_to_float {
1218   my ($self, $version) = @_;
1219   return $version if grep( /\./, $version ) < 2;
1220   $version =~ s/\./../;
1221   $version =~ s/\.(\d+)/sprintf '%03d', $1/eg;
1222   return $version;
1223 }
1224
1225 sub _parse_conditions {
1226   my ($self, $spec) = @_;
1227
1228   if ($spec =~ /^\s*([\w.]+)\s*$/) { # A plain number, maybe with dots, letters, and underscores
1229     return (">= $spec");
1230   } else {
1231     return split /\s*,\s*/, $spec;
1232   }
1233 }
1234
1235 sub check_installed_status {
1236   my ($self, $modname, $spec) = @_;
1237   my %status = (need => $spec);
1238   
1239   if ($modname eq 'perl') {
1240     $status{have} = $self->perl_version;
1241   
1242   } elsif (eval { no strict; $status{have} = ${"${modname}::VERSION"} }) {
1243     # Don't try to load if it's already loaded
1244     
1245   } else {
1246     my $pm_info = Module::Build::ModuleInfo->new_from_module( $modname );
1247     unless (defined( $pm_info )) {
1248       @status{ qw(have message) } = ('<none>', "$modname is not installed");
1249       return \%status;
1250     }
1251     
1252     $status{have} = $pm_info->version();
1253     if ($spec and !defined($status{have})) {
1254       @status{ qw(have message) } = (undef, "Couldn't find a \$VERSION in prerequisite $modname");
1255       return \%status;
1256     }
1257   }
1258   
1259   my @conditions = $self->_parse_conditions($spec);
1260   
1261   foreach (@conditions) {
1262     my ($op, $version) = /^\s*  (<=?|>=?|==|!=)  \s*  ([\w.]+)  \s*$/x
1263       or die "Invalid prerequisite condition '$_' for $modname";
1264     
1265     $version = $self->perl_version_to_float($version)
1266       if $modname eq 'perl';
1267     
1268     next if $op eq '>=' and !$version;  # Module doesn't have to actually define a $VERSION
1269     
1270     unless ($self->compare_versions( $status{have}, $op, $version )) {
1271       $status{message} = "$modname ($status{have}) is installed, but we need version $op $version";
1272       return \%status;
1273     }
1274   }
1275   
1276   $status{ok} = 1;
1277   return \%status;
1278 }
1279
1280 sub compare_versions {
1281   my $self = shift;
1282   my ($v1, $op, $v2) = @_;
1283   $v1 = Module::Build::Version->new($v1) 
1284     unless UNIVERSAL::isa($v1,'Module::Build::Version');
1285
1286   my $eval_str = "\$v1 $op \$v2";
1287   my $result   = eval $eval_str;
1288   $self->log_warn("error comparing versions: '$eval_str' $@") if $@;
1289
1290   return $result;
1291 }
1292
1293 # I wish I could set $! to a string, but I can't, so I use $@
1294 sub check_installed_version {
1295   my ($self, $modname, $spec) = @_;
1296   
1297   my $status = $self->check_installed_status($modname, $spec);
1298   
1299   if ($status->{ok}) {
1300     return $status->{have} if $status->{have} and "$status->{have}" ne '<none>';
1301     return '0 but true';
1302   }
1303   
1304   $@ = $status->{message};
1305   return 0;
1306 }
1307
1308 sub make_executable {
1309   # Perl's chmod() is mapped to useful things on various non-Unix
1310   # platforms, so we use it in the base class even though it looks
1311   # Unixish.
1312
1313   my $self = shift;
1314   foreach (@_) {
1315     my $current_mode = (stat $_)[2];
1316     chmod $current_mode | oct(111), $_;
1317   }
1318 }
1319
1320 sub is_executable {
1321   # We assume this does the right thing on generic platforms, though
1322   # we do some other more specific stuff on Unixish platforms.
1323   my ($self, $file) = @_;
1324   return -x $file;
1325 }
1326
1327 sub _startperl { shift()->config('startperl') }
1328
1329 # Return any directories in @INC which are not in the default @INC for
1330 # this perl.  For example, stuff passed in with -I or loaded with "use lib".
1331 sub _added_to_INC {
1332   my $self = shift;
1333
1334   my %seen;
1335   $seen{$_}++ foreach $self->_default_INC;
1336   return grep !$seen{$_}++, @INC;
1337 }
1338
1339 # Determine the default @INC for this Perl
1340 {
1341   my @default_inc; # Memoize
1342   sub _default_INC {
1343     my $self = shift;
1344     return @default_inc if @default_inc;
1345     
1346     local $ENV{PERL5LIB};  # this is not considered part of the default.
1347     
1348     my $perl = ref($self) ? $self->perl : $self->find_perl_interpreter;
1349     
1350     my @inc = $self->_backticks($perl, '-le', 'print for @INC');
1351     chomp @inc;
1352     
1353     return @default_inc = @inc;
1354   }
1355 }
1356
1357 sub print_build_script {
1358   my ($self, $fh) = @_;
1359   
1360   my $build_package = $self->build_class;
1361   
1362   my $closedata="";
1363
1364   my %q = map {$_, $self->$_()} qw(config_dir base_dir);
1365
1366   my $case_tolerant = 0+(File::Spec->can('case_tolerant')
1367                          && File::Spec->case_tolerant);
1368   $q{base_dir} = uc $q{base_dir} if $case_tolerant;
1369   $q{base_dir} = Win32::GetShortPathName($q{base_dir}) if $self->is_windowsish;
1370
1371   $q{magic_numfile} = $self->config_file('magicnum');
1372
1373   my @myINC = $self->_added_to_INC;
1374   for (@myINC, values %q) {
1375     $_ = File::Spec->canonpath( $_ );
1376     s/([\\\'])/\\$1/g;
1377   }
1378
1379   my $quoted_INC = join ",\n", map "     '$_'", @myINC;
1380   my $shebang = $self->_startperl;
1381   my $magic_number = $self->magic_number;
1382
1383   print $fh <<EOF;
1384 $shebang
1385
1386 use strict;
1387 use Cwd;
1388 use File::Basename;
1389 use File::Spec;
1390
1391 sub magic_number_matches {
1392   return 0 unless -e '$q{magic_numfile}';
1393   local *FH;
1394   open FH, '$q{magic_numfile}' or return 0;
1395   my \$filenum = <FH>;
1396   close FH;
1397   return \$filenum == $magic_number;
1398 }
1399
1400 my \$progname;
1401 my \$orig_dir;
1402 BEGIN {
1403   \$^W = 1;  # Use warnings
1404   \$progname = basename(\$0);
1405   \$orig_dir = Cwd::cwd();
1406   my \$base_dir = '$q{base_dir}';
1407   if (!magic_number_matches()) {
1408     unless (chdir(\$base_dir)) {
1409       die ("Couldn't chdir(\$base_dir), aborting\\n");
1410     }
1411     unless (magic_number_matches()) {
1412       die ("Configuration seems to be out of date, please re-run 'perl Build.PL' again.\\n");
1413     }
1414   }
1415   unshift \@INC,
1416     (
1417 $quoted_INC
1418     );
1419 }
1420
1421 close(*DATA) unless eof(*DATA); # ensure no open handles to this script
1422
1423 use $build_package;
1424
1425 # Some platforms have problems setting \$^X in shebang contexts, fix it up here
1426 \$^X = Module::Build->find_perl_interpreter;
1427
1428 if (-e 'Build.PL' and not $build_package->up_to_date('Build.PL', \$progname)) {
1429    warn "Warning: Build.PL has been altered.  You may need to run 'perl Build.PL' again.\\n";
1430 }
1431
1432 # This should have just enough arguments to be able to bootstrap the rest.
1433 my \$build = $build_package->resume (
1434   properties => {
1435     config_dir => '$q{config_dir}',
1436     orig_dir => \$orig_dir,
1437   },
1438 );
1439
1440 \$build->dispatch;
1441 EOF
1442 }
1443
1444 sub create_build_script {
1445   my ($self) = @_;
1446   $self->write_config;
1447   
1448   my ($build_script, $dist_name, $dist_version)
1449     = map $self->$_(), qw(build_script dist_name dist_version);
1450   
1451   if ( $self->delete_filetree($build_script) ) {
1452     $self->log_info("Removed previous script '$build_script'\n\n");
1453   }
1454
1455   $self->log_info("Creating new '$build_script' script for ",
1456                   "'$dist_name' version '$dist_version'\n");
1457   my $fh = IO::File->new(">$build_script") or die "Can't create '$build_script': $!";
1458   $self->print_build_script($fh);
1459   close $fh;
1460   
1461   $self->make_executable($build_script);
1462
1463   return 1;
1464 }
1465
1466 sub check_manifest {
1467   my $self = shift;
1468   return unless -e 'MANIFEST';
1469   
1470   # Stolen nearly verbatim from MakeMaker.  But ExtUtils::Manifest
1471   # could easily be re-written into a modern Perl dialect.
1472
1473   require ExtUtils::Manifest;  # ExtUtils::Manifest is not warnings clean.
1474   local ($^W, $ExtUtils::Manifest::Quiet) = (0,1);
1475   
1476   $self->log_info("Checking whether your kit is complete...\n");
1477   if (my @missed = ExtUtils::Manifest::manicheck()) {
1478     $self->log_warn("WARNING: the following files are missing in your kit:\n",
1479                     "\t", join("\n\t", @missed), "\n",
1480                     "Please inform the author.\n\n");
1481   } else {
1482     $self->log_info("Looks good\n\n");
1483   }
1484 }
1485
1486 sub dispatch {
1487   my $self = shift;
1488   local $self->{_completed_actions} = {};
1489
1490   if (@_) {
1491     my ($action, %p) = @_;
1492     my $args = $p{args} ? delete($p{args}) : {};
1493
1494     local $self->{invoked_action} = $action;
1495     local $self->{args} = {%{$self->{args}}, %$args};
1496     local $self->{properties} = {%{$self->{properties}}, %p};
1497     return $self->_call_action($action);
1498   }
1499
1500   die "No build action specified" unless $self->{action};
1501   local $self->{invoked_action} = $self->{action};
1502   $self->_call_action($self->{action});
1503 }
1504
1505 sub _call_action {
1506   my ($self, $action) = @_;
1507
1508   return if $self->{_completed_actions}{$action}++;
1509
1510   local $self->{action} = $action;
1511   my $method = "ACTION_$action";
1512   die "No action '$action' defined, try running the 'help' action.\n" unless $self->can($method);
1513   return $self->$method();
1514 }
1515
1516 # cuts the user-specified options out of the command-line args
1517 sub cull_options {
1518     my $self = shift;
1519     my (@argv) = @_;
1520
1521     my $specs = $self->get_options;
1522     return({}, @argv) unless($specs and %$specs); # no user options
1523
1524     require Getopt::Long;
1525     # XXX Should we let Getopt::Long handle M::B's options? That would
1526     # be easy-ish to add to @specs right here, but wouldn't handle options
1527     # passed without "--" as M::B currently allows. We might be able to
1528     # get around this by setting the "prefix_pattern" Configure option.
1529     my @specs;
1530     my $args = {};
1531     # Construct the specifications for GetOptions.
1532     while (my ($k, $v) = each %$specs) {
1533         # Throw an error if specs conflict with our own.
1534         die "Option specification '$k' conflicts with a " . ref $self
1535           . " option of the same name"
1536           if $self->valid_property($k);
1537         push @specs, $k . (defined $v->{type} ? $v->{type} : '');
1538         push @specs, $v->{store} if exists $v->{store};
1539         $args->{$k} = $v->{default} if exists $v->{default};
1540     }
1541
1542     local @ARGV = @argv; # No other way to dupe Getopt::Long
1543
1544     # Get the options values and return them.
1545     # XXX Add option to allow users to set options?
1546     if ( @specs ) {
1547       Getopt::Long::Configure('pass_through');
1548       Getopt::Long::GetOptions($args, @specs);
1549     }
1550
1551     return $args, @ARGV;
1552 }
1553
1554 sub unparse_args {
1555   my ($self, $args) = @_;
1556   my @out;
1557   while (my ($k, $v) = each %$args) {
1558     push @out, (UNIVERSAL::isa($v, 'HASH')  ? map {+"--$k", "$_=$v->{$_}"} keys %$v :
1559                 UNIVERSAL::isa($v, 'ARRAY') ? map {+"--$k", $_} @$v :
1560                 ("--$k", $v));
1561   }
1562   return @out;
1563 }
1564
1565 sub args {
1566     my $self = shift;
1567     return wantarray ? %{ $self->{args} } : $self->{args} unless @_;
1568     my $key = shift;
1569     $self->{args}{$key} = shift if @_;
1570     return $self->{args}{$key};
1571 }
1572
1573 # allows select parameters (with underscores) to be spoken with dashes
1574 # when used as command-line options
1575 sub _translate_option {
1576   my $self = shift;
1577   my $opt  = shift;
1578
1579   (my $tr_opt = $opt) =~ tr/-/_/;
1580
1581   return $tr_opt if grep $tr_opt =~ /^(?:no_?)?$_$/, qw(
1582     create_makefile_pl
1583     create_readme
1584     extra_compiler_flags
1585     extra_linker_flags
1586     html_css
1587     install_base
1588     install_path
1589     meta_add
1590     meta_merge
1591     test_files
1592     use_rcfile
1593     use_tap_harness
1594     tap_harness_args
1595   ); # normalize only selected option names
1596
1597   return $opt;
1598 }
1599
1600 sub _read_arg {
1601   my ($self, $args, $key, $val) = @_;
1602
1603   $key = $self->_translate_option($key);
1604
1605   if ( exists $args->{$key} ) {
1606     $args->{$key} = [ $args->{$key} ] unless ref $args->{$key};
1607     push @{$args->{$key}}, $val;
1608   } else {
1609     $args->{$key} = $val;
1610   }
1611 }
1612
1613 # decide whether or not an option requires/has an opterand
1614 sub _optional_arg {
1615   my $self = shift;
1616   my $opt  = shift;
1617   my $argv = shift;
1618
1619   $opt = $self->_translate_option($opt);
1620
1621   my @bool_opts = qw(
1622     build_bat
1623     create_readme
1624     pollute
1625     quiet
1626     uninst
1627     use_rcfile
1628     verbose
1629     sign
1630     use_tap_harness
1631   );
1632
1633   # inverted boolean options; eg --noverbose or --no-verbose
1634   # converted to proper name & returned with false value (verbose, 0)
1635   if ( grep $opt =~ /^no[-_]?$_$/, @bool_opts ) {
1636     $opt =~ s/^no-?//;
1637     return ($opt, 0);
1638   }
1639
1640   # non-boolean option; return option unchanged along with its argument
1641   return ($opt, shift(@$argv)) unless grep $_ eq $opt, @bool_opts;
1642
1643   # we're punting a bit here, if an option appears followed by a digit
1644   # we take the digit as the argument for the option. If there is
1645   # nothing that looks like a digit, we pretend the option is a flag
1646   # that is being set and has no argument.
1647   my $arg = 1;
1648   $arg = shift(@$argv) if @$argv && $argv->[0] =~ /^\d+$/;
1649
1650   return ($opt, $arg);
1651 }
1652
1653 sub read_args {
1654   my $self = shift;
1655
1656   (my $args, @_) = $self->cull_options(@_);
1657   my %args = %$args;
1658
1659   my $opt_re = qr/[\w\-]+/;
1660
1661   my ($action, @argv);
1662   while (@_) {
1663     local $_ = shift;
1664     if ( /^(?:--)?($opt_re)=(.*)$/ ) {
1665       $self->_read_arg(\%args, $1, $2);
1666     } elsif ( /^--($opt_re)$/ ) {
1667       my($opt, $arg) = $self->_optional_arg($1, \@_);
1668       $self->_read_arg(\%args, $opt, $arg);
1669     } elsif ( /^($opt_re)$/ and !defined($action)) {
1670       $action = $1;
1671     } else {
1672       push @argv, $_;
1673     }
1674   }
1675   $args{ARGV} = \@argv;
1676
1677   for ('extra_compiler_flags', 'extra_linker_flags') {
1678     $args{$_} = [ $self->split_like_shell($args{$_}) ] if exists $args{$_};
1679   }
1680
1681   # Hashify these parameters
1682   for ($self->hash_properties, 'config') {
1683     next unless exists $args{$_};
1684     my %hash;
1685     $args{$_} ||= [];
1686     $args{$_} = [ $args{$_} ] unless ref $args{$_};
1687     foreach my $arg ( @{$args{$_}} ) {
1688       $arg =~ /(\w+)=(.*)/
1689         or die "Malformed '$_' argument: '$arg' should be something like 'foo=bar'";
1690       $hash{$1} = $2;
1691     }
1692     $args{$_} = \%hash;
1693   }
1694
1695   # De-tilde-ify any path parameters
1696   for my $key (qw(prefix install_base destdir)) {
1697     next if !defined $args{$key};
1698     $args{$key} = $self->_detildefy($args{$key});
1699   }
1700
1701   for my $key (qw(install_path)) {
1702     next if !defined $args{$key};
1703
1704     for my $subkey (keys %{$args{$key}}) {
1705       next if !defined $args{$key}{$subkey};
1706       my $subkey_ext = $self->_detildefy($args{$key}{$subkey});
1707       if ( $subkey eq 'html' ) { # translate for compatability
1708         $args{$key}{binhtml} = $subkey_ext;
1709         $args{$key}{libhtml} = $subkey_ext;
1710       } else {
1711         $args{$key}{$subkey} = $subkey_ext;
1712       }
1713     }
1714   }
1715
1716   if ($args{makefile_env_macros}) {
1717     require Module::Build::Compat;
1718     %args = (%args, Module::Build::Compat->makefile_to_build_macros);
1719   }
1720   
1721   return \%args, $action;
1722 }
1723
1724 # Default: do nothing.  Overridden for Unix & Windows.
1725 sub _detildefy {}
1726
1727
1728 # merge Module::Build argument lists that have already been parsed
1729 # by read_args(). Takes two references to option hashes and merges
1730 # the contents, giving priority to the first.
1731 sub _merge_arglist {
1732   my( $self, $opts1, $opts2 ) = @_;
1733
1734   my %new_opts = %$opts1;
1735   while (my ($key, $val) = each %$opts2) {
1736     if ( exists( $opts1->{$key} ) ) {
1737       if ( ref( $val ) eq 'HASH' ) {
1738         while (my ($k, $v) = each %$val) {
1739           $new_opts{$key}{$k} = $v unless exists( $opts1->{$key}{$k} );
1740         }
1741       }
1742     } else {
1743       $new_opts{$key} = $val
1744     }
1745   }
1746
1747   return %new_opts;
1748 }
1749
1750 # Look for a home directory on various systems.
1751 sub _home_dir {
1752   my @home_dirs;
1753   push( @home_dirs, $ENV{HOME} ) if $ENV{HOME};
1754
1755   push( @home_dirs, File::Spec->catpath($ENV{HOMEDRIVE}, $ENV{HOMEPATH}, '') )
1756       if $ENV{HOMEDRIVE} && $ENV{HOMEPATH};
1757
1758   my @other_home_envs = qw( USERPROFILE APPDATA WINDIR SYS$LOGIN );
1759   push( @home_dirs, map $ENV{$_}, grep $ENV{$_}, @other_home_envs );
1760
1761   my @real_home_dirs = grep -d, @home_dirs;
1762
1763   return wantarray ? @real_home_dirs : shift( @real_home_dirs );
1764 }
1765
1766 sub _find_user_config {
1767   my $self = shift;
1768   my $file = shift;
1769   foreach my $dir ( $self->_home_dir ) {
1770     my $path = File::Spec->catfile( $dir, $file );
1771     return $path if -e $path;
1772   }
1773   return undef;
1774 }
1775
1776 # read ~/.modulebuildrc returning global options '*' and
1777 # options specific to the currently executing $action.
1778 sub read_modulebuildrc {
1779   my( $self, $action ) = @_;
1780
1781   return () unless $self->use_rcfile;
1782
1783   my $modulebuildrc;
1784   if ( exists($ENV{MODULEBUILDRC}) && $ENV{MODULEBUILDRC} eq 'NONE' ) {
1785     return ();
1786   } elsif ( exists($ENV{MODULEBUILDRC}) && -e $ENV{MODULEBUILDRC} ) {
1787     $modulebuildrc = $ENV{MODULEBUILDRC};
1788   } elsif ( exists($ENV{MODULEBUILDRC}) ) {
1789     $self->log_warn("WARNING: Can't find resource file " .
1790                     "'$ENV{MODULEBUILDRC}' defined in environment.\n" .
1791                     "No options loaded\n");
1792     return ();
1793   } else {
1794     $modulebuildrc = $self->_find_user_config( '.modulebuildrc' );
1795     return () unless $modulebuildrc;
1796   }
1797
1798   my $fh = IO::File->new( $modulebuildrc )
1799       or die "Can't open $modulebuildrc: $!";
1800
1801   my %options; my $buffer = '';
1802   while (defined( my $line = <$fh> )) {
1803     chomp( $line );
1804     $line =~ s/#.*$//;
1805     next unless length( $line );
1806
1807     if ( $line =~ /^\S/ ) {
1808       if ( $buffer ) {
1809         my( $action, $options ) = split( /\s+/, $buffer, 2 );
1810         $options{$action} .= $options . ' ';
1811         $buffer = '';
1812       }
1813       $buffer = $line;
1814     } else {
1815       $buffer .= $line;
1816     }
1817   }
1818
1819   if ( $buffer ) { # anything left in $buffer ?
1820     my( $action, $options ) = split( /\s+/, $buffer, 2 );
1821     $options{$action} .= $options . ' '; # merge if more than one line
1822   }
1823
1824   my ($global_opts) =
1825     $self->read_args( $self->split_like_shell( $options{'*'} || '' ) );
1826   my ($action_opts) =
1827     $self->read_args( $self->split_like_shell( $options{$action} || '' ) );
1828
1829   # specific $action options take priority over global options '*'
1830   return $self->_merge_arglist( $action_opts, $global_opts );
1831 }
1832
1833 # merge the relevant options in ~/.modulebuildrc into Module::Build's
1834 # option list where they do not conflict with commandline options.
1835 sub merge_modulebuildrc {
1836   my( $self, $action, %cmdline_opts ) = @_;
1837   my %rc_opts = $self->read_modulebuildrc( $action || $self->{action} || 'build' );
1838   my %new_opts = $self->_merge_arglist( \%cmdline_opts, \%rc_opts );
1839   $self->merge_args( $action, %new_opts );
1840 }
1841
1842 sub merge_args {
1843   my ($self, $action, %args) = @_;
1844   $self->{action} = $action if defined $action;
1845
1846   my %additive = map { $_ => 1 } $self->hash_properties;
1847
1848   # Extract our 'properties' from $cmd_args, the rest are put in 'args'.
1849   while (my ($key, $val) = each %args) {
1850     $self->{phash}{runtime_params}->access( $key => $val )
1851       if $self->valid_property($key);
1852
1853     if ($key eq 'config') {
1854       $self->config($_ => $val->{$_}) foreach keys %$val;
1855     } else {
1856       my $add_to = $additive{$key}             ? $self->{properties}{$key} :
1857                    $self->valid_property($key) ? $self->{properties}       :
1858                    $self->{args}               ;
1859
1860       if ($additive{$key}) {
1861         $add_to->{$_} = $val->{$_} foreach keys %$val;
1862       } else {
1863         $add_to->{$key} = $val;
1864       }
1865     }
1866   }
1867 }
1868
1869 sub cull_args {
1870   my $self = shift;
1871   my ($args, $action) = $self->read_args(@_);
1872   $self->merge_args($action, %$args);
1873   $self->merge_modulebuildrc( $action, %$args );
1874 }
1875
1876 sub super_classes {
1877   my ($self, $class, $seen) = @_;
1878   $class ||= ref($self) || $self;
1879   $seen  ||= {};
1880   
1881   no strict 'refs';
1882   my @super = grep {not $seen->{$_}++} $class, @{ $class . '::ISA' };
1883   return @super, map {$self->super_classes($_,$seen)} @super;
1884 }
1885
1886 sub known_actions {
1887   my ($self) = @_;
1888
1889   my %actions;
1890   no strict 'refs';
1891   
1892   foreach my $class ($self->super_classes) {
1893     foreach ( keys %{ $class . '::' } ) {
1894       $actions{$1}++ if /^ACTION_(\w+)/;
1895     }
1896   }
1897
1898   return wantarray ? sort keys %actions : \%actions;
1899 }
1900
1901 sub get_action_docs {
1902   my ($self, $action) = @_;
1903   my $actions = $self->known_actions;
1904   die "No known action '$action'" unless $actions->{$action};
1905
1906   my ($files_found, @docs) = (0);
1907   foreach my $class ($self->super_classes) {
1908     (my $file = $class) =~ s{::}{/}g;
1909     # NOTE: silently skipping relative paths if any chdir() happened
1910     $file = $INC{$file . '.pm'} or next;
1911     my $fh = IO::File->new("< $file") or next;
1912     $files_found++;
1913
1914     # Code below modified from /usr/bin/perldoc
1915
1916     # Skip to ACTIONS section
1917     local $_;
1918     while (<$fh>) {
1919       last if /^=head1 ACTIONS\s/;
1920     }
1921
1922     # Look for our action and determine the style
1923     my $style;
1924     while (<$fh>) {
1925       last if /^=head1 /;
1926
1927       # only item and head2 are allowed (3&4 are not in 5.005)
1928       if(/^=(item|head2)\s+\Q$action\E\b/) {
1929         $style = $1;
1930         push @docs, $_;
1931         last;
1932       }
1933     }
1934     $style or next; # not here
1935
1936     # and the content
1937     if($style eq 'item') {
1938       my ($found, $inlist) = (0, 0);
1939       while (<$fh>) {
1940         if (/^=(item|back)/) {
1941           last unless $inlist;
1942         }
1943         push @docs, $_;
1944         ++$inlist if /^=over/;
1945         --$inlist if /^=back/;
1946       }
1947     }
1948     else { # head2 style
1949       # stop at anything equal or greater than the found level
1950       while (<$fh>) {
1951         last if(/^=(?:head[12]|cut)/);
1952         push @docs, $_;
1953       }
1954     }
1955     # TODO maybe disallow overriding just pod for an action
1956     # TODO and possibly: @docs and last;
1957   }
1958
1959   unless ($files_found) {
1960     $@ = "Couldn't find any documentation to search";
1961     return;
1962   }
1963   unless (@docs) {
1964     $@ = "Couldn't find any docs for action '$action'";
1965     return;
1966   }
1967   
1968   return join '', @docs;
1969 }
1970
1971 sub ACTION_prereq_report {
1972   my $self = shift;
1973   $self->log_info( $self->prereq_report );
1974 }
1975
1976 sub prereq_report {
1977   my $self = shift;
1978   my @types = @{ $self->prereq_action_types };
1979   my $info = { map { $_ => $self->$_() } @types };
1980
1981   my $output = '';
1982   foreach my $type (@types) {
1983     my $prereqs = $info->{$type};
1984     next unless %$prereqs;
1985     $output .= "\n$type:\n";
1986     my $mod_len = 2;
1987     my $ver_len = 4;
1988     my %mods;
1989     while ( my ($modname, $spec) = each %$prereqs ) {
1990       my $len  = length $modname;
1991       $mod_len = $len if $len > $mod_len;
1992       $spec    ||= '0';
1993       $len     = length $spec;
1994       $ver_len = $len if $len > $ver_len;
1995
1996       my $mod = $self->check_installed_status($modname, $spec);
1997       $mod->{name} = $modname;
1998       $mod->{ok} ||= 0;
1999       $mod->{ok} = ! $mod->{ok} if $type =~ /^(\w+_)?conflicts$/;
2000
2001       $mods{lc $modname} = $mod;
2002     }
2003
2004     my $space  = q{ } x ($mod_len - 3);
2005     my $vspace = q{ } x ($ver_len - 3);
2006     my $sline  = q{-} x ($mod_len - 3);
2007     my $vline  = q{-} x ($ver_len - 3);
2008     my $disposition = ($type =~ /^(\w+_)?conflicts$/) ?
2009                         'Clash' : 'Need';
2010     $output .=
2011       "    Module $space  $disposition $vspace  Have\n".
2012       "    ------$sline+------$vline-+----------\n";
2013
2014
2015     for my $k (sort keys %mods) {
2016       my $mod = $mods{$k};
2017       my $space  = q{ } x ($mod_len - length $k);
2018       my $vspace = q{ } x ($ver_len - length $mod->{need});
2019       my $f = $mod->{ok} ? ' ' : '!';
2020       $output .=
2021         "  $f $mod->{name} $space     $mod->{need}  $vspace   ".
2022         (defined($mod->{have}) ? $mod->{have} : "")."\n";
2023     }
2024   }
2025   return $output;
2026 }
2027
2028 sub ACTION_help {
2029   my ($self) = @_;
2030   my $actions = $self->known_actions;
2031   
2032   if (@{$self->{args}{ARGV}}) {
2033     my $msg = eval {$self->get_action_docs($self->{args}{ARGV}[0], $actions)};
2034     print $@ ? "$@\n" : $msg;
2035     return;
2036   }
2037
2038   print <<EOF;
2039
2040  Usage: $0 <action> arg1=value arg2=value ...
2041  Example: $0 test verbose=1
2042  
2043  Actions defined:
2044 EOF
2045   
2046   print $self->_action_listing($actions);
2047
2048   print "\nRun `Build help <action>` for details on an individual action.\n";
2049   print "See `perldoc Module::Build` for complete documentation.\n";
2050 }
2051
2052 sub _action_listing {
2053   my ($self, $actions) = @_;
2054
2055   # Flow down columns, not across rows
2056   my @actions = sort keys %$actions;
2057   @actions = map $actions[($_ + ($_ % 2) * @actions) / 2],  0..$#actions;
2058   
2059   my $out = '';
2060   while (my ($one, $two) = splice @actions, 0, 2) {
2061     $out .= sprintf("  %-12s                   %-12s\n", $one, $two||'');
2062   }
2063   return $out;
2064 }
2065
2066 sub ACTION_retest {
2067   my ($self) = @_;
2068   
2069   # Protect others against our @INC changes
2070   local @INC = @INC;
2071
2072   # Filter out nonsensical @INC entries - some versions of
2073   # Test::Harness will really explode the number of entries here
2074   @INC = grep {ref() || -d} @INC if @INC > 100;
2075
2076   $self->do_tests;
2077 }
2078
2079 sub ACTION_testall {
2080   my ($self) = @_;
2081
2082   my @types;
2083   for my $action (grep { $_ ne 'all' } $self->get_test_types) {
2084     # XXX We can't just dispatch because we get multiple summaries but
2085     # we'll need to dispatch to support custom setup/teardown in the
2086     # action.  To support that, we'll need to call something besides
2087     # Harness::runtests() because we'll need to collect the results in
2088     # parts, then run the summary.
2089     push(@types, $action);
2090     #$self->_call_action( "test$action" );
2091   }
2092   $self->generic_test(types => ['default', @types]);
2093 }
2094
2095 sub get_test_types {
2096   my ($self) = @_;
2097
2098   my $t = $self->{properties}->{test_types};
2099   return ( defined $t ? ( keys %$t ) : () );
2100 }
2101
2102
2103 sub ACTION_test {
2104   my ($self) = @_;
2105   $self->generic_test(type => 'default');
2106 }
2107
2108 sub generic_test {
2109   my $self = shift;
2110   (@_ % 2) and croak('Odd number of elements in argument hash');
2111   my %args = @_;
2112
2113   my $p = $self->{properties};
2114
2115   my @types = (
2116     (exists($args{type})  ? $args{type} : ()), 
2117     (exists($args{types}) ? @{$args{types}} : ()),
2118   );
2119   @types or croak "need some types of tests to check";
2120
2121   my %test_types = (
2122     default => $p->{test_file_exts},
2123     (defined($p->{test_types}) ? %{$p->{test_types}} : ()),
2124   );
2125
2126   for my $type (@types) {
2127     croak "$type not defined in test_types!"
2128       unless defined $test_types{ $type };
2129   }
2130
2131   # we use local here because it ends up two method calls deep
2132   local $p->{test_file_exts} = [ map { ref $_ ? @$_ : $_ } @test_types{@types} ];
2133   $self->depends_on('code');
2134
2135   # Protect others against our @INC changes
2136   local @INC = @INC;
2137
2138   # Make sure we test the module in blib/
2139   unshift @INC, (File::Spec->catdir($p->{base_dir}, $self->blib, 'lib'),
2140                  File::Spec->catdir($p->{base_dir}, $self->blib, 'arch'));
2141
2142   # Filter out nonsensical @INC entries - some versions of
2143   # Test::Harness will really explode the number of entries here
2144   @INC = grep {ref() || -d} @INC if @INC > 100;
2145
2146   $self->do_tests;
2147 }
2148
2149 sub do_tests {
2150   my $self = shift;
2151
2152   my $tests = $self->find_test_files;
2153
2154   if(@$tests) {
2155     my $args = $self->tap_harness_args;
2156     if($self->use_tap_harness or ($args and %$args)) {
2157       $self->run_tap_harness($tests);
2158     }
2159     else {
2160       $self->run_test_harness($tests);
2161     }
2162   }
2163   else {
2164     $self->log_info("No tests defined.\n");
2165   }
2166
2167   $self->run_visual_script;
2168 }
2169
2170 sub run_tap_harness {
2171   my ($self, $tests) = @_;
2172
2173   require TAP::Harness;
2174
2175   # TODO allow the test @INC to be set via our API?
2176
2177   TAP::Harness->new({
2178     lib => [@INC],
2179     verbosity => $self->{properties}{verbose},
2180     switches  => [ $self->harness_switches ],
2181     %{ $self->tap_harness_args },
2182   })->runtests(@$tests);
2183 }
2184
2185 sub run_test_harness {
2186     my ($self, $tests) = @_;
2187     require Test::Harness;
2188     my $p = $self->{properties};
2189     my @harness_switches = $self->harness_switches;
2190
2191     # Work around a Test::Harness bug that loses the particular perl
2192     # we're running under.  $self->perl is trustworthy, but $^X isn't.
2193     local $^X = $self->perl;
2194
2195     # Do everything in our power to work with all versions of Test::Harness
2196     local $Test::Harness::switches    = join ' ', grep defined, $Test::Harness::switches, @harness_switches;
2197     local $Test::Harness::Switches    = join ' ', grep defined, $Test::Harness::Switches, @harness_switches;
2198     local $ENV{HARNESS_PERL_SWITCHES} = join ' ', grep defined, $ENV{HARNESS_PERL_SWITCHES}, @harness_switches;
2199
2200     $Test::Harness::switches = undef   unless length $Test::Harness::switches;
2201     $Test::Harness::Switches = undef   unless length $Test::Harness::Switches;
2202     delete $ENV{HARNESS_PERL_SWITCHES} unless length $ENV{HARNESS_PERL_SWITCHES};
2203
2204     local ($Test::Harness::verbose,
2205            $Test::Harness::Verbose,
2206            $ENV{TEST_VERBOSE},
2207            $ENV{HARNESS_VERBOSE}) = ($p->{verbose} || 0) x 4;
2208
2209     Test::Harness::runtests(@$tests);
2210 }
2211
2212 sub run_visual_script {
2213     my $self = shift;
2214     # This will get run and the user will see the output.  It doesn't
2215     # emit Test::Harness-style output.
2216     $self->run_perl_script('visual.pl', '-Mblib='.$self->blib)
2217         if -e 'visual.pl';
2218 }
2219
2220 sub harness_switches {
2221     shift->{properties}{debugger} ? qw(-w -d) : ();
2222 }
2223
2224 sub test_files {
2225   my $self = shift;
2226   my $p = $self->{properties};
2227   if (@_) {
2228     return $p->{test_files} = (@_ == 1 ? shift : [@_]);
2229   }
2230   return $self->find_test_files;
2231 }
2232
2233 sub expand_test_dir {
2234   my ($self, $dir) = @_;
2235   my $exts = $self->{properties}{test_file_exts};
2236
2237   return sort map { @{$self->rscan_dir($dir, qr{^[^.].*\Q$_\E$})} } @$exts
2238     if $self->recursive_test_files;
2239
2240   return sort map { glob File::Spec->catfile($dir, "*$_") } @$exts;
2241 }
2242
2243 sub ACTION_testdb {
2244   my ($self) = @_;
2245   local $self->{properties}{debugger} = 1;
2246   $self->depends_on('test');
2247 }
2248
2249 sub ACTION_testcover {
2250   my ($self) = @_;
2251
2252   unless (Module::Build::ModuleInfo->find_module_by_name('Devel::Cover')) {
2253     warn("Cannot run testcover action unless Devel::Cover is installed.\n");
2254     return;
2255   }
2256
2257   $self->add_to_cleanup('coverage', 'cover_db');
2258   $self->depends_on('code');
2259
2260   # See whether any of the *.pm files have changed since last time
2261   # testcover was run.  If so, start over.
2262   if (-e 'cover_db') {
2263     my $pm_files = $self->rscan_dir
2264         (File::Spec->catdir($self->blib, 'lib'), file_qr('\.pm$') );
2265     my $cover_files = $self->rscan_dir('cover_db', sub {-f $_ and not /\.html$/});
2266     
2267     $self->do_system(qw(cover -delete))
2268       unless $self->up_to_date($pm_files,         $cover_files)
2269           && $self->up_to_date($self->test_files, $cover_files);
2270   }
2271
2272   local $Test::Harness::switches    = 
2273   local $Test::Harness::Switches    = 
2274   local $ENV{HARNESS_PERL_SWITCHES} = "-MDevel::Cover";
2275
2276   $self->depends_on('test');
2277   $self->do_system('cover');
2278 }
2279
2280 sub ACTION_code {
2281   my ($self) = @_;
2282   
2283   # All installable stuff gets created in blib/ .
2284   # Create blib/arch to keep blib.pm happy
2285   my $blib = $self->blib;
2286   $self->add_to_cleanup($blib);
2287   File::Path::mkpath( File::Spec->catdir($blib, 'arch') );
2288   
2289   if (my $split = $self->autosplit) {
2290     $self->autosplit_file($_, $blib) for ref($split) ? @$split : ($split);
2291   }
2292   
2293   foreach my $element (@{$self->build_elements}) {
2294     my $method = "process_${element}_files";
2295     $method = "process_files_by_extension" unless $self->can($method);
2296     $self->$method($element);
2297   }
2298
2299   $self->depends_on('config_data');
2300 }
2301
2302 sub ACTION_build {
2303   my $self = shift;
2304   $self->depends_on('code');
2305   $self->depends_on('docs');
2306 }
2307
2308 sub process_files_by_extension {
2309   my ($self, $ext) = @_;
2310   
2311   my $method = "find_${ext}_files";
2312   my $files = $self->can($method) ? $self->$method() : $self->_find_file_by_type($ext,  'lib');
2313   
2314   while (my ($file, $dest) = each %$files) {
2315     $self->copy_if_modified(from => $file, to => File::Spec->catfile($self->blib, $dest) );
2316   }
2317 }
2318
2319 sub process_support_files {
2320   my $self = shift;
2321   my $p = $self->{properties};
2322   return unless $p->{c_source};
2323   
2324   push @{$p->{include_dirs}}, $p->{c_source};
2325   
2326   my $files = $self->rscan_dir($p->{c_source}, file_qr('\.c(pp)?$'));
2327   foreach my $file (@$files) {
2328     push @{$p->{objects}}, $self->compile_c($file);
2329   }
2330 }
2331
2332 sub process_PL_files {
2333   my ($self) = @_;
2334   my $files = $self->find_PL_files;
2335   
2336   while (my ($file, $to) = each %$files) {
2337     unless ($self->up_to_date( $file, $to )) {
2338       $self->run_perl_script($file, [], [@$to]) or die "$file failed";
2339       $self->add_to_cleanup(@$to);
2340     }
2341   }
2342 }
2343
2344 sub process_xs_files {
2345   my $self = shift;
2346   my $files = $self->find_xs_files;
2347   while (my ($from, $to) = each %$files) {
2348     unless ($from eq $to) {
2349       $self->add_to_cleanup($to);
2350       $self->copy_if_modified( from => $from, to => $to );
2351     }
2352     $self->process_xs($to);
2353   }
2354 }
2355
2356 sub process_pod_files { shift()->process_files_by_extension(shift()) }
2357 sub process_pm_files  { shift()->process_files_by_extension(shift()) }
2358
2359 sub process_script_files {
2360   my $self = shift;
2361   my $files = $self->find_script_files;
2362   return unless keys %$files;
2363
2364   my $script_dir = File::Spec->catdir($self->blib, 'script');
2365   File::Path::mkpath( $script_dir );
2366   
2367   foreach my $file (keys %$files) {
2368     my $result = $self->copy_if_modified($file, $script_dir, 'flatten') or next;
2369     $self->fix_shebang_line($result) unless $self->is_vmsish;
2370     $self->make_executable($result);
2371   }
2372 }
2373
2374 sub find_PL_files {
2375   my $self = shift;
2376   if (my $files = $self->{properties}{PL_files}) {
2377     # 'PL_files' is given as a Unix file spec, so we localize_file_path().
2378     
2379     if (UNIVERSAL::isa($files, 'ARRAY')) {
2380       return { map {$_, [/^(.*)\.PL$/]}
2381                map $self->localize_file_path($_),
2382                @$files };
2383
2384     } elsif (UNIVERSAL::isa($files, 'HASH')) {
2385       my %out;
2386       while (my ($file, $to) = each %$files) {
2387         $out{ $self->localize_file_path($file) } = [ map $self->localize_file_path($_),
2388                                                      ref $to ? @$to : ($to) ];
2389       }
2390       return \%out;
2391
2392     } else {
2393       die "'PL_files' must be a hash reference or array reference";
2394     }
2395   }
2396   
2397   return unless -d 'lib';
2398   return { map {$_, [/^(.*)\.PL$/i ]} @{ $self->rscan_dir('lib',
2399                                                           file_qr('\.PL$')) } };
2400 }
2401
2402 sub find_pm_files  { shift->_find_file_by_type('pm',  'lib') }
2403 sub find_pod_files { shift->_find_file_by_type('pod', 'lib') }
2404 sub find_xs_files  { shift->_find_file_by_type('xs',  'lib') }
2405
2406 sub find_script_files {
2407   my $self = shift;
2408   if (my $files = $self->script_files) {
2409     # Always given as a Unix file spec.  Values in the hash are
2410     # meaningless, but we preserve if present.
2411     return { map {$self->localize_file_path($_), $files->{$_}} keys %$files };
2412   }
2413   
2414   # No default location for script files
2415   return {};
2416 }
2417
2418 sub find_test_files {
2419   my $self = shift;
2420   my $p = $self->{properties};
2421
2422   if (my $files = $p->{test_files}) {
2423     $files = [keys %$files] if UNIVERSAL::isa($files, 'HASH');
2424     $files = [map { -d $_ ? $self->expand_test_dir($_) : $_ }
2425               map glob,
2426               $self->split_like_shell($files)];
2427     
2428     # Always given as a Unix file spec.
2429     return [ map $self->localize_file_path($_), @$files ];
2430     
2431   } else {
2432     # Find all possible tests in t/ or test.pl
2433     my @tests;
2434     push @tests, 'test.pl'                          if -e 'test.pl';
2435     push @tests, $self->expand_test_dir('t')        if -e 't' and -d _;
2436     return \@tests;
2437   }
2438 }
2439
2440 sub _find_file_by_type {
2441   my ($self, $type, $dir) = @_;
2442   
2443   if (my $files = $self->{properties}{"${type}_files"}) {
2444     # Always given as a Unix file spec
2445     return { map $self->localize_file_path($_), %$files };
2446   }
2447   
2448   return {} unless -d $dir;
2449   return { map {$_, $_}
2450            map $self->localize_file_path($_),
2451            grep !/\.\#/,
2452            @{ $self->rscan_dir($dir, file_qr("\\.$type\$")) } };
2453 }
2454
2455 sub localize_file_path {
2456   my ($self, $path) = @_;
2457   return File::Spec->catfile( split m{/}, $path );
2458 }
2459
2460 sub localize_dir_path {
2461   my ($self, $path) = @_;
2462   return File::Spec->catdir( split m{/}, $path );
2463 }
2464
2465 sub fix_shebang_line { # Adapted from fixin() in ExtUtils::MM_Unix 1.35
2466   my ($self, @files) = @_;
2467   my $c = ref($self) ? $self->{config} : 'Module::Build::Config';
2468   
2469   my ($does_shbang) = $c->get('sharpbang') =~ /^\s*\#\!/;
2470   for my $file (@files) {
2471     my $FIXIN = IO::File->new($file) or die "Can't process '$file': $!";
2472     local $/ = "\n";
2473     chomp(my $line = <$FIXIN>);
2474     next unless $line =~ s/^\s*\#!\s*//;     # Not a shbang file.
2475     
2476     my ($cmd, $arg) = (split(' ', $line, 2), '');
2477     next unless $cmd =~ /perl/i;
2478     my $interpreter = $self->{properties}{perl};
2479     
2480     $self->log_verbose("Changing sharpbang in $file to $interpreter");
2481     my $shb = '';
2482     $shb .= $c->get('sharpbang')."$interpreter $arg\n" if $does_shbang;
2483     
2484     # I'm not smart enough to know the ramifications of changing the
2485     # embedded newlines here to \n, so I leave 'em in.
2486     $shb .= qq{
2487 eval 'exec $interpreter $arg -S \$0 \${1+"\$\@"}'
2488     if 0; # not running under some shell
2489 } unless $self->is_windowsish; # this won't work on win32, so don't
2490     
2491     my $FIXOUT = IO::File->new(">$file.new")
2492       or die "Can't create new $file: $!\n";
2493     
2494     # Print out the new #! line (or equivalent).
2495     local $\;
2496     undef $/; # Was localized above
2497     print $FIXOUT $shb, <$FIXIN>;
2498     close $FIXIN;
2499     close $FIXOUT;
2500     
2501     rename($file, "$file.bak")
2502       or die "Can't rename $file to $file.bak: $!";
2503     
2504     rename("$file.new", $file)
2505       or die "Can't rename $file.new to $file: $!";
2506     
2507     $self->delete_filetree("$file.bak")
2508       or $self->log_warn("Couldn't clean up $file.bak, leaving it there");
2509     
2510     $self->do_system($c->get('eunicefix'), $file) if $c->get('eunicefix') ne ':';
2511   }
2512 }
2513
2514
2515 sub ACTION_testpod {
2516   my $self = shift;
2517   $self->depends_on('docs');
2518   
2519   eval q{use Test::Pod 0.95; 1}
2520     or die "The 'testpod' action requires Test::Pod version 0.95";
2521
2522   my @files = sort keys %{$self->_find_pods($self->libdoc_dirs)},
2523                    keys %{$self->_find_pods
2524                              ($self->bindoc_dirs,
2525                               exclude => [ file_qr('\.bat$') ])}
2526     or die "Couldn't find any POD files to test\n";
2527
2528   { package Module::Build::PodTester;  # Don't want to pollute the main namespace
2529     Test::Pod->import( tests => scalar @files );
2530     pod_file_ok($_) foreach @files;
2531   }
2532 }
2533
2534 sub ACTION_testpodcoverage {
2535   my $self = shift;
2536
2537   $self->depends_on('docs');
2538   
2539   eval q{use Test::Pod::Coverage 1.00; 1}
2540     or die "The 'testpodcoverage' action requires ",
2541            "Test::Pod::Coverage version 1.00";
2542
2543   # TODO this needs test coverage!
2544
2545   # XXX work-around a bug in Test::Pod::Coverage previous to v1.09
2546   # Make sure we test the module in blib/
2547   local @INC = @INC;
2548   my $p = $self->{properties};
2549   unshift(@INC,
2550     # XXX any reason to include arch?
2551     File::Spec->catdir($p->{base_dir}, $self->blib, 'lib'),
2552     #File::Spec->catdir($p->{base_dir}, $self->blib, 'arch')
2553   );
2554
2555   all_pod_coverage_ok();
2556 }
2557
2558 sub ACTION_docs {
2559   my $self = shift;
2560
2561   $self->depends_on('code');
2562   $self->depends_on('manpages', 'html');
2563 }
2564
2565 # Given a file type, will return true if the file type would normally
2566 # be installed when neither install-base nor prefix has been set.
2567 # I.e. it will be true only if the path is set from Config.pm or
2568 # set explicitly by the user via install-path.
2569 sub _is_default_installable {
2570   my $self = shift;
2571   my $type = shift;
2572   return ( $self->install_destination($type) &&
2573            ( $self->install_path($type) ||
2574              $self->install_sets($self->installdirs)->{$type} )
2575          ) ? 1 : 0;
2576 }
2577
2578 sub ACTION_manpages {
2579   my $self = shift;
2580
2581   return unless $self->_mb_feature('manpage_support');
2582
2583   $self->depends_on('code');
2584
2585   foreach my $type ( qw(bin lib) ) {
2586     my $files = $self->_find_pods( $self->{properties}{"${type}doc_dirs"},
2587                                    exclude => [ file_qr('\.bat$') ] );
2588     next unless %$files;
2589
2590     my $sub = $self->can("manify_${type}_pods");
2591     next unless defined( $sub );
2592
2593     if ( $self->invoked_action eq 'manpages' ) {
2594       $self->$sub();
2595     } elsif ( $self->_is_default_installable("${type}doc") ) {
2596       $self->$sub();
2597     }
2598   }
2599
2600 }
2601
2602 sub manify_bin_pods {
2603   my $self    = shift;
2604
2605   my $files   = $self->_find_pods( $self->{properties}{bindoc_dirs},
2606                                    exclude => [ file_qr('\.bat$') ] );
2607   return unless keys %$files;
2608
2609   my $mandir = File::Spec->catdir( $self->blib, 'bindoc' );
2610   File::Path::mkpath( $mandir, 0, oct(777) );
2611
2612   require Pod::Man;
2613   foreach my $file (keys %$files) {
2614     # Pod::Simple based parsers only support one document per instance.
2615     # This is expected to change in a future version (Pod::Simple > 3.03).
2616     my $parser  = Pod::Man->new( section => 1 ); # binaries go in section 1
2617     my $manpage = $self->man1page_name( $file ) . '.' .
2618                   $self->config( 'man1ext' );
2619     my $outfile = File::Spec->catfile($mandir, $manpage);
2620     next if $self->up_to_date( $file, $outfile );
2621     $self->log_info("Manifying $file -> $outfile\n");
2622     $parser->parse_from_file( $file, $outfile );
2623     $files->{$file} = $outfile;
2624   }
2625 }
2626
2627 sub manify_lib_pods {
2628   my $self    = shift;
2629
2630   my $files   = $self->_find_pods($self->{properties}{libdoc_dirs});
2631   return unless keys %$files;
2632
2633   my $mandir = File::Spec->catdir( $self->blib, 'libdoc' );
2634   File::Path::mkpath( $mandir, 0, oct(777) );
2635
2636   require Pod::Man;
2637   while (my ($file, $relfile) = each %$files) {
2638     # Pod::Simple based parsers only support one document per instance.
2639     # This is expected to change in a future version (Pod::Simple > 3.03).
2640     my $parser  = Pod::Man->new( section => 3 ); # libraries go in section 3
2641     my $manpage = $self->man3page_name( $relfile ) . '.' .
2642                   $self->config( 'man3ext' );
2643     my $outfile = File::Spec->catfile( $mandir, $manpage);
2644     next if $self->up_to_date( $file, $outfile );
2645     $self->log_info("Manifying $file -> $outfile\n");
2646     $parser->parse_from_file( $file, $outfile );
2647     $files->{$file} = $outfile;
2648   }
2649 }
2650
2651 sub _find_pods {
2652   my ($self, $dirs, %args) = @_;
2653   my %files;
2654   foreach my $spec (@$dirs) {
2655     my $dir = $self->localize_dir_path($spec);
2656     next unless -e $dir;
2657
2658     FILE: foreach my $file ( @{ $self->rscan_dir( $dir ) } ) {
2659       foreach my $regexp ( @{ $args{exclude} } ) {
2660         next FILE if $file =~ $regexp;
2661       }
2662       $files{$file} = File::Spec->abs2rel($file, $dir) if $self->contains_pod( $file )
2663     }
2664   }
2665   return \%files;
2666 }
2667
2668 sub contains_pod {
2669   my ($self, $file) = @_;
2670   return '' unless -T $file;  # Only look at text files
2671   
2672   my $fh = IO::File->new( $file ) or die "Can't open $file: $!";
2673   while (my $line = <$fh>) {
2674     return 1 if $line =~ /^\=(?:head|pod|item)/;
2675   }
2676   
2677   return '';
2678 }
2679
2680 sub ACTION_html {
2681   my $self = shift;
2682
2683   return unless $self->_mb_feature('HTML_support');
2684
2685   $self->depends_on('code');
2686
2687   foreach my $type ( qw(bin lib) ) {
2688     my $files = $self->_find_pods( $self->{properties}{"${type}doc_dirs"},
2689                                    exclude => 
2690                                         [ file_qr('\.(?:bat|com|html)$') ] );
2691     next unless %$files;
2692
2693     if ( $self->invoked_action eq 'html' ) {
2694       $self->htmlify_pods( $type );
2695     } elsif ( $self->_is_default_installable("${type}html") ) {
2696       $self->htmlify_pods( $type );
2697     }
2698   }
2699
2700 }
2701
2702
2703 # 1) If it's an ActiveState perl install, we need to run
2704 #    ActivePerl::DocTools->UpdateTOC;
2705 # 2) Links to other modules are not being generated
2706 sub htmlify_pods {
2707   my $self = shift;
2708   my $type = shift;
2709   my $htmldir = shift || File::Spec->catdir($self->blib, "${type}html");
2710
2711   require Module::Build::PodParser;
2712   require Pod::Html;
2713
2714   $self->add_to_cleanup('pod2htm*');
2715
2716   my $pods = $self->_find_pods( $self->{properties}{"${type}doc_dirs"},
2717                                 exclude => [ file_qr('\.(?:bat|com|html)$') ] );
2718   return unless %$pods;  # nothing to do
2719
2720   unless ( -d $htmldir ) {
2721     File::Path::mkpath($htmldir, 0, oct(755))
2722       or die "Couldn't mkdir $htmldir: $!";
2723   }
2724
2725   my @rootdirs = ($type eq 'bin') ? qw(bin) :
2726       $self->installdirs eq 'core' ? qw(lib) : qw(site lib);
2727
2728   my $podpath = join ':',
2729                 map  $_->[1],
2730                 grep -e $_->[0],
2731                 map  [File::Spec->catdir($self->blib, $_), $_],
2732                 qw( script lib );
2733
2734   foreach my $pod ( keys %$pods ) {
2735
2736     my ($name, $path) = File::Basename::fileparse($pods->{$pod},
2737                                                  file_qr('\.(?:pm|plx?|pod)$'));
2738     my @dirs = File::Spec->splitdir( File::Spec->canonpath( $path ) );
2739     pop( @dirs ) if $dirs[-1] eq File::Spec->curdir;
2740
2741     my $fulldir = File::Spec->catfile($htmldir, @rootdirs, @dirs);
2742     my $outfile = File::Spec->catfile($fulldir, "${name}.html");
2743     my $infile  = File::Spec->abs2rel($pod);
2744
2745     next if $self->up_to_date($infile, $outfile);
2746
2747     unless ( -d $fulldir ){
2748       File::Path::mkpath($fulldir, 0, oct(755))
2749         or die "Couldn't mkdir $fulldir: $!";
2750     }
2751
2752     my $path2root = join( '/', ('..') x (@rootdirs+@dirs) );
2753     my $htmlroot = join( '/',
2754                          ($path2root,
2755                           $self->installdirs eq 'core' ? () : qw(site) ) );
2756
2757     my $fh = IO::File->new($infile) or die "Can't read $infile: $!";
2758     my $abstract = Module::Build::PodParser->new(fh => $fh)->get_abstract();
2759
2760     my $title = join( '::', (@dirs, $name) );
2761     $title .= " - $abstract" if $abstract;
2762
2763     my @opts = (
2764                 '--flush',
2765                 "--title=$title",
2766                 "--podpath=$podpath",
2767                 "--infile=$infile",
2768                 "--outfile=$outfile",
2769                 '--podroot=' . $self->blib,
2770                 "--htmlroot=$htmlroot",
2771                );
2772
2773     if ( eval{Pod::Html->VERSION(1.03)} ) {
2774       push( @opts, ('--header', '--backlink=Back to Top') );
2775       push( @opts, "--css=$path2root/" . $self->html_css) if $self->html_css;
2776     }
2777
2778     $self->log_info("HTMLifying $infile -> $outfile\n");
2779     $self->log_verbose("pod2html @opts\n");
2780     Pod::Html::pod2html(@opts); # or warn "pod2html @opts failed: $!";
2781   }
2782
2783 }
2784
2785 # Adapted from ExtUtils::MM_Unix
2786 sub man1page_name {
2787   my $self = shift;
2788   return File::Basename::basename( shift );
2789 }
2790
2791 # Adapted from ExtUtils::MM_Unix and Pod::Man
2792 # Depending on M::B's dependency policy, it might make more sense to refactor
2793 # Pod::Man::begin_pod() to extract a name() methods, and use them...
2794 #    -spurkis
2795 sub man3page_name {
2796   my $self = shift;
2797   my ($vol, $dirs, $file) = File::Spec->splitpath( shift );
2798   my @dirs = File::Spec->splitdir( File::Spec->canonpath($dirs) );
2799   
2800   # Remove known exts from the base name
2801   $file =~ s/\.p(?:od|m|l)\z//i;
2802   
2803   return join( $self->manpage_separator, @dirs, $file );
2804 }
2805
2806 sub manpage_separator {
2807   return '::';
2808 }
2809
2810 # For systems that don't have 'diff' executable, should use Algorithm::Diff
2811 sub ACTION_diff {
2812   my $self = shift;
2813   $self->depends_on('build');
2814   my $local_lib = File::Spec->rel2abs('lib');
2815   my @myINC = grep {$_ ne $local_lib} @INC;
2816
2817   # The actual install destination might not be in @INC, so check there too.
2818   push @myINC, map $self->install_destination($_), qw(lib arch);
2819
2820   my @flags = @{$self->{args}{ARGV}};
2821   @flags = $self->split_like_shell($self->{args}{flags} || '') unless @flags;
2822   
2823   my $installmap = $self->install_map;
2824   delete $installmap->{read};
2825   delete $installmap->{write};
2826
2827   my $text_suffix = file_qr('\.(pm|pod)$');
2828
2829   while (my $localdir = each %$installmap) {
2830     my @localparts = File::Spec->splitdir($localdir);
2831     my $files = $self->rscan_dir($localdir, sub {-f});
2832     
2833     foreach my $file (@$files) {
2834       my @parts = File::Spec->splitdir($file);
2835       @parts = @parts[@localparts .. $#parts]; # Get rid of blib/lib or similar
2836       
2837       my $installed = Module::Build::ModuleInfo->find_module_by_name(
2838                         join('::', @parts), \@myINC );
2839       if (not $installed) {
2840         print "Only in lib: $file\n";
2841         next;
2842       }
2843       
2844       my $status = File::Compare::compare($installed, $file);
2845       next if $status == 0;  # Files are the same
2846       die "Can't compare $installed and $file: $!" if $status == -1;
2847       
2848       if ($file =~ $text_suffix) {
2849         $self->do_system('diff', @flags, $installed, $file);
2850       } else {
2851         print "Binary files $file and $installed differ\n";
2852       }
2853     }
2854   }
2855 }
2856
2857 sub ACTION_pure_install {
2858   shift()->depends_on('install');
2859 }
2860
2861 sub ACTION_install {
2862   my ($self) = @_;
2863   require ExtUtils::Install;
2864   $self->depends_on('build');
2865   ExtUtils::Install::install($self->install_map, !$self->quiet, 0, $self->{args}{uninst}||0);
2866 }
2867
2868 sub ACTION_fakeinstall {
2869   my ($self) = @_;
2870   require ExtUtils::Install;
2871   $self->depends_on('build');
2872   ExtUtils::Install::install($self->install_map, !$self->quiet, 1, $self->{args}{uninst}||0);
2873 }
2874
2875 sub ACTION_versioninstall {
2876   my ($self) = @_;
2877   
2878   die "You must have only.pm 0.25 or greater installed for this operation: $@\n"
2879     unless eval { require only; 'only'->VERSION(0.25); 1 };
2880   
2881   $self->depends_on('build');
2882   
2883   my %onlyargs = map {exists($self->{args}{$_}) ? ($_ => $self->{args}{$_}) : ()}
2884     qw(version versionlib);
2885   only::install::install(%onlyargs);
2886 }
2887
2888 sub ACTION_clean {
2889   my ($self) = @_;
2890   foreach my $item (map glob($_), $self->cleanup) {
2891     $self->delete_filetree($item);
2892   }
2893 }
2894
2895 sub ACTION_realclean {
2896   my ($self) = @_;
2897   $self->depends_on('clean');
2898   $self->delete_filetree($self->config_dir, $self->build_script);
2899 }
2900
2901 sub ACTION_ppd {
2902   my ($self) = @_;
2903   require Module::Build::PPMMaker;
2904   my $ppd = Module::Build::PPMMaker->new();
2905   my $file = $ppd->make_ppd(%{$self->{args}}, build => $self);
2906   $self->add_to_cleanup($file);
2907 }
2908
2909 sub ACTION_ppmdist {
2910   my ($self) = @_;
2911
2912   $self->depends_on( 'build' );
2913
2914   my $ppm = $self->ppm_name;
2915   $self->delete_filetree( $ppm );
2916   $self->log_info( "Creating $ppm\n" );
2917   $self->add_to_cleanup( $ppm, "$ppm.tar.gz" );
2918
2919   my %types = ( # translate types/dirs to those expected by ppm
2920     lib     => 'lib',
2921     arch    => 'arch',
2922     bin     => 'bin',
2923     script  => 'script',
2924     bindoc  => 'man1',
2925     libdoc  => 'man3',
2926     binhtml => undef,
2927     libhtml => undef,
2928   );
2929
2930   foreach my $type ($self->install_types) {
2931     next if exists( $types{$type} ) && !defined( $types{$type} );
2932
2933     my $dir = File::Spec->catdir( $self->blib, $type );
2934     next unless -e $dir;
2935
2936     my $files = $self->rscan_dir( $dir );
2937     foreach my $file ( @$files ) {
2938       next unless -f $file;
2939       my $rel_file =
2940         File::Spec->abs2rel( File::Spec->rel2abs( $file ),
2941                              File::Spec->rel2abs( $dir  ) );
2942       my $to_file  =
2943         File::Spec->catfile( $ppm, 'blib',
2944                             exists( $types{$type} ) ? $types{$type} : $type,
2945                             $rel_file );
2946       $self->copy_if_modified( from => $file, to => $to_file );
2947     }
2948   }
2949
2950   foreach my $type ( qw(bin lib) ) {
2951     local $self->{properties}{html_css} = 'Active.css';
2952     $self->htmlify_pods( $type, File::Spec->catdir($ppm, 'blib', 'html') );
2953   }
2954
2955   # create a tarball;
2956   # the directory tar'ed must be blib so we need to do a chdir first
2957   my $target = File::Spec->catfile( File::Spec->updir, $ppm );
2958   $self->_do_in_dir( $ppm, sub { $self->make_tarball( 'blib', $target ) } );
2959
2960   $self->depends_on( 'ppd' );
2961
2962   $self->delete_filetree( $ppm );
2963 }
2964
2965 sub ACTION_pardist {
2966   my ($self) = @_;
2967
2968   # Need PAR::Dist
2969   if ( not eval { require PAR::Dist; PAR::Dist->VERSION(0.17) } ) {
2970     $self->log_warn(
2971       "In order to create .par distributions, you need to\n"
2972       . "install PAR::Dist first."
2973     );
2974     return();
2975   }
2976   
2977   $self->depends_on( 'build' );
2978
2979   return PAR::Dist::blib_to_par(
2980     name => $self->dist_name,
2981     version => $self->dist_version,
2982   );
2983 }
2984
2985 sub ACTION_dist {
2986   my ($self) = @_;
2987   
2988   $self->depends_on('distdir');
2989   
2990   my $dist_dir = $self->dist_dir;
2991   
2992   $self->make_tarball($dist_dir);
2993   $self->delete_filetree($dist_dir);
2994 }
2995
2996 sub ACTION_distcheck {
2997   my ($self) = @_;
2998
2999   require ExtUtils::Manifest;
3000   local $^W; # ExtUtils::Manifest is not warnings clean.
3001   my ($missing, $extra) = ExtUtils::Manifest::fullcheck();
3002
3003   return unless @$missing || @$extra;
3004
3005   my $msg = "MANIFEST appears to be out of sync with the distribution\n";
3006   if ( $self->invoked_action eq 'distcheck' ) {
3007     die $msg;
3008   } else {
3009     warn $msg;
3010   }
3011 }
3012
3013 sub _add_to_manifest {
3014   my ($self, $manifest, $lines) = @_;
3015   $lines = [$lines] unless ref $lines;
3016
3017   my $existing_files = $self->_read_manifest($manifest);
3018   return unless defined( $existing_files );
3019
3020   @$lines = grep {!exists $existing_files->{$_}} @$lines
3021     or return;
3022
3023   my $mode = (stat $manifest)[2];
3024   chmod($mode | oct(222), $manifest) or die "Can't make $manifest writable: $!";
3025   
3026   my $fh = IO::File->new("< $manifest") or die "Can't read $manifest: $!";
3027   my $last_line = (<$fh>)[-1] || "\n";
3028   my $has_newline = $last_line =~ /\n$/;
3029   $fh->close;
3030
3031   $fh = IO::File->new(">> $manifest") or die "Can't write to $manifest: $!";
3032   print $fh "\n" unless $has_newline;
3033   print $fh map "$_\n", @$lines;
3034   close $fh;
3035   chmod($mode, $manifest);
3036
3037   $self->log_info(map "Added to $manifest: $_\n", @$lines);
3038 }
3039
3040 sub _sign_dir {
3041   my ($self, $dir) = @_;
3042
3043   unless (eval { require Module::Signature; 1 }) {
3044     $self->log_warn("Couldn't load Module::Signature for 'distsign' action:\n $@\n");
3045     return;
3046   }
3047   
3048   # Add SIGNATURE to the MANIFEST
3049   {
3050     my $manifest = File::Spec->catfile($dir, 'MANIFEST');
3051     die "Signing a distribution requires a MANIFEST file" unless -e $manifest;
3052     $self->_add_to_manifest($manifest, "SIGNATURE    Added here by Module::Build");
3053   }
3054   
3055   # Would be nice if Module::Signature took a directory argument.
3056   
3057   $self->_do_in_dir($dir, sub {local $Module::Signature::Quiet = 1; Module::Signature::sign()});
3058 }
3059
3060 sub _do_in_dir {
3061   my ($self, $dir, $do) = @_;
3062
3063   my $start_dir = $self->cwd;
3064   chdir $dir or die "Can't chdir() to $dir: $!";
3065   eval {$do->()};
3066   my @err = $@ ? ($@) : ();
3067   chdir $start_dir or push @err, "Can't chdir() back to $start_dir: $!";
3068   die join "\n", @err if @err;
3069 }
3070
3071 sub ACTION_distsign {
3072   my ($self) = @_;
3073   {
3074     local $self->{properties}{sign} = 0;  # We'll sign it ourselves
3075     $self->depends_on('distdir') unless -d $self->dist_dir;
3076   }
3077   $self->_sign_dir($self->dist_dir);
3078 }
3079
3080 sub ACTION_skipcheck {
3081   my ($self) = @_;
3082   
3083   require ExtUtils::Manifest;
3084   local $^W; # ExtUtils::Manifest is not warnings clean.
3085   ExtUtils::Manifest::skipcheck();
3086 }
3087
3088 sub ACTION_distclean {
3089   my ($self) = @_;
3090   
3091   $self->depends_on('realclean');
3092   $self->depends_on('distcheck');
3093 }
3094
3095 sub do_create_makefile_pl {
3096   my $self = shift;
3097   require Module::Build::Compat;
3098   $self->log_info("Creating Makefile.PL\n");
3099   Module::Build::Compat->create_makefile_pl($self->create_makefile_pl, $self, @_);
3100   $self->_add_to_manifest('MANIFEST', 'Makefile.PL');
3101 }
3102
3103 sub do_create_readme {
3104   my $self = shift;
3105   $self->delete_filetree('README');
3106
3107   my $docfile = $self->_main_docfile;
3108   unless ( $docfile ) {
3109     $self->log_warn(<<EOF);
3110 Cannot create README: can't determine which file contains documentation;
3111 Must supply either 'dist_version_from', or 'module_name' parameter.
3112 EOF
3113     return;
3114   }
3115
3116   if ( eval {require Pod::Readme; 1} ) {
3117     $self->log_info("Creating README using Pod::Readme\n");
3118
3119     my $parser = Pod::Readme->new;
3120     $parser->parse_from_file($docfile, 'README', @_);
3121
3122   } elsif ( eval {require Pod::Text; 1} ) {
3123     $self->log_info("Creating README using Pod::Text\n");
3124
3125     my $fh = IO::File->new('> README');
3126     if ( defined($fh) ) {
3127       local $^W = 0;
3128       no strict "refs";
3129
3130       # work around bug in Pod::Text 3.01, which expects
3131       # Pod::Simple::parse_file to take input and output filehandles
3132       # when it actually only takes an input filehandle
3133
3134       my $old_parse_file;
3135       $old_parse_file = \&{"Pod::Simple::parse_file"}
3136         and
3137       local *{"Pod::Simple::parse_file"} = sub {
3138         my $self = shift;
3139         $self->output_fh($_[1]) if $_[1];
3140         $self->$old_parse_file($_[0]);
3141       }
3142         if $Pod::Text::VERSION
3143           == 3.01; # Split line to avoid evil version-finder
3144
3145       Pod::Text::pod2text( $docfile, $fh );
3146
3147       $fh->close;
3148     } else {
3149       $self->log_warn(
3150         "Cannot create 'README' file: Can't open file for writing\n" );
3151       return;
3152     }
3153
3154   } else {
3155     $self->log_warn("Can't load Pod::Readme or Pod::Text to create README\n");
3156     return;
3157   }
3158
3159   $self->_add_to_manifest('MANIFEST', 'README');
3160 }
3161
3162 sub _main_docfile {
3163   my $self = shift;
3164   if ( my $pm_file = $self->dist_version_from ) {
3165     (my $pod_file = $pm_file) =~ s/.pm$/.pod/;
3166     return (-e $pod_file ? $pod_file : $pm_file);
3167   } else {
3168     return undef;
3169   }
3170 }
3171
3172 sub ACTION_distdir {
3173   my ($self) = @_;
3174
3175   $self->depends_on('distmeta');
3176
3177   my $dist_files = $self->_read_manifest('MANIFEST')
3178     or die "Can't create distdir without a MANIFEST file - run 'manifest' action first";
3179   delete $dist_files->{SIGNATURE};  # Don't copy, create a fresh one
3180   die "No files found in MANIFEST - try running 'manifest' action?\n"
3181     unless ($dist_files and keys %$dist_files);
3182   my $metafile = $self->metafile;
3183   $self->log_warn("*** Did you forget to add $metafile to the MANIFEST?\n")
3184     unless exists $dist_files->{$metafile};
3185   
3186   my $dist_dir = $self->dist_dir;
3187   $self->delete_filetree($dist_dir);
3188   $self->log_info("Creating $dist_dir\n");
3189   $self->add_to_cleanup($dist_dir);
3190   
3191   foreach my $file (keys %$dist_files) {
3192     my $new = $self->copy_if_modified(from => $file, to_dir => $dist_dir, verbose => 0);
3193   }
3194   
3195   $self->_sign_dir($dist_dir) if $self->{properties}{sign};
3196 }
3197
3198 sub ACTION_disttest {
3199   my ($self) = @_;
3200
3201   $self->depends_on('distdir');
3202
3203   $self->_do_in_dir
3204     ( $self->dist_dir,
3205       sub {
3206         # XXX could be different names for scripts
3207
3208         $self->run_perl_script('Build.PL') # XXX Should this be run w/ --nouse-rcfile
3209           or die "Error executing 'Build.PL' in dist directory: $!";
3210         $self->run_perl_script('Build')
3211           or die "Error executing 'Build' in dist directory: $!";
3212         $self->run_perl_script('Build', [], ['test'])
3213           or die "Error executing 'Build test' in dist directory";
3214       });
3215 }
3216
3217 sub _write_default_maniskip {
3218   my $self = shift;
3219   my $file = shift || 'MANIFEST.SKIP';
3220   my $fh = IO::File->new("> $file")
3221     or die "Can't open $file: $!";
3222
3223   # This is derived from MakeMaker's default MANIFEST.SKIP file with
3224   # some new entries
3225
3226   print $fh <<'EOF';
3227 # Avoid version control files.
3228 \bRCS\b
3229 \bCVS\b
3230 ,v$
3231 \B\.svn\b
3232 \B\.cvsignore$
3233
3234 # Avoid Makemaker generated and utility files.
3235 \bMakefile$
3236 \bblib
3237 \bMakeMaker-\d
3238 \bpm_to_blib$
3239 \bblibdirs$
3240 ^MANIFEST\.SKIP$
3241
3242 # Avoid VMS specific Makmaker generated files
3243 \bDescrip.MMS$
3244 \bDESCRIP.MMS$
3245 \bdescrip.mms$
3246
3247 # Avoid Module::Build generated and utility files.
3248 \bBuild$
3249 \bBuild.bat$
3250 \b_build
3251 \bBuild.COM$
3252 \bBUILD.COM$
3253 \bbuild.com$
3254
3255 # Avoid Devel::Cover generated files
3256 \bcover_db
3257
3258 # Avoid temp and backup files.
3259 ~$
3260 \.tmp$
3261 \.old$
3262 \.bak$
3263 \#$
3264 \.#
3265 \.rej$
3266
3267 # Avoid OS-specific files/dirs
3268 #   Mac OSX metadata
3269 \B\.DS_Store
3270 #   Mac OSX SMB mount metadata files
3271 \B\._
3272 # Avoid archives of this distribution
3273 EOF
3274
3275   # Skip, for example, 'Module-Build-0.27.tar.gz'
3276   print $fh '\b'.$self->dist_name.'-[\d\.\_]+'."\n";
3277
3278   $fh->close();
3279 }
3280
3281 sub ACTION_manifest {
3282   my ($self) = @_;
3283
3284   my $maniskip = 'MANIFEST.SKIP';
3285   unless ( -e 'MANIFEST' || -e $maniskip ) {
3286     $self->log_warn("File '$maniskip' does not exist: Creating a default '$maniskip'\n");
3287     $self->_write_default_maniskip($maniskip);
3288   }
3289
3290   require ExtUtils::Manifest;  # ExtUtils::Manifest is not warnings clean.
3291   local ($^W, $ExtUtils::Manifest::Quiet) = (0,1);
3292   ExtUtils::Manifest::mkmanifest();
3293 }
3294
3295 # Case insenstive regex for files
3296 sub file_qr {
3297     return File::Spec->case_tolerant ? qr($_[0])i : qr($_[0]);
3298 }
3299
3300 sub dist_dir {
3301   my ($self) = @_;
3302   return "$self->{properties}{dist_name}-$self->{properties}{dist_version}";
3303 }
3304
3305 sub ppm_name {
3306   my $self = shift;
3307   return 'PPM-' . $self->dist_dir;
3308 }
3309
3310 sub _files_in {
3311   my ($self, $dir) = @_;
3312   return unless -d $dir;
3313
3314   local *DH;
3315   opendir DH, $dir or die "Can't read directory $dir: $!";
3316
3317   my @files;
3318   while (defined (my $file = readdir DH)) {
3319     my $full_path = File::Spec->catfile($dir, $file);
3320     next if -d $full_path;
3321     push @files, $full_path;
3322   }
3323   return @files;
3324 }
3325
3326 sub script_files {
3327   my $self = shift;
3328   
3329   for ($self->{properties}{script_files}) {
3330     $_ = shift if @_;
3331     next unless $_;
3332     
3333     # Always coerce into a hash
3334     return $_ if UNIVERSAL::isa($_, 'HASH');
3335     return $_ = { map {$_,1} @$_ } if UNIVERSAL::isa($_, 'ARRAY');
3336     
3337     die "'script_files' must be a hashref, arrayref, or string" if ref();
3338     
3339     return $_ = { map {$_,1} $self->_files_in( $_ ) } if -d $_;
3340     return $_ = {$_ => 1};
3341   }
3342   
3343   return $_ = { map {$_,1} $self->_files_in('bin') };
3344 }
3345 BEGIN { *scripts = \&script_files; }
3346
3347 {
3348   my %licenses = (
3349     perl         => 'http://dev.perl.org/licenses/',
3350     apache       => 'http://apache.org/licenses/LICENSE-2.0',
3351     artistic     => 'http://opensource.org/licenses/artistic-license.php',
3352     artistic_2   => 'http://opensource.org/licenses/artistic-license-2.0.php',
3353     lgpl         => 'http://opensource.org/licenses/lgpl-license.php',
3354     bsd          => 'http://opensource.org/licenses/bsd-license.php',
3355     gpl          => 'http://opensource.org/licenses/gpl-license.php',
3356     gpl2         => 'http://opensource.org/licenses/gpl-2.0.php',
3357     gpl3         => 'http://opensource.org/licenses/gpl-3.0.html',
3358     mit          => 'http://opensource.org/licenses/mit-license.php',
3359     mozilla      => 'http://opensource.org/licenses/mozilla1.1.php',
3360     open_source  => undef,
3361     unrestricted => undef,
3362     restrictive  => undef,
3363     unknown      => undef,
3364   );
3365   sub valid_licenses {
3366     return \%licenses;
3367   }
3368 }
3369
3370 sub _hash_merge {
3371   my ($self, $h, $k, $v) = @_;
3372   if (ref $h->{$k} eq 'ARRAY') {
3373     push @{$h->{$k}}, ref $v ? @$v : $v;
3374   } elsif (ref $h->{$k} eq 'HASH') {
3375     $h->{$k}{$_} = $v->{$_} foreach keys %$v;
3376   } else {
3377     $h->{$k} = $v;
3378   }
3379 }
3380
3381 sub ACTION_distmeta {
3382   my ($self) = @_;
3383
3384   $self->do_create_makefile_pl if $self->create_makefile_pl;
3385   $self->do_create_readme if $self->create_readme;
3386   $self->do_create_metafile;
3387 }
3388
3389 sub do_create_metafile {
3390   my $self = shift;
3391   return if $self->{wrote_metadata};
3392   
3393   my $p = $self->{properties};
3394   my $metafile = $self->metafile;
3395   
3396   unless ($p->{license}) {
3397     $self->log_warn("No license specified, setting license = 'unknown'\n");
3398     $p->{license} = 'unknown';
3399   }
3400   unless (exists $self->valid_licenses->{ $p->{license} }) {
3401     die "Unknown license type '$p->{license}'";
3402   }
3403
3404   # If we're in the distdir, the metafile may exist and be non-writable.
3405   $self->delete_filetree($metafile);
3406   $self->log_info("Creating $metafile\n");
3407
3408   # Since we're building ourself, we have to do some special stuff
3409   # here: the ConfigData module is found in blib/lib.
3410   local @INC = @INC;
3411   if (($self->module_name || '') eq 'Module::Build') {
3412     $self->depends_on('config_data');
3413     push @INC, File::Spec->catdir($self->blib, 'lib');
3414   }
3415
3416   $self->write_metafile;
3417 }
3418
3419 sub write_metafile {
3420   my $self = shift;
3421   my $metafile = $self->metafile;
3422
3423   if ($self->_mb_feature('YAML_support')) {
3424     require YAML;
3425     require YAML::Node;
3426
3427     # We use YAML::Node to get the order nice in the YAML file.
3428     $self->prepare_metadata( my $node = YAML::Node->new({}) );
3429     
3430     # YAML API changed after version 0.30
3431     my $yaml_sub = $YAML::VERSION le '0.30' ? \&YAML::StoreFile : \&YAML::DumpFile;
3432     $self->{wrote_metadata} = $yaml_sub->($metafile, $node );
3433
3434   } else {
3435     require Module::Build::YAML;
3436     my (%node, @order_keys);
3437     $self->prepare_metadata(\%node, \@order_keys);
3438     $node{_order} = \@order_keys;
3439     &Module::Build::YAML::DumpFile($metafile, \%node);
3440     $self->{wrote_metadata} = 1;
3441   }
3442
3443   $self->_add_to_manifest('MANIFEST', $metafile);
3444 }
3445
3446 sub prepare_metadata {
3447   my ($self, $node, $keys) = @_;
3448   my $p = $self->{properties};
3449
3450   # A little helper sub
3451   my $add_node = sub {
3452     my ($name, $val) = @_;
3453     $node->{$name} = $val;
3454     push @$keys, $name if $keys;
3455   };
3456
3457   foreach (qw(dist_name dist_version dist_author dist_abstract license)) {
3458     (my $name = $_) =~ s/^dist_//;
3459     $add_node->($name, $self->$_());
3460     die "ERROR: Missing required field '$_' for META.yml\n"
3461       unless defined($node->{$name}) && length($node->{$name});
3462   }
3463   $node->{version} = '' . $node->{version}; # Stringify version objects
3464
3465   if (defined( $self->license ) &&
3466       defined( my $url = $self->valid_licenses->{ $self->license } )) {
3467     $node->{resources}{license} = $url;
3468   }
3469
3470   if (exists $p->{configure_requires}) {
3471     foreach my $spec (keys %{$p->{configure_requires}}) {
3472       warn ("Warning: $spec is listed in 'configure_requires', but ".
3473             "it is not found in any of the other prereq fields.\n")
3474         unless grep exists $p->{$_}{$spec}, 
3475                grep !/conflicts$/, @{$self->prereq_action_types};
3476     }
3477   }
3478
3479   foreach ( 'configure_requires', @{$self->prereq_action_types} ) {
3480     if (exists $p->{$_} and keys %{ $p->{$_} }) {
3481       $add_node->($_, $p->{$_});
3482     }
3483   }
3484
3485   if (exists $p->{dynamic_config}) {
3486     $add_node->('dynamic_config', $p->{dynamic_config});
3487   }
3488   my $pkgs = eval { $self->find_dist_packages };
3489   if ($@) {
3490     $self->log_warn("$@\nWARNING: Possible missing or corrupt 'MANIFEST' file.\n" .
3491                     "Nothing to enter for 'provides' field in META.yml\n");
3492   } else {
3493     $node->{provides} = $pkgs if %$pkgs;
3494   }
3495 ;
3496   if (exists $p->{no_index}) {
3497     $add_node->('no_index', $p->{no_index});
3498   }
3499
3500   $add_node->('generated_by', "Module::Build version $Module::Build::VERSION");
3501
3502   $add_node->('meta-spec', 
3503               {version => '1.2',
3504                url     => 'http://module-build.sourceforge.net/META-spec-v1.2.html',
3505               });
3506
3507   while (my($k, $v) = each %{$self->meta_add}) {
3508     $add_node->($k, $v);
3509   }
3510
3511   while (my($k, $v) = each %{$self->meta_merge}) {
3512     $self->_hash_merge($node, $k, $v);
3513   }
3514
3515   return $node;
3516 }
3517
3518 sub _read_manifest {
3519   my ($self, $file) = @_;
3520   return undef unless -e $file;
3521
3522   require ExtUtils::Manifest;  # ExtUtils::Manifest is not warnings clean.
3523   local ($^W, $ExtUtils::Manifest::Quiet) = (0,1);
3524   return scalar ExtUtils::Manifest::maniread($file);
3525 }
3526
3527 sub find_dist_packages {
3528   my $self = shift;
3529
3530   # Only packages in .pm files are candidates for inclusion here.
3531   # Only include things in the MANIFEST, not things in developer's
3532   # private stock.
3533
3534   my $manifest = $self->_read_manifest('MANIFEST')
3535     or die "Can't find dist packages without a MANIFEST file - run 'manifest' action first";
3536
3537   # Localize
3538   my %dist_files = map { $self->localize_file_path($_) => $_ }
3539                        keys %$manifest;
3540
3541   my @pm_files = grep {exists $dist_files{$_}} keys %{ $self->find_pm_files };
3542
3543   # First, we enumerate all packages & versions,
3544   # seperating into primary & alternative candidates
3545   my( %prime, %alt );
3546   foreach my $file (@pm_files) {
3547     next if $dist_files{$file} =~ m{^t/};  # Skip things in t/
3548
3549     my @path = split( /\//, $dist_files{$file} );
3550     (my $prime_package = join( '::', @path[1..$#path] )) =~ s/\.pm$//;
3551
3552     my $pm_info = Module::Build::ModuleInfo->new_from_file( $file );
3553
3554     foreach my $package ( $pm_info->packages_inside ) {
3555       next if $package eq 'main';  # main can appear numerous times, ignore
3556       next if grep /^_/, split( /::/, $package ); # private package, ignore
3557
3558       my $version = $pm_info->version( $package );
3559
3560       if ( $package eq $prime_package ) {
3561         if ( exists( $prime{$package} ) ) {
3562           # M::B::ModuleInfo will handle this conflict
3563           die "Unexpected conflict in '$package'; multiple versions found.\n";
3564         } else {
3565           $prime{$package}{file} = $dist_files{$file};
3566           $prime{$package}{version} = $version if defined( $version );
3567         }
3568       } else {
3569         push( @{$alt{$package}}, {
3570                                   file    => $dist_files{$file},
3571                                   version => $version,
3572                                  } );
3573       }
3574     }
3575   }
3576
3577   # Then we iterate over all the packages found above, identifying conflicts
3578   # and selecting the "best" candidate for recording the file & version
3579   # for each package.
3580   foreach my $package ( keys( %alt ) ) {
3581     my $result = $self->_resolve_module_versions( $alt{$package} );
3582
3583     if ( exists( $prime{$package} ) ) { # primary package selected
3584
3585       if ( $result->{err} ) {
3586         # Use the selected primary package, but there are conflicting
3587         # errors amoung multiple alternative packages that need to be
3588         # reported
3589         $self->log_warn(
3590           "Found conflicting versions for package '$package'\n" .
3591           "  $prime{$package}{file} ($prime{$package}{version})\n" .
3592           $result->{err}
3593         );
3594
3595       } elsif ( defined( $result->{version} ) ) {
3596         # There is a primary package selected, and exactly one
3597         # alternative package
3598
3599         if ( exists( $prime{$package}{version} ) &&
3600              defined( $prime{$package}{version} ) ) {
3601           # Unless the version of the primary package agrees with the
3602           # version of the alternative package, report a conflict
3603           if ( $self->compare_versions( $prime{$package}{version}, '!=',
3604                                         $result->{version} ) ) {
3605             $self->log_warn(
3606               "Found conflicting versions for package '$package'\n" .
3607               "  $prime{$package}{file} ($prime{$package}{version})\n" .
3608               "  $result->{file} ($result->{version})\n"
3609             );
3610           }
3611
3612         } else {
3613           # The prime package selected has no version so, we choose to
3614           # use any alternative package that does have a version
3615           $prime{$package}{file}    = $result->{file};
3616           $prime{$package}{version} = $result->{version};
3617         }
3618
3619       } else {
3620         # no alt package found with a version, but we have a prime
3621         # package so we use it whether it has a version or not
3622       }
3623
3624     } else { # No primary package was selected, use the best alternative
3625
3626       if ( $result->{err} ) {
3627         $self->log_warn(
3628           "Found conflicting versions for package '$package'\n" .
3629           $result->{err}
3630         );
3631       }
3632
3633       # Despite possible conflicting versions, we choose to record
3634       # something rather than nothing
3635       $prime{$package}{file}    = $result->{file};
3636       $prime{$package}{version} = $result->{version}
3637           if defined( $result->{version} );
3638     }
3639   }
3640
3641   # Stringify versions.  Can't use exists() here because of bug in YAML::Node.
3642   for (grep defined $_->{version}, values %prime) {
3643     $_->{version} = '' . $_->{version};
3644   }
3645
3646   return \%prime;
3647 }
3648
3649 # seperate out some of the conflict resolution logic from
3650 # $self->find_dist_packages(), above, into a helper function.
3651 #
3652 sub _resolve_module_versions {
3653   my $self = shift;
3654
3655   my $packages = shift;
3656
3657   my( $file, $version );
3658   my $err = '';
3659     foreach my $p ( @$packages ) {
3660       if ( defined( $p->{version} ) ) {
3661         if ( defined( $version ) ) {
3662           if ( $self->compare_versions( $version, '!=', $p->{version} ) ) {
3663             $err .= "  $p->{file} ($p->{version})\n";
3664           } else {
3665             # same version declared multiple times, ignore
3666           }
3667         } else {
3668           $file    = $p->{file};
3669           $version = $p->{version};
3670         }
3671       }
3672       $file ||= $p->{file} if defined( $p->{file} );
3673     }
3674
3675   if ( $err ) {
3676     $err = "  $file ($version)\n" . $err;
3677   }
3678
3679   my %result = (
3680     file    => $file,
3681     version => $version,
3682     err     => $err
3683   );
3684
3685   return \%result;
3686 }
3687
3688 sub make_tarball {
3689   my ($self, $dir, $file) = @_;
3690   $file ||= $dir;
3691   
3692   $self->log_info("Creating $file.tar.gz\n");
3693   
3694   if ($self->{args}{tar}) {
3695     my $tar_flags = $self->verbose ? 'cvf' : 'cf';
3696     $self->do_system($self->split_like_shell($self->{args}{tar}), $tar_flags, "$file.tar", $dir);
3697     $self->do_system($self->split_like_shell($self->{args}{gzip}), "$file.tar") if $self->{args}{gzip};
3698   } else {
3699     require Archive::Tar;
3700     # Archive::Tar versions >= 1.09 use the following to enable a compatibility
3701     # hack so that the resulting archive is compatible with older clients.
3702     $Archive::Tar::DO_NOT_USE_PREFIX = 0;
3703     my $files = $self->rscan_dir($dir);
3704     Archive::Tar->create_archive("$file.tar.gz", 1, @$files);
3705   }
3706 }
3707
3708 sub install_path {
3709   my $self = shift;
3710   my( $type, $value ) = ( @_, '<empty>' );
3711
3712   Carp::croak( 'Type argument missing' )
3713     unless defined( $type );
3714
3715   my $map = $self->{properties}{install_path};
3716   return $map unless @_;
3717
3718   # delete existing value if $value is literal undef()
3719   unless ( defined( $value ) ) {
3720     delete( $map->{$type} );
3721     return undef;
3722   }
3723
3724   # return existing value if no new $value is given
3725   if ( $value eq '<empty>' ) {
3726     return undef unless exists $map->{$type};
3727     return $map->{$type};
3728   }
3729
3730   # set value if $value is a valid relative path
3731   return $map->{$type} = $value;
3732 }
3733
3734 sub install_base_relpaths {
3735   # Usage: install_base_relpaths(), install_base_relpaths('lib'),
3736   #   or install_base_relpaths('lib' => $value);
3737   my $self = shift;
3738   my $map = $self->{properties}{install_base_relpaths};
3739   return $map unless @_;
3740   return $self->_relpaths($map, @_);
3741 }
3742
3743
3744 # Translated from ExtUtils::MM_Any::init_INSTALL_from_PREFIX
3745 sub prefix_relative {
3746   my ($self, $type) = @_;
3747   my $installdirs = $self->installdirs;
3748
3749   my $relpath = $self->install_sets($installdirs)->{$type};
3750
3751   return $self->_prefixify($relpath,
3752                            $self->original_prefix($installdirs),
3753                            $type,
3754                           );
3755 }
3756
3757 sub _relpaths {
3758   my $self = shift;
3759   my( $map, $type, $value ) = ( @_, '<empty>' );
3760
3761   Carp::croak( 'Type argument missing' )
3762     unless defined( $type );
3763
3764   my @value = ();
3765
3766   # delete existing value if $value is literal undef()
3767   unless ( defined( $value ) ) {
3768     delete( $map->{$type} );
3769     return undef;
3770   }
3771
3772   # return existing value if no new $value is given
3773   elsif ( $value eq '<empty>' ) {
3774     return undef unless exists $map->{$type};
3775     @value = @{ $map->{$type} };
3776   }
3777
3778   # set value if $value is a valid relative path
3779   else {
3780     Carp::croak( "Value must be a relative path" )
3781       if File::Spec::Unix->file_name_is_absolute($value);
3782
3783     @value = split( /\//, $value );
3784     $map->{$type} = \@value;
3785   }
3786
3787   return File::Spec->catdir( @value );
3788 }
3789
3790 # Defaults to use in case the config install paths cannot be prefixified.
3791 sub prefix_relpaths {
3792   # Usage: prefix_relpaths('site'), prefix_relpaths('site', 'lib'),
3793   #   or prefix_relpaths('site', 'lib' => $value);
3794   my $self = shift;
3795   my $installdirs = shift || $self->installdirs;
3796   my $map = $self->{properties}{prefix_relpaths}{$installdirs};
3797   return $map unless @_;
3798   return $self->_relpaths($map, @_);
3799 }
3800
3801
3802 # Translated from ExtUtils::MM_Unix::prefixify()
3803 sub _prefixify {
3804   my($self, $path, $sprefix, $type) = @_;
3805
3806   my $rprefix = $self->prefix;
3807   $rprefix .= '/' if $sprefix =~ m|/$|;
3808
3809   $self->log_verbose("  prefixify $path from $sprefix to $rprefix\n")
3810     if defined( $path ) && length( $path );
3811
3812   if( !defined( $path ) || ( length( $path ) == 0 ) ) {
3813     $self->log_verbose("  no path to prefixify, falling back to default.\n");
3814     return $self->_prefixify_default( $type, $rprefix );
3815   } elsif( !File::Spec->file_name_is_absolute($path) ) {
3816     $self->log_verbose("    path is relative, not prefixifying.\n");
3817   } elsif( $sprefix eq $rprefix ) {
3818     $self->log_verbose("  no new prefix.\n");
3819   } elsif( $path !~ s{^\Q$sprefix\E\b}{}s ) {
3820     $self->log_verbose("    cannot prefixify, falling back to default.\n");
3821     return $self->_prefixify_default( $type, $rprefix );
3822   }
3823
3824   $self->log_verbose("    now $path in $rprefix\n");
3825
3826   return $path;
3827 }
3828
3829 sub _prefixify_default {
3830   my $self = shift;
3831   my $type = shift;
3832   my $rprefix = shift;
3833
3834   my $default = $self->prefix_relpaths($self->installdirs, $type);
3835   if( !$default ) {
3836     $self->log_verbose("    no default install location for type '$type', using prefix '$rprefix'.\n");
3837     return $rprefix;
3838   } else {
3839     return $default;
3840   }
3841 }
3842
3843 sub install_destination {
3844   my ($self, $type) = @_;
3845
3846   return $self->install_path($type) if $self->install_path($type);
3847
3848   if ( $self->install_base ) {
3849     my $relpath = $self->install_base_relpaths($type);
3850     return $relpath ? File::Spec->catdir($self->install_base, $relpath) : undef;
3851   }
3852
3853   if ( $self->prefix ) {
3854     my $relpath = $self->prefix_relative($type);
3855     return $relpath ? File::Spec->catdir($self->prefix, $relpath) : undef;
3856   }
3857
3858   return $self->install_sets($self->installdirs)->{$type};
3859 }
3860
3861 sub install_types {
3862   my $self = shift;
3863
3864   my %types;
3865   if ( $self->install_base ) {
3866     %types = %{$self->install_base_relpaths};
3867   } elsif ( $self->prefix ) {
3868     %types = %{$self->prefix_relpaths};
3869   } else {
3870     %types = %{$self->install_sets($self->installdirs)};
3871   }
3872
3873   %types = (%types, %{$self->install_path});
3874
3875   return sort keys %types;
3876 }
3877
3878 sub install_map {
3879   my ($self, $blib) = @_;
3880   $blib ||= $self->blib;
3881
3882   my( %map, @skipping );
3883   foreach my $type ($self->install_types) {
3884     my $localdir = File::Spec->catdir( $blib, $type );
3885     next unless -e $localdir;
3886
3887     if (my $dest = $self->install_destination($type)) {
3888       $map{$localdir} = $dest;
3889     } else {
3890       push( @skipping, $type );
3891     }
3892   }
3893
3894   $self->log_warn(
3895     "WARNING: Can't figure out install path for types: @skipping\n" .
3896     "Files will not be installed.\n"
3897   ) if @skipping;
3898
3899   # Write the packlist into the same place as ExtUtils::MakeMaker.
3900   if ($self->create_packlist and my $module_name = $self->module_name) {
3901     my $archdir = $self->install_destination('arch');
3902     my @ext = split /::/, $module_name;
3903     $map{write} = File::Spec->catfile($archdir, 'auto', @ext, '.packlist');
3904   }
3905
3906   # Handle destdir
3907   if (length(my $destdir = $self->destdir || '')) {
3908     foreach (keys %map) {
3909       # Need to remove volume from $map{$_} using splitpath, or else
3910       # we'll create something crazy like C:\Foo\Bar\E:\Baz\Quux
3911       # VMS will always have the file separate than the path.
3912       my ($volume, $path, $file) = File::Spec->splitpath( $map{$_}, 1 );
3913
3914       # catdir needs a list of directories, or it will create something
3915       # crazy like volume:[Foo.Bar.volume.Baz.Quux]
3916       my @dirs = File::Spec->splitdir($path);
3917
3918       # First merge the directories
3919       $path = File::Spec->catdir($destdir, @dirs);
3920
3921       # Then put the file back on if there is one.
3922       if ($file ne '') {
3923           $map{$_} = File::Spec->catfile($path, $file)
3924       } else {
3925           $map{$_} = $path;
3926       }
3927     }
3928   }
3929   
3930   $map{read} = '';  # To keep ExtUtils::Install quiet
3931
3932   return \%map;
3933 }
3934
3935 sub depends_on {
3936   my $self = shift;
3937   foreach my $action (@_) {
3938     $self->_call_action($action);
3939   }
3940 }
3941
3942 sub rscan_dir {
3943   my ($self, $dir, $pattern) = @_;
3944   my @result;
3945   local $_; # find() can overwrite $_, so protect ourselves
3946   my $subr = !$pattern ? sub {push @result, $File::Find::name} :
3947              !ref($pattern) || (ref $pattern eq 'Regexp') ? sub {push @result, $File::Find::name if /$pattern/} :
3948              ref($pattern) eq 'CODE' ? sub {push @result, $File::Find::name if $pattern->()} :
3949              die "Unknown pattern type";
3950   
3951   File::Find::find({wanted => $subr, no_chdir => 1}, $dir);
3952   return \@result;
3953 }
3954
3955 sub delete_filetree {
3956   my $self = shift;
3957   my $deleted = 0;
3958   foreach (@_) {
3959     next unless -e $_;
3960     $self->log_info("Deleting $_\n");
3961     File::Path::rmtree($_, 0, 0);
3962     die "Couldn't remove '$_': $!\n" if -e $_;
3963     $deleted++;
3964   }
3965   return $deleted;
3966 }
3967
3968 sub autosplit_file {
3969   my ($self, $file, $to) = @_;
3970   require AutoSplit;
3971   my $dir = File::Spec->catdir($to, 'lib', 'auto');
3972   AutoSplit::autosplit($file, $dir);
3973 }
3974
3975 sub cbuilder {
3976   # Returns a CBuilder object
3977
3978   my $self = shift;
3979   my $p = $self->{properties};
3980   return $p->{_cbuilder} if $p->{_cbuilder};
3981   die "Module::Build is not configured with C_support"
3982           unless $self->_mb_feature('C_support');
3983
3984   require ExtUtils::CBuilder;
3985   return $p->{_cbuilder} = ExtUtils::CBuilder->new(
3986     config => $self->config,
3987     ($self->quiet ? (quiet => 1 ) : ()),
3988   );
3989 }
3990
3991 sub have_c_compiler {
3992   my ($self) = @_;
3993   
3994   my $p = $self->{properties};
3995   return $p->{have_compiler} if defined $p->{have_compiler};
3996   
3997   $self->log_verbose("Checking if compiler tools configured... ");
3998   my $b = eval { $self->cbuilder };
3999   my $have = $b && $b->have_compiler;
4000   $self->log_verbose($have ? "ok.\n" : "failed.\n");
4001   return $p->{have_compiler} = $have;
4002 }
4003
4004 sub compile_c {
4005   my ($self, $file, %args) = @_;
4006   my $b = $self->cbuilder;
4007
4008   my $obj_file = $b->object_file($file);
4009   $self->add_to_cleanup($obj_file);
4010   return $obj_file if $self->up_to_date($file, $obj_file);
4011
4012   $b->compile(source => $file,
4013               defines => $args{defines},
4014               object_file => $obj_file,
4015               include_dirs => $self->include_dirs,
4016               extra_compiler_flags => $self->extra_compiler_flags,
4017              );
4018
4019   return $obj_file;
4020 }
4021
4022 sub link_c {
4023   my ($self, $to, $file_base) = @_;
4024   my $p = $self->{properties}; # For convenience
4025
4026   my $spec = $self->_infer_xs_spec($file_base);
4027
4028   $self->add_to_cleanup($spec->{lib_file});
4029
4030   my $objects = $p->{objects} || [];
4031
4032   return $spec->{lib_file}
4033     if $self->up_to_date([$spec->{obj_file}, @$objects],
4034                          $spec->{lib_file});
4035
4036   my $module_name = $self->module_name;
4037   $module_name  ||= $spec->{module_name};
4038
4039   $self->cbuilder->link(
4040     module_name => $module_name,
4041     objects     => [$spec->{obj_file}, @$objects],
4042     lib_file    => $spec->{lib_file},
4043     extra_linker_flags => $p->{extra_linker_flags} );
4044
4045   return $spec->{lib_file};
4046 }
4047
4048 sub compile_xs {
4049   my ($self, $file, %args) = @_;
4050   
4051   $self->log_info("$file -> $args{outfile}\n");
4052
4053   if (eval {require ExtUtils::ParseXS; 1}) {
4054     
4055     ExtUtils::ParseXS::process_file(
4056                                     filename => $file,
4057                                     prototypes => 0,
4058                                     output => $args{outfile},
4059                                    );
4060   } else {
4061     # Ok, I give up.  Just use backticks.
4062     
4063     my $xsubpp = Module::Build::ModuleInfo->find_module_by_name('ExtUtils::xsubpp')
4064       or die "Can't find ExtUtils::xsubpp in INC (@INC)";
4065     
4066     my @typemaps;
4067     push @typemaps, Module::Build::ModuleInfo->find_module_by_name(
4068         'ExtUtils::typemap', \@INC
4069     );
4070     my $lib_typemap = Module::Build::ModuleInfo->find_module_by_name(
4071         'typemap', [File::Basename::dirname($file)]
4072     );
4073     push @typemaps, $lib_typemap if $lib_typemap;
4074     @typemaps = map {+'-typemap', $_} @typemaps;
4075
4076     my $cf = $self->{config};
4077     my $perl = $self->{properties}{perl};
4078     
4079     my @command = ($perl, "-I".$cf->get('installarchlib'), "-I".$cf->get('installprivlib'), $xsubpp, '-noprototypes',
4080                    @typemaps, $file);
4081     
4082     $self->log_info("@command\n");
4083     my $fh = IO::File->new("> $args{outfile}") or die "Couldn't write $args{outfile}: $!";
4084     print {$fh} $self->_backticks(@command);
4085     close $fh;
4086   }
4087 }
4088
4089 sub split_like_shell {
4090   my ($self, $string) = @_;
4091   
4092   return () unless defined($string);
4093   return @$string if UNIVERSAL::isa($string, 'ARRAY');
4094   $string =~ s/^\s+|\s+$//g;
4095   return () unless length($string);
4096   
4097   return Text::ParseWords::shellwords($string);
4098 }
4099
4100 sub oneliner {
4101   # Returns a string that the shell can evaluate as a perl command.
4102   # This should be avoided whenever possible, since "the shell" really
4103   # means zillions of shells on zillions of platforms and it's really
4104   # hard to get it right all the time.
4105
4106   # Some of this code is stolen with permission from ExtUtils::MakeMaker.
4107
4108   my($self, $cmd, $switches, $args) = @_;
4109   $switches = [] unless defined $switches;
4110   $args = [] unless defined $args;
4111
4112   # Strip leading and trailing newlines
4113   $cmd =~ s{^\n+}{};
4114   $cmd =~ s{\n+$}{};
4115
4116   my $perl = ref($self) ? $self->perl : $self->find_perl_interpreter;
4117   return $self->_quote_args($perl, @$switches, '-e', $cmd, @$args);
4118 }
4119
4120 sub run_perl_script {
4121   my ($self, $script, $preargs, $postargs) = @_;
4122   foreach ($preargs, $postargs) {
4123     $_ = [ $self->split_like_shell($_) ] unless ref();
4124   }
4125   return $self->run_perl_command([@$preargs, $script, @$postargs]);
4126 }
4127
4128 sub run_perl_command {
4129   # XXX Maybe we should accept @args instead of $args?  Must resolve
4130   # this before documenting.
4131   my ($self, $args) = @_;
4132   $args = [ $self->split_like_shell($args) ] unless ref($args);
4133   my $perl = ref($self) ? $self->perl : $self->find_perl_interpreter;
4134
4135   # Make sure our local additions to @INC are propagated to the subprocess
4136   local $ENV{PERL5LIB} = join $self->config('path_sep'), $self->_added_to_INC;
4137
4138   return $self->do_system($perl, @$args);
4139 }
4140
4141 # Infer various data from the path of the input filename
4142 # that is needed to create output files.
4143 # The input filename is expected to be of the form:
4144 #   lib/Module/Name.ext or Module/Name.ext
4145 sub _infer_xs_spec {
4146   my $self = shift;
4147   my $file = shift;
4148
4149   my $cf = $self->{config};
4150
4151   my %spec;
4152
4153   my( $v, $d, $f ) = File::Spec->splitpath( $file );
4154   my @d = File::Spec->splitdir( $d );
4155   (my $file_base = $f) =~ s/\.[^.]+$//i;
4156
4157   $spec{base_name} = $file_base;
4158
4159   $spec{src_dir} = File::Spec->catpath( $v, $d, '' );
4160
4161   # the module name
4162   shift( @d ) while @d && ($d[0] eq 'lib' || $d[0] eq '');
4163   pop( @d ) while @d && $d[-1] eq '';
4164   $spec{module_name} = join( '::', (@d, $file_base) );
4165
4166   $spec{archdir} = File::Spec->catdir($self->blib, 'arch', 'auto',
4167                                       @d, $file_base);
4168
4169   $spec{bs_file} = File::Spec->catfile($spec{archdir}, "${file_base}.bs");
4170
4171   $spec{lib_file} = File::Spec->catfile($spec{archdir},
4172                                         "${file_base}.".$cf->get('dlext'));
4173
4174   $spec{c_file} = File::Spec->catfile( $spec{src_dir},
4175                                        "${file_base}.c" );
4176
4177   $spec{obj_file} = File::Spec->catfile( $spec{src_dir},
4178                                          "${file_base}".$cf->get('obj_ext') );
4179
4180   return \%spec;
4181 }
4182
4183 sub process_xs {
4184   my ($self, $file) = @_;
4185
4186   my $spec = $self->_infer_xs_spec($file);
4187
4188   # File name, minus the suffix
4189   (my $file_base = $file) =~ s/\.[^.]+$//;
4190
4191   # .xs -> .c
4192   $self->add_to_cleanup($spec->{c_file});
4193
4194   unless ($self->up_to_date($file, $spec->{c_file})) {
4195     $self->compile_xs($file, outfile => $spec->{c_file});
4196   }
4197
4198   # .c -> .o
4199   my $v = $self->dist_version;
4200   $self->compile_c($spec->{c_file},
4201                    defines => {VERSION => qq{"$v"}, XS_VERSION => qq{"$v"}});
4202
4203   # archdir
4204   File::Path::mkpath($spec->{archdir}, 0, oct(777)) unless -d $spec->{archdir};
4205
4206   # .xs -> .bs
4207   $self->add_to_cleanup($spec->{bs_file});
4208   unless ($self->up_to_date($file, $spec->{bs_file})) {
4209     require ExtUtils::Mkbootstrap;
4210     $self->log_info("ExtUtils::Mkbootstrap::Mkbootstrap('$spec->{bs_file}')\n");
4211     ExtUtils::Mkbootstrap::Mkbootstrap($spec->{bs_file});  # Original had $BSLOADLIBS - what's that?
4212     {my $fh = IO::File->new(">> $spec->{bs_file}")}  # create
4213     utime((time)x2, $spec->{bs_file});  # touch
4214   }
4215
4216   # .o -> .(a|bundle)
4217   $self->link_c($spec->{archdir}, $file_base);
4218 }
4219
4220 sub do_system {
4221   my ($self, @cmd) = @_;
4222   $self->log_info("@cmd\n");
4223
4224   # Some systems proliferate huge PERL5LIBs, try to ameliorate:
4225   my %seen;
4226   my $sep = $self->config('path_sep');
4227   local $ENV{PERL5LIB} = 
4228     ( !exists($ENV{PERL5LIB}) ? '' :
4229       length($ENV{PERL5LIB}) < 500
4230       ? $ENV{PERL5LIB}
4231       : join $sep, grep { ! $seen{$_}++ and -d $_ } split($sep, $ENV{PERL5LIB})
4232     );
4233
4234   my $status = system(@cmd);
4235   if ($status and $! =~ /Argument list too long/i) {
4236     my $env_entries = '';
4237     foreach (sort keys %ENV) { $env_entries .= "$_=>".length($ENV{$_})."; " }
4238     warn "'Argument list' was 'too long', env lengths are $env_entries";
4239   }
4240   return !$status;
4241 }
4242
4243 sub copy_if_modified {
4244   my $self = shift;
4245   my %args = (@_ > 3
4246               ? ( @_ )
4247               : ( from => shift, to_dir => shift, flatten => shift )
4248              );
4249   $args{verbose} = !$self->quiet
4250     unless exists $args{verbose};
4251   
4252   my $file = $args{from};
4253   unless (defined $file and length $file) {
4254     die "No 'from' parameter given to copy_if_modified";
4255   }
4256   
4257   my $to_path;
4258   if (defined $args{to} and length $args{to}) {
4259     $to_path = $args{to};
4260   } elsif (defined $args{to_dir} and length $args{to_dir}) {
4261     $to_path = File::Spec->catfile( $args{to_dir}, $args{flatten}
4262                                     ? File::Basename::basename($file)
4263                                     : $file );
4264   } else {
4265     die "No 'to' or 'to_dir' parameter given to copy_if_modified";
4266   }
4267   
4268   return if $self->up_to_date($file, $to_path); # Already fresh
4269
4270   {
4271     local $self->{properties}{quiet} = 1;
4272     $self->delete_filetree($to_path); # delete destination if exists
4273   }
4274
4275   # Create parent directories
4276   File::Path::mkpath(File::Basename::dirname($to_path), 0, oct(777));
4277   
4278   $self->log_info("Copying $file -> $to_path\n") if $args{verbose};
4279   
4280   if ($^O eq 'os2') {# copy will not overwrite; 0x1 = overwrite
4281     chmod 0666, $to_path;
4282     File::Copy::syscopy($file, $to_path, 0x1) or die "Can't copy('$file', '$to_path'): $!";
4283   } else {
4284     File::Copy::copy($file, $to_path) or die "Can't copy('$file', '$to_path'): $!";
4285   }
4286
4287   # mode is read-only + (executable if source is executable)
4288   my $mode = oct(444) | ( $self->is_executable($file) ? oct(111) : 0 );
4289   chmod( $mode, $to_path );
4290
4291   return $to_path;
4292 }
4293
4294 sub up_to_date {
4295   my ($self, $source, $derived) = @_;
4296   $source  = [$source]  unless ref $source;
4297   $derived = [$derived] unless ref $derived;
4298
4299   return 0 if grep {not -e} @$derived;
4300
4301   my $most_recent_source = time / (24*60*60);
4302   foreach my $file (@$source) {
4303     unless (-e $file) {
4304       $self->log_warn("Can't find source file $file for up-to-date check");
4305       next;
4306     }
4307     $most_recent_source = -M _ if -M _ < $most_recent_source;
4308   }
4309   
4310   foreach my $derived (@$derived) {
4311     return 0 if -M $derived > $most_recent_source;
4312   }
4313   return 1;
4314 }
4315
4316 sub dir_contains {
4317   my ($self, $first, $second) = @_;
4318   # File::Spec doesn't have an easy way to check whether one directory
4319   # is inside another, unfortunately.
4320   
4321   ($first, $second) = map File::Spec->canonpath($_), ($first, $second);
4322   my @first_dirs = File::Spec->splitdir($first);
4323   my @second_dirs = File::Spec->splitdir($second);
4324
4325   return 0 if @second_dirs < @first_dirs;
4326   
4327   my $is_same = ( File::Spec->case_tolerant
4328                   ? sub {lc(shift()) eq lc(shift())}
4329                   : sub {shift() eq shift()} );
4330   
4331   while (@first_dirs) {
4332     return 0 unless $is_same->(shift @first_dirs, shift @second_dirs);
4333   }
4334   
4335   return 1;
4336 }
4337
4338 1;
4339 __END__
4340
4341
4342 =head1 NAME
4343
4344 Module::Build::Base - Default methods for Module::Build
4345
4346 =head1 SYNOPSIS
4347
4348   Please see the Module::Build documentation.
4349
4350 =head1 DESCRIPTION
4351
4352 The C<Module::Build::Base> module defines the core functionality of
4353 C<Module::Build>.  Its methods may be overridden by any of the
4354 platform-dependent modules in the C<Module::Build::Platform::>
4355 namespace, but the intention here is to make this base module as
4356 platform-neutral as possible.  Nicely enough, Perl has several core
4357 tools available in the C<File::> namespace for doing this, so the task
4358 isn't very difficult.
4359
4360 Please see the C<Module::Build> documentation for more details.
4361
4362 =head1 AUTHOR
4363
4364 Ken Williams <kwilliams@cpan.org>
4365
4366 =head1 COPYRIGHT
4367
4368 Copyright (c) 2001-2006 Ken Williams.  All rights reserved.
4369
4370 This library is free software; you can redistribute it and/or
4371 modify it under the same terms as Perl itself.
4372
4373 =head1 SEE ALSO
4374
4375 perl(1), Module::Build(3)
4376
4377 =cut