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