lib/Module/Build/Base.pm Module::Build
lib/Module/Build/Changes Module::Build
lib/Module/Build/Compat.pm Module::Build
+lib/Module/Build/Config.pm Module::Build
lib/Module/Build/ConfigData.pm Module::Build
lib/Module/Build/Cookbook.pm Module::Build
lib/Module/Build/ModuleInfo.pm Module::Build
use vars qw($VERSION @ISA);
@ISA = qw(Module::Build::Base);
-$VERSION = '0.2805';
+$VERSION = '0.2806';
$VERSION = eval $VERSION;
# Okay, this is the brute-force method of finding out what kind of
sunos Unix
cygwin Unix
os2 Unix
+ interix Unix
dos Windows
MSWin32 Windows
'actions'. In this case the actions run are 'build' (the default
action), 'test', and 'install'. Other actions defined so far include:
- build install
- clean manifest
- code manpages
+ build manifest
+ clean manpages
+ code pardist
config_data ppd
diff ppmdist
dist prereq_report
distcheck pure_install
distclean realclean
- distdir skipcheck
- distmeta test
- distsign testcover
- disttest testdb
- docs testpod
- fakeinstall testpodcoverage
- help versioninstall
- html
+ distdir retest
+ distmeta skipcheck
+ distsign test
+ disttest testcover
+ docs testdb
+ fakeinstall testpod
+ help testpodcoverage
+ html versioninstall
+ install
You can run the 'help' action for a complete list of actions.
warning will be issued.
The current version of the F<META.yml> specification can be found at
-L<http://module-build.sourceforge.net/META-spec-v1.2.html>
+L<http://module-build.sourceforge.net/META-spec-current.html>
=item distsign
the command line with the C<bindoc> and C<libdoc> installation
targets.
+=item pardist
+
+[version 0.2806]
+
+Generates a PAR binary distribution for use with L<PAR> or L<PAR::Dist>.
+
+It requires that the PAR::Dist module (version 0.17 and up) is
+installed on your system.
+
=item ppd
[version 0.20]
C<realclean> action, you are essentially starting over, so you will
have to re-create the C<Build> script again.
+=item retest
+
+[version 0.2806]
+
+This is just like the C<test> action, but doesn't actually build the
+distribution first, and doesn't add F<blib/> to the load path, and
+therefore will test against a I<previously> installed version of the
+distribution. This can be used to verify that a certain installed
+distribution still works, or to see whether newer versions of a
+distribution still pass the old regression tests, and so on.
+
=item skipcheck
[version 0.05]
libhtml => /home/ken/html
Note that this is I<different> from how MakeMaker's C<PREFIX>
-parameter works. See L</"Why PREFIX is not recommended"> for more
-details. C<install_base> just gives you a default layout under the
+parameter works. C<install_base> just gives you a default layout under the
directory you specify, which may have little to do with the
C<installdirs=site> layout.
=head1 COPYRIGHT
-Copyright (c) 2001-2005 Ken Williams. All rights reserved.
+Copyright (c) 2001-2006 Ken Williams. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
=head1 SEE ALSO
-perl(1), L<Module::Build::Cookbook>(3), L<Module::Build::Authoring>(3),
-L<Module::Build::API>(3), L<ExtUtils::MakeMaker>(3), L<YAML>(3)
+perl(1), L<Module::Build::Cookbook>, L<Module::Build::Authoring>,
+L<Module::Build::API>, L<ExtUtils::MakeMaker>, L<YAML>
F<META.yml> Specification:
-L<http://module-build.sourceforge.net/META-spec-v1.2.html>
+L<http://module-build.sourceforge.net/META-spec-current.html>
L<http://www.dsmit.com/cons/>
property is true, then the C<t/> directory will be scanned recursively
for C<*.t> files.
+
=item xs_files
[version 0.19]
In the future, the guts of this method might be replaced with a call
out to C<version.pm>.
-=item config()
+=item config($key)
+
+=item config($key, $value)
+
+=item config() [deprecated]
[version 0.22]
-Returns a hash reference containing the C<Config.pm> hash, including
-any changes the author or user has specified. This is a reference to
-the actual internal hash we use, so you probably shouldn't modify
-stuff there.
+With a single argument C<$key>, returns the value associated with that
+key in the C<Config.pm> hash, including any changes the author or user
+has specified.
+
+With C<$key> and C<$value> arguments, sets the value for future
+callers of C<config($key)>.
+
+With no arguments, returns a hash reference containing all such
+key-value pairs. This usage is deprecated, though, because it's a
+resource hog and violates encapsulation.
=item config_data($name)
=item c_source()
-=item config()
-
=item config_dir()
=item conflicts()
L<Module::Build::Cookbook>(3), L<ExtUtils::MakeMaker>(3), L<YAML>(3)
F<META.yml> Specification:
-L<http://module-build.sourceforge.net/META-spec-v1.2.html>
+L<http://module-build.sourceforge.net/META-spec-current.html>
=cut
L<Module::Build::Cookbook>(3), L<ExtUtils::MakeMaker>(3), L<YAML>(3)
F<META.yml> Specification:
-L<http://module-build.sourceforge.net/META-spec-v1.2.html>
+L<http://module-build.sourceforge.net/META-spec-current.html>
L<http://www.dsmit.com/cons/>
use Module::Build::ModuleInfo;
use Module::Build::Notes;
+use Module::Build::Config;
#################### Constructors ###########################
my $self = bless {
args => {%$args},
- config => {%Config, %$config},
+ config => Module::Build::Config->new(values => $config),
properties => {
base_dir => $package->cwd,
mb_version => $Module::Build::VERSION,
}, $package;
$self->_set_defaults;
- my ($p, $c, $ph) = ($self->{properties}, $self->{config}, $self->{phash});
+ my ($p, $ph) = ($self->{properties}, $self->{phash});
foreach (qw(notes config_data features runtime_params cleanup auto_features)) {
my $file = File::Spec->catfile($self->config_dir, $_);
sub _set_install_paths {
my $self = shift;
- my $c = $self->config;
+ my $c = $self->{config};
my $p = $self->{properties};
- my @libstyle = $c->{installstyle} ?
- File::Spec->splitdir($c->{installstyle}) : qw(lib perl5);
- my $arch = $c->{archname};
- my $version = $c->{version};
+ my @libstyle = $c->get('installstyle') ?
+ File::Spec->splitdir($c->get('installstyle')) : qw(lib perl5);
+ my $arch = $c->get('archname');
+ my $version = $c->get('version');
- my $bindoc = $c->{installman1dir} || undef;
- my $libdoc = $c->{installman3dir} || undef;
+ my $bindoc = $c->get('installman1dir') || undef;
+ my $libdoc = $c->get('installman3dir') || undef;
- my $binhtml = $c->{installhtml1dir} || $c->{installhtmldir} || undef;
- my $libhtml = $c->{installhtml3dir} || $c->{installhtmldir} || undef;
+ my $binhtml = $c->get('installhtml1dir') || $c->get('installhtmldir') || undef;
+ my $libhtml = $c->get('installhtml3dir') || $c->get('installhtmldir') || undef;
$p->{install_sets} =
{
core => {
- lib => $c->{installprivlib},
- arch => $c->{installarchlib},
- bin => $c->{installbin},
- script => $c->{installscript},
+ lib => $c->get('installprivlib'),
+ arch => $c->get('installarchlib'),
+ bin => $c->get('installbin'),
+ script => $c->get('installscript'),
bindoc => $bindoc,
libdoc => $libdoc,
binhtml => $binhtml,
libhtml => $libhtml,
},
site => {
- lib => $c->{installsitelib},
- arch => $c->{installsitearch},
- bin => $c->{installsitebin} || $c->{installbin},
- script => $c->{installsitescript} ||
- $c->{installsitebin} || $c->{installscript},
- bindoc => $c->{installsiteman1dir} || $bindoc,
- libdoc => $c->{installsiteman3dir} || $libdoc,
- binhtml => $c->{installsitehtml1dir} || $binhtml,
- libhtml => $c->{installsitehtml3dir} || $libhtml,
+ lib => $c->get('installsitelib'),
+ arch => $c->get('installsitearch'),
+ bin => $c->get('installsitebin') || $c->get('installbin'),
+ script => $c->get('installsitescript') ||
+ $c->get('installsitebin') || $c->get('installscript'),
+ bindoc => $c->get('installsiteman1dir') || $bindoc,
+ libdoc => $c->get('installsiteman3dir') || $libdoc,
+ binhtml => $c->get('installsitehtml1dir') || $binhtml,
+ libhtml => $c->get('installsitehtml3dir') || $libhtml,
},
vendor => {
- lib => $c->{installvendorlib},
- arch => $c->{installvendorarch},
- bin => $c->{installvendorbin} || $c->{installbin},
- script => $c->{installvendorscript} ||
- $c->{installvendorbin} || $c->{installscript},
- bindoc => $c->{installvendorman1dir} || $bindoc,
- libdoc => $c->{installvendorman3dir} || $libdoc,
- binhtml => $c->{installvendorhtml1dir} || $binhtml,
- libhtml => $c->{installvendorhtml3dir} || $libhtml,
+ lib => $c->get('installvendorlib'),
+ arch => $c->get('installvendorarch'),
+ bin => $c->get('installvendorbin') || $c->get('installbin'),
+ script => $c->get('installvendorscript') ||
+ $c->get('installvendorbin') || $c->get('installscript'),
+ bindoc => $c->get('installvendorman1dir') || $bindoc,
+ libdoc => $c->get('installvendorman3dir') || $libdoc,
+ binhtml => $c->get('installvendorhtml1dir') || $binhtml,
+ libhtml => $c->get('installvendorhtml3dir') || $libhtml,
},
};
$p->{original_prefix} =
{
- core => $c->{installprefixexp} || $c->{installprefix} ||
- $c->{prefixexp} || $c->{prefix} || '',
- site => $c->{siteprefixexp},
- vendor => $c->{usevendorprefix} ? $c->{vendorprefixexp} : '',
+ core => $c->get('installprefixexp') || $c->get('installprefix') ||
+ $c->get('prefixexp') || $c->get('prefix') || '',
+ site => $c->get('siteprefixexp'),
+ vendor => $c->get('usevendorprefix') ? $c->get('vendorprefixexp') : '',
};
$p->{original_prefix}{site} ||= $p->{original_prefix}{core};
my ($self, @cmd) = @_;
if ($self->have_forkpipe) {
local *FH;
- my $pid = open FH, "-|";
+ my $pid = open *FH, "-|";
if ($pid) {
return wantarray ? <FH> : join '', <FH>;
} else {
# invoking the wrong perl.
sub find_perl_interpreter {
my $proto = shift;
- my $c = ref($proto) ? $proto->config : \%Config::Config;
+ my $c = ref($proto) ? $proto->{config} : 'Module::Build::Config';
my $perl = $^X;
my $perl_basename = File::Basename::basename($perl);
# PATH. We do not want to do either if we are running from an
# uninstalled perl in a perl source tree.
- push( @potential_perls, $c->{perlpath} );
+ push( @potential_perls, $c->get('perlpath') );
push( @potential_perls,
map File::Spec->catfile($_, $perl_basename), File::Spec->path() );
# Now that we've enumerated the potential perls, it's time to test
# them to see if any of them match our configuration, returning the
# absolute path of the first successful match.
- my $exe = $c->{exe_ext};
+ my $exe = $c->get('exe_ext');
foreach my $thisperl ( @potential_perls ) {
if ($proto->os_type eq 'VMS') {
if ( $type eq 'HASH' ) {
*{"$class\::$property"} = sub {
my $self = shift;
- my $x = ( $property eq 'config' ) ? $self : $self->{properties};
+ my $x = $self->{properties};
return $x->{$property} unless @_;
if ( defined($_[0]) && !ref($_[0]) ) {
__PACKAGE__->add_property(use_rcfile => 1);
__PACKAGE__->add_property(create_packlist => 1);
__PACKAGE__->add_property(allow_mb_mismatch => 0);
+__PACKAGE__->add_property(config => undef);
{
my $Is_ActivePerl = eval {require ActivePerl::DocTools};
}
__PACKAGE__->add_property($_ => {}) for qw(
- config
get_options
install_base_relpaths
install_path
xs_files
);
+sub config {
+ my $self = shift;
+ my $c = ref($self) ? $self->{config} : 'Module::Build::Config';
+ return $c->all_config unless @_;
+
+ my $key = shift;
+ return $c->get($key) unless @_;
+
+ my $val = shift;
+ return $c->set($key => $val);
+}
sub mb_parents {
# Code borrowed from Class::ISA.
my $fh = IO::File->new($file) or die "Can't read '$file': $!";
my $ref = eval do {local $/; <$fh>};
die if $@;
- ($self->{args}, $self->{config}, $self->{properties}) = @$ref;
+ my $c;
+ ($self->{args}, $c, $self->{properties}) = @$ref;
+ $self->{config} = Module::Build::Config->new(values => $c);
close $fh;
}
my @items = @{ $self->prereq_action_types };
$self->_write_data('prereqs', { map { $_, $self->$_() } @items });
- $self->_write_data('build_params', [$self->{args}, $self->{config}, $self->{properties}]);
+ $self->_write_data('build_params', [$self->{args}, $self->{config}->values_set, $self->{properties}]);
# Set a new magic number and write it to a file
$self->_write_data('magicnum', $self->magic_number(int rand 1_000_000));
my $xs_files = $self->find_xs_files;
if (keys %$xs_files && !$self->_mb_feature('C_support')) {
$self->log_warn("Warning: this distribution contains XS files, ".
- "but Module::Build is not configured with C_support");
+ "but Module::Build is not configured with C_support. ".
+ "Please install ExtUtils::CBuilder to enable C_support.\n");
}
# Check to see if there are any prereqs to check
my $self = shift;
foreach (@_) {
my $current_mode = (stat $_)[2];
- chmod $current_mode | 0111, $_;
+ chmod $current_mode | oct(111), $_;
}
}
$args{ARGV} = \@argv;
# Hashify these parameters
- for ($self->hash_properties) {
+ for ($self->hash_properties, 'config') {
next unless exists $args{$_};
my %hash;
$args{$_} ||= [];
sub _detildefy {
my $arg = shift;
- my($new_arg) = glob($arg) if $arg =~ /^~/;
-
- return defined($new_arg) ? $new_arg : $arg;
+ return $arg =~ /^~/ ? (glob $arg)[0] : $arg;
}
while (my ($key, $val) = each %args) {
$self->{phash}{runtime_params}->access( $key => $val )
if $self->valid_property($key);
- my $add_to = ( $key eq 'config' ? $self->{config}
- : $additive{$key} ? $self->{properties}{$key}
- : $self->valid_property($key) ? $self->{properties}
- : $self->{args});
- if ($additive{$key}) {
- $add_to->{$_} = $val->{$_} foreach keys %$val;
+ if ($key eq 'config') {
+ $self->config($_ => $val->{$_}) foreach keys %$val;
} else {
- $add_to->{$key} = $val;
+ my $add_to = ( $additive{$key} ? $self->{properties}{$key}
+ : $self->valid_property($key) ? $self->{properties}
+ : $self->{args});
+
+ if ($additive{$key}) {
+ $add_to->{$_} = $val->{$_} foreach keys %$val;
+ } else {
+ $add_to->{$key} = $val;
+ }
}
}
}
return $out;
}
+sub ACTION_retest {
+ my ($self) = @_;
+
+ # Protect others against our @INC changes
+ local @INC = @INC;
+
+ # Filter out nonsensical @INC entries - some versions of
+ # Test::Harness will really explode the number of entries here
+ @INC = grep {ref() || -d} @INC if @INC > 100;
+
+ $self->do_tests;
+}
+
+
sub ACTION_test {
my ($self) = @_;
my $p = $self->{properties};
- require Test::Harness;
$self->depends_on('code');
+ # Protect others against our @INC changes
+ local @INC = @INC;
+
+ # Make sure we test the module in blib/
+ unshift @INC, (File::Spec->catdir($p->{base_dir}, $self->blib, 'lib'),
+ File::Spec->catdir($p->{base_dir}, $self->blib, 'arch'));
+
+ # Filter out nonsensical @INC entries - some versions of
+ # Test::Harness will really explode the number of entries here
+ @INC = grep {ref() || -d} @INC if @INC > 100;
+
+ $self->do_tests;
+}
+
+sub do_tests {
+ my $self = shift;
+ my $p = $self->{properties};
+ require Test::Harness;
+
# Do everything in our power to work with all versions of Test::Harness
my @harness_switches = $p->{debugger} ? qw(-w -d) : ();
local $Test::Harness::switches = join ' ', grep defined, $Test::Harness::switches, @harness_switches;
$ENV{TEST_VERBOSE},
$ENV{HARNESS_VERBOSE}) = ($p->{verbose} || 0) x 4;
- # Make sure we test the module in blib/
- local @INC = (File::Spec->catdir($p->{base_dir}, $self->blib, 'lib'),
- File::Spec->catdir($p->{base_dir}, $self->blib, 'arch'),
- @INC);
-
- # Filter out nonsensical @INC entries - some versions of
- # Test::Harness will really explode the number of entries here
- @INC = grep {ref() || -d} @INC if @INC > 100;
-
my $tests = $self->find_test_files;
if (@$tests) {
my $cover_files = $self->rscan_dir('cover_db', sub {-f $_ and not /\.html$/});
$self->do_system(qw(cover -delete))
- unless $self->up_to_date($pm_files, $cover_files);
+ unless $self->up_to_date($pm_files, $cover_files)
+ && $self->up_to_date($self->test_files, $cover_files);
}
local $Test::Harness::switches =
sub fix_shebang_line { # Adapted from fixin() in ExtUtils::MM_Unix 1.35
my ($self, @files) = @_;
- my $c = $self->config;
+ my $c = ref($self) ? $self->{config} : 'Module::Build::Config';
- my ($does_shbang) = $c->{sharpbang} =~ /^\s*\#\!/;
+ my ($does_shbang) = $c->get('sharpbang') =~ /^\s*\#\!/;
for my $file (@files) {
my $FIXIN = IO::File->new($file) or die "Can't process '$file': $!";
local $/ = "\n";
$self->log_verbose("Changing sharpbang in $file to $interpreter");
my $shb = '';
- $shb .= "$c->{sharpbang}$interpreter $arg\n" if $does_shbang;
+ $shb .= $c->get('sharpbang')."$interpreter $arg\n" if $does_shbang;
# I'm not smart enough to know the ramifications of changing the
# embedded newlines here to \n, so I leave 'em in.
unlink "$file.bak"
or $self->log_warn("Couldn't clean up $file.bak, leaving it there");
- $self->do_system($c->{eunicefix}, $file) if $c->{eunicefix} ne ':';
+ $self->do_system($c->get('eunicefix'), $file) if $c->get('eunicefix') ne ':';
}
}
return unless keys %$files;
my $mandir = File::Spec->catdir( $self->blib, 'bindoc' );
- File::Path::mkpath( $mandir, 0, 0777 );
+ File::Path::mkpath( $mandir, 0, oct(777) );
require Pod::Man;
foreach my $file (keys %$files) {
return unless keys %$files;
my $mandir = File::Spec->catdir( $self->blib, 'libdoc' );
- File::Path::mkpath( $mandir, 0, 0777 );
+ File::Path::mkpath( $mandir, 0, oct(777) );
require Pod::Man;
while (my ($file, $relfile) = each %$files) {
return unless %$pods; # nothing to do
unless ( -d $htmldir ) {
- File::Path::mkpath($htmldir, 0, 0755)
+ File::Path::mkpath($htmldir, 0, oct(755))
or die "Couldn't mkdir $htmldir: $!";
}
next if $self->up_to_date($infile, $outfile);
unless ( -d $fulldir ){
- File::Path::mkpath($fulldir, 0, 0755)
+ File::Path::mkpath($fulldir, 0, oct(755))
or die "Couldn't mkdir $fulldir: $!";
}
$self->delete_filetree( $ppm );
}
+sub ACTION_pardist {
+ my ($self) = @_;
+
+ # Need PAR::Dist
+ if ( not eval { require PAR::Dist; PAR::Dist->VERSION(0.17) } ) {
+ $self->log_warn(
+ "In order to create .par distributions, you need to\n"
+ . "install PAR::Dist first."
+ );
+ return();
+ }
+
+ $self->depends_on( 'build' );
+
+ return PAR::Dist::blib_to_par(
+ name => $self->dist_name,
+ version => $self->dist_version,
+ );
+}
+
sub ACTION_dist {
my ($self) = @_;
or return;
my $mode = (stat $manifest)[2];
- chmod($mode | 0222, $manifest) or die "Can't make $manifest writable: $!";
+ chmod($mode | oct(222), $manifest) or die "Can't make $manifest writable: $!";
my $fh = IO::File->new("< $manifest") or die "Can't read $manifest: $!";
my $last_line = (<$fh>)[-1] || "\n";
}
}
- # Stringify versions
- for (grep exists $_->{version}, values %prime) {
- $_->{version} = $_->{version}->stringify;
+ # Stringify versions. Can't use exists() here because of bug in YAML::Node.
+ for (grep defined $_->{version}, values %prime) {
+ $_->{version} = '' . $_->{version};
}
return \%prime;
}
@typemaps = map {+'-typemap', $_} @typemaps;
- my $cf = $self->config;
+ my $cf = $self->{config};
my $perl = $self->{properties}{perl};
- my @command = ($perl, "-I$cf->{installarchlib}", "-I$cf->{installprivlib}", $xsubpp, '-noprototypes',
+ my @command = ($perl, "-I".$cf->get('installarchlib'), "-I".$cf->get('installprivlib'), $xsubpp, '-noprototypes',
@typemaps, $file);
$self->log_info("@command\n");
# this before documenting.
my ($self, $args) = @_;
$args = [ $self->split_like_shell($args) ] unless ref($args);
- $args = [ split(/\s+/, $self->_quote_args($args)) ] if $self->os_type eq 'VMS';
my $perl = ref($self) ? $self->perl : $self->find_perl_interpreter;
# Make sure our local additions to @INC are propagated to the subprocess
- my $c = ref $self ? $self->config : \%Config::Config;
- local $ENV{PERL5LIB} = join $c->{path_sep}, $self->_added_to_INC;
+ local $ENV{PERL5LIB} = join $self->config('path_sep'), $self->_added_to_INC;
return $self->do_system($perl, @$args);
}
$spec{bs_file} = File::Spec->catfile($spec{archdir}, "${file_base}.bs");
$spec{lib_file} = File::Spec->catfile($spec{archdir},
- "${file_base}.$cf->{dlext}");
+ "${file_base}.".$cf->get('dlext'));
$spec{c_file} = File::Spec->catfile( $spec{src_dir},
"${file_base}.c" );
$spec{obj_file} = File::Spec->catfile( $spec{src_dir},
- "${file_base}$cf->{obj_ext}" );
+ "${file_base}".$cf->get('obj_ext') );
return \%spec;
}
sub process_xs {
my ($self, $file) = @_;
- my $cf = $self->config; # For convenience
my $spec = $self->_infer_xs_spec($file);
defines => {VERSION => qq{"$v"}, XS_VERSION => qq{"$v"}});
# archdir
- File::Path::mkpath($spec->{archdir}, 0, 0777) unless -d $spec->{archdir};
+ File::Path::mkpath($spec->{archdir}, 0, oct(777)) unless -d $spec->{archdir};
# .xs -> .bs
$self->add_to_cleanup($spec->{bs_file});
sub do_system {
my ($self, @cmd) = @_;
$self->log_info("@cmd\n");
+
+ # Some systems proliferate huge PERL5LIBs, try to ameliorate:
+ my %seen;
+ my $sep = $self->config('path_sep');
+ local $ENV{PERL5LIB} =
+ ( length($ENV{PERL5LIB}) < 500
+ ? $ENV{PERL5LIB}
+ : join $sep, grep { ! $seen{$_}++ and -d $_ } split($sep, $ENV{PERL5LIB})
+ );
+
my $status = system(@cmd);
if ($status and $! =~ /Argument list too long/i) {
my $env_entries = '';
return if $self->up_to_date($file, $to_path); # Already fresh
- $self->delete_filetree($to_path); # delete destination if exists
+ {
+ local $self->{properties}{quiet} = 1;
+ $self->delete_filetree($to_path); # delete destination if exists
+ }
# Create parent directories
- File::Path::mkpath(File::Basename::dirname($to_path), 0, 0777);
+ File::Path::mkpath(File::Basename::dirname($to_path), 0, oct(777));
- $self->log_info("$file -> $to_path\n") if $args{verbose};
+ $self->log_info("Copying $file -> $to_path\n") if $args{verbose};
File::Copy::copy($file, $to_path) or die "Can't copy('$file', '$to_path'): $!";
# mode is read-only + (executable if source is executable)
- my $mode = 0444 | ( $self->is_executable($file) ? 0111 : 0 );
+ my $mode = oct(444) | ( $self->is_executable($file) ? oct(111) : 0 );
chmod( $mode, $to_path );
return $to_path;
=head1 AUTHOR
-Ken Williams <ken@cpan.org>
+Ken Williams <kwilliams@cpan.org>
=head1 COPYRIGHT
-Copyright (c) 2001-2005 Ken Williams. All rights reserved.
+Copyright (c) 2001-2006 Ken Williams. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
Revision history for Perl extension Module::Build.
+ - On some systems (haven't identified the actual problem yet)
+ $ENV{PERL5LIB} can grow to enormous enough sizes that we can't
+ launch any more subprocesses because the environment table is full.
+ This is the now-infamous "Couldn't run Build.PL: Argument list too
+ long" error. Now we detect such situations and trim the directory
+ list to only include directories that actually exist, listed only
+ once each. Not the ideal solution, but it should work.
+
+ - Silence a warning in M::B::ModuleInfo that happens when the author
+ is using the "$VERSION = eval $VERSION" idiom.
+
+ - When running the 'testcover' action, do "cover --delete" if any of
+ the test files have changed (we already did so if any of the code
+ under test has changed). [Suggested by Chris Dolan, RT #23584]
+
+ - Fixed a broken link in the documentation about PREFIX. [Spotted by
+ David Steinbrunner]
+
+ - Changes to do_system() & friends on VMS to get system calls working
+ much better there. [Craig Berry]
+
+ - Added the "pardist" target which creates a PAR binary distribution
+ akin to a PPM distribution. [Steffen Mueller]
+
+ - Added the Interix platform as a Unix variant. [Stephen Hartland]
+
+ - Improved the error message we emit when a distribution contains XS
+ files but the user has no C compiler. [Suggested by Andreas Koenig]
+
+0.2805_01 Thu Sep 7 21:57:29 CDT 2006
+
+ - Because of a weird behavior of YAML::Node, any distribution that
+ used version.pm objects to define their versions was generating the
+ wrong syntax for the versions in their META.yml file. They will
+ now appear as strings like v3.42.1 or similar, including the
+ leading v.
+
+ - Upgraded to version 0.67 of version.pm. [John Peacock]
+
+ - Added a contrib/ directory with a bash completion function for M::B
+ actions and switches. [Julian Mehnle]
+
+ - When we eval() the embedded version.pm code we will now die() if
+ the eval() was unsuccessful, rather than continuing blindly on and
+ dying mysteriously later.
+
+ - Added a 'retest' action that lets users run the current regression
+ tests on a previously-installed version of a distribution.
+
+ * Instead of storing an entire dump of the Config.pm hash in the
+ _build/ directory upon startup, we now just store any overrides the
+ user or author has specified. Note that if you were doing anything
+ you weren't supposed to be doing, like poking around in the
+ internals of $buld->{config}, your code might break, so I've put
+ the asterisk of incompatibility on this one just to cover my
+ tuchus. [Idea originally by Randy Sims]
+
+ - Made copying files via copy_if_modified() a little less chatty.
+
0.2805 Sat Jul 29 22:01:24 CDT 2006
- We now embed a copy of version.pm right in the
=head1 AUTHOR
-Ken Williams <ken@cpan.org>
+Ken Williams <kwilliams@cpan.org>
=head1 COPYRIGHT
-Copyright (c) 2001-2005 Ken Williams. All rights reserved.
+Copyright (c) 2001-2006 Ken Williams. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
--- /dev/null
+package Module::Build::Config;
+
+use strict;
+use Config;
+
+sub new {
+ my ($pack, %args) = @_;
+ return bless {
+ stack => {},
+ values => $args{values} || {},
+ }, $pack;
+}
+
+sub get {
+ my ($self, $key) = @_;
+ return $self->{values}{$key} if ref($self) && exists $self->{values}{$key};
+ return $Config{$key};
+}
+
+sub set {
+ my ($self, $key, $val) = @_;
+ $self->{values}{$key} = $val;
+}
+
+sub push {
+ my ($self, $key, $val) = @_;
+ push @{$self->{stack}{$key}}, $self->{values}{$key}
+ if exists $self->{values}{$key};
+ $self->{values}{$key} = $val;
+}
+
+sub pop {
+ my ($self, $key) = @_;
+
+ my $val = delete $self->{values}{$key};
+ if ( exists $self->{stack}{$key} ) {
+ $self->{values}{$key} = pop @{$self->{stack}{$key}};
+ delete $self->{stack}{$key} unless @{$self->{stack}{$key}};
+ }
+
+ return $val;
+}
+
+sub values_set {
+ my $self = shift;
+ return undef unless ref($self);
+ return $self->{values};
+}
+
+sub all_config {
+ my $self = shift;
+ my $v = ref($self) ? $self->{values} : {};
+ return {%Config, %$v};
+}
+
+1;
=head1 AUTHOR
-Ken Williams <ken@cpan.org>
+Ken Williams <kwilliams@cpan.org>
=head1 COPYRIGHT
-Copyright (c) 2001-2005 Ken Williams. All rights reserved.
+Copyright (c) 2001-2006 Ken Williams. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
my $fh = IO::File->new( $filename )
or die( "Can't open '$filename': $!" );
+ $self->_parse_fh($fh);
+}
+
+sub _parse_fh {
+ my ($self, $fh) = @_;
+
my( $in_pod, $seen_end, $need_vers ) = ( 0, 0, 0 );
my( @pkgs, %vers, %pod, @pod );
my $pkg = 'main';
push( @pkgs, $vers_pkg ) unless grep( $vers_pkg eq $_, @pkgs );
$need_vers = 0 if $vers_pkg eq $pkg;
- my $v =
- $self->_evaluate_version_line( $vers_sig, $vers_fullname, $line );
unless ( defined $vers{$vers_pkg} && length $vers{$vers_pkg} ) {
- $vers{$vers_pkg} = $v;
+ $vers{$vers_pkg} =
+ $self->_evaluate_version_line( $vers_sig, $vers_fullname, $line );
} else {
- warn <<"EOM";
-Package '$vers_pkg' already declared with version '$vers{$vers_pkg}'
-ignoring new version '$v'.
+ # Warn unless the user is using the "$VERSION = eval
+ # $VERSION" idiom (though there are probably other idioms
+ # that we should watch out for...)
+ warn <<"EOM" unless $line =~ /=\s*eval/;
+Package '$vers_pkg' already declared with version '$vers{$vers_pkg}',
+ignoring subsequent declaration.
EOM
}
=head1 AUTHOR
-Ken Williams <ken@cpan.org>, Randy W. Sims <RandyS@ThePierianSpring.org>
+Ken Williams <kwilliams@cpan.org>, Randy W. Sims <RandyS@ThePierianSpring.org>
=head1 COPYRIGHT
-Copyright (c) 2001-2005 Ken Williams. All rights reserved.
+Copyright (c) 2001-2006 Ken Williams. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
=head1 AUTHOR
-Dave Rolsky <autarch@urth.org>, Ken Williams <ken@cpan.org>
+Dave Rolsky <autarch@urth.org>, Ken Williams <kwilliams@cpan.org>
=head1 COPYRIGHT
-Copyright (c) 2001-2005 Ken Williams. All rights reserved.
+Copyright (c) 2001-2006 Ken Williams. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
=head1 AUTHOR
-Ken Williams <ken@cpan.org>
+Ken Williams <kwilliams@cpan.org>
=head1 SEE ALSO
=head1 AUTHOR
-Ken Williams <ken@cpan.org>
+Ken Williams <kwilliams@cpan.org>
=head1 SEE ALSO
=head1 AUTHOR
-Ken Williams <ken@cpan.org>
+Ken Williams <kwilliams@cpan.org>
=head1 SEE ALSO
=head1 AUTHOR
-Ken Williams <ken@cpan.org>
+Ken Williams <kwilliams@cpan.org>
=head1 SEE ALSO
my $self = $class->SUPER::new(@_);
# $Config{sitelib} and $Config{sitearch} are, unfortunately, missing.
- $self->{config}{sitelib} ||= $self->{config}{installsitelib};
- $self->{config}{sitearch} ||= $self->{config}{installsitearch};
+ foreach ('sitelib', 'sitearch') {
+ $self->config($_ => $self->config("install$_"))
+ unless $self->config($_);
+ }
# For some reason $Config{startperl} is filled with a bunch of crap.
- $self->{config}{startperl} =~ s/.*Exit \{Status\}\s//;
+ (my $sp = $self->config('startperl')) =~ s/.*Exit \{Status\}\s//;
+ $self->config(startperl => $sp);
return $self;
}
=head1 AUTHOR
-Ken Williams <ken@cpan.org>
+Ken Williams <kwilliams@cpan.org>
=head1 SEE ALSO
=head1 AUTHOR
-Ken Williams <ken@cpan.org>
+Ken Williams <kwilliams@cpan.org>
=head1 SEE ALSO
=over 4
-=item new
+=item _set_defaults
Change $self->{build_script} to 'Build.com' so @Build works.
=cut
-sub new {
- my $class = shift;
- my $self = $class->SUPER::new(@_);
+sub _set_defaults {
+ my $self = shift;
+ $self->SUPER::_set_defaults(@_);
$self->{properties}{build_script} = 'Build.com';
-
- return $self;
}
}
else {
my($path_vol, $path_dirs) = File::Spec->splitpath( $path );
- my $vms_prefix = $self->config->{vms_prefix};
+ my $vms_prefix = $self->config('vms_prefix');
if( $path_vol eq $vms_prefix.':' ) {
$self->log_verbose(" $vms_prefix: seen\n");
return $path;
}
+=item _quote_args
+
+Command-line arguments (but not the command itself) must be quoted
+to ensure case preservation.
+
+=cut
sub _quote_args {
# Returns a string that can become [part of] a command line with
- # proper quoting so that the subprocess sees this same list of args.
+ # proper quoting so that the subprocess sees this same list of args,
+ # or if we get a single arg that is an array reference, quote the
+ # elements of it and return the reference.
my ($self, @args) = @_;
-
- my $return_args = '';
- for (@args) {
- $return_args .= q( ").$_.q(") if !/^\"/ && length($_) > 0;
- }
- return $return_args;
+ my $got_arrayref = (scalar(@args) == 1
+ && UNIVERSAL::isa($args[0], 'ARRAY'))
+ ? 1
+ : 0;
+
+ map { $_ = q(").$_.q(") if !/^\"/ && length($_) > 0 }
+ ($got_arrayref ? @{$args[0]}
+ : @args
+ );
+
+ return $got_arrayref ? $args[0]
+ : join(' ', @args);
}
+=item have_forkpipe
+
+There is no native fork(), so some constructs depending on it are not
+available.
+
+=cut
+
sub have_forkpipe { 0 }
+=item _backticks
+
+Override to ensure that we quote the arguments but not the command.
+
+=cut
+
+sub _backticks {
+ # The command must not be quoted but the arguments to it must be.
+ my ($self, @cmd) = @_;
+ my $cmd = shift @cmd;
+ my $args = $self->_quote_args(@cmd);
+ return `$cmd $args`;
+}
+
+=item do_system
+
+Override to ensure that we quote the arguments but not the command.
+
+=cut
+
+sub do_system {
+ # The command must not be quoted but the arguments to it must be.
+ my ($self, @cmd) = @_;
+ $self->log_info("@cmd\n");
+ my $cmd = shift @cmd;
+ my $args = $self->_quote_args(@cmd);
+ return !system("$cmd $args");
+}
+
+=item _infer_xs_spec
+
+Inherit the standard version but tweak the library file name to be
+something Dynaloader can find.
+
+=cut
+
+sub _infer_xs_spec {
+ my $self = shift;
+ my $file = shift;
+
+ my $spec = $self->SUPER::_infer_xs_spec($file);
+
+ # Need to create with the same name as DynaLoader will load with.
+ if (defined &DynaLoader::mod2fname) {
+ my $file = DynaLoader::mod2fname([$$spec{base_name}]);
+ $$spec{lib_file} = File::Spec->catfile($$spec{archdir}, "$file.$self->{config}->{dlext}");
+ }
+
+ return $spec;
+}
+
=back
=head1 AUTHOR
-Michael G Schwern <schwern@pobox.com>, Ken Williams <ken@cpan.org>
+Michael G Schwern <schwern@pobox.com>, Ken Williams <kwilliams@cpan.org>
=head1 SEE ALSO
=head1 AUTHOR
-Ken Williams <ken@cpan.org>
+Ken Williams <kwilliams@cpan.org>
=head1 SEE ALSO
=head1 AUTHOR
-Ken Williams <ken@cpan.org>, Randy W. Sims <RandyS@ThePierianSpring.org>
+Ken Williams <kwilliams@cpan.org>, Randy W. Sims <RandyS@ThePierianSpring.org>
=head1 SEE ALSO
=head1 AUTHOR
-Ken Williams <ken@cpan.org>
+Ken Williams <kwilliams@cpan.org>
=head1 SEE ALSO
=head1 AUTHOR
-Ken Williams <ken@cpan.org>
+Ken Williams <kwilliams@cpan.org>
=head1 SEE ALSO
=head1 AUTHOR
-Ken Williams <ken@cpan.org>
+Ken Williams <kwilliams@cpan.org>
=head1 SEE ALSO
# but we eval them in reverse order since version depends on
# version::vpp to already exist
- eval $vpp;
+ eval $vpp; die $@ if $@;
$INC{'version/vpp.pm'} = 'inside Module::Build::Version';
- eval $version;
+ eval $version; die $@ if $@;
$INC{'version.pm'} = 'inside Module::Build::Version';
}
use Scalar::Util;
use vars qw ($VERSION @ISA @REGEXS);
-$VERSION = 0.661;
+$VERSION = 0.67;
push @REGEXS, qr/
^v? # optional leading 'v'
$value = $tvalue;
}
}
+
+ # exponential notation
+ if ( $value =~ /\d+e-?\d+/ ) {
+ $value = sprintf("%.9f",$value);
+ $value =~ s/(0+)$//;
+ }
# This is not very efficient, but it is morally equivalent
# to the XS code (as that is the reference implementation).
sub qv {
my ($value) = @_;
- if ( $value =~ /\d+e-?\d+/ ) { # exponential notation
- $value = sprintf("%.9f",$value);
- $value =~ s/(0+)//;
- }
-
my $eval = eval 'Scalar::Util::isvstring($value)';
if ( !$@ and $eval ) {
$value = sprintf("v%vd",$value);
}
if ( defined $req ) {
- if ( $req =~ /\d+e-?\d+/ ) { # exponential notation
- $req = sprintf("%.9f",$req);
- $req =~ s/(0+)$//;
- }
unless ( defined $version ) {
my $msg = "$class does not define ".
"\$$class\::VERSION--version check failed";
use strict;
use lib $ENV{PERL_CORE} ? '../lib/Module/Build/t/lib' : 't/lib';
-use MBTest tests => 55;
+use MBTest tests => 49;
use Cwd ();
my $cwd = Cwd::cwd;
is $@, '';
my $mb = Module::Build->resume;
+ ok $mb->valid_property('config');
+
is $mb->config('cc'), $Config{cc};
is $mb->config('foocakes'), 'barcakes';
is $mb->args('any'), 'hey';
is $mb->args('dee'), 'goo';
is $mb->destdir, 'yo';
- is $mb->runtime_params('destdir'), 'yo';
- is $mb->runtime_params('verbose'), '1';
- ok ! $mb->runtime_params('license');
- ok my %runtime = $mb->runtime_params;
- is scalar keys %runtime, 4;
- is $runtime{destdir}, 'yo';
- is $runtime{verbose}, '1';
- ok $runtime{config};
+ my %runtime = $mb->runtime_params;
+ is_deeply \%runtime,
+ {
+ verbose => 1,
+ destdir => 'yo',
+ use_rcfile => 0,
+ config => { foocakes => 'barcakes' },
+ };
ok my $argsref = $mb->args;
is $argsref->{foo}, 1;
{
# Make sure run_perl_script() propagates @INC
- local @INC = ('whosiewhatzit', @INC);
+ my $dir = 'whosiewhatzit';
+ mkdir $dir, 0777;
+ local @INC = ($dir, @INC);
my $output = stdout_of( sub { Module::Build->run_perl_script('', ['-le', 'print for @INC']) } );
- like $output, qr{^whosiewhatzit}m;
+ like $output, qr{^$dir}m;
+ rmdir $dir;
}
##################################################################
eval{ $mb->y_n('Prompt?', 'invalid default') };
like $@, qr/Invalid default/, "y_n() requires a default of 'y' or 'n'";
- SKIP:{
- skip "No available STDIN", 7 unless -t STDIN;
+ $ENV{PERL_MM_USE_DEFAULT} = 1;
- $ENV{PERL_MM_USE_DEFAULT} = 1;
+ eval{ $mb->y_n('Is this a question?') };
+ like $@, qr/ERROR:/,
+ 'Do not allow default-less y_n() for unattended builds';
- eval{ $mb->y_n("# Is this a question?") };
- like $@, qr/ERROR:/, 'Do not allow default-less y_n() for unattended builds';
+ eval{ $ans = $mb->prompt('Is this a question?') };
+ like $@, qr/ERROR:/,
+ 'Do not allow default-less prompt() for unattended builds';
- eval{ $ans = $mb->prompt('# Is this a question?') };
- like $@, qr/ERROR:/, 'Do not allow default-less prompt() for unattended builds';
+
+ # When running Test::Smoke under a cron job, STDIN will be closed which
+ # will fool our _is_interactive() method causing various failures.
+ {
+ local *{Module::Build::_is_interactive} = sub { 1 };
$ENV{PERL_MM_USE_DEFAULT} = 0;
- $ans = $mb->prompt('# Is this a question?');
+ $ans = $mb->prompt('Is this a question?');
print "\n"; # fake <enter> after input
is $ans, 'y', "prompt() doesn't require default for interactive builds";
- $ans = $mb->y_n('# Say yes');
+ $ans = $mb->y_n('Say yes');
print "\n"; # fake <enter> after input
ok $ans, "y_n() doesn't require default for interactive build";
# Test Defaults
*{Module::Build::_readline} = sub { '' };
- $ans = $mb->prompt("# Is this a question");
+ $ans = $mb->prompt("Is this a question");
is $ans, '', "default for prompt() without a default is ''";
- $ans = $mb->prompt("# Is this a question", 'y');
+ $ans = $mb->prompt("Is this a question", 'y');
is $ans, 'y', " prompt() with a default";
- $ans = $mb->y_n("# Is this a question", 'y');
+ $ans = $mb->y_n("Is this a question", 'y');
ok $ans, " y_n() with a default";
}
+
}
# cleanup
use strict;
use lib $ENV{PERL_CORE} ? '../lib/Module/Build/t/lib' : 't/lib';
-use MBTest tests => 43;
+use MBTest tests => 47;
use Cwd ();
my $cwd = Cwd::cwd;
'Foo::Bar' => { file => 'lib/Simple.pm',
version => '1.23' }});
+{
+ $dist->change_file( 'lib/Simple.pm', <<'---' );
+package Simple;
+$VERSION = version->new('0.60.' . qw$Revision: 128 $[1]);
+package Simple::Simon;
+$VERSION = version->new('0.61.' . qw$Revision: 129 $[1]);
+---
+ $dist->regen;
+ my $provides = new_build()->prepare_metadata()->{provides};
+ is $provides->{'Simple'}{version}, 'v0.60.128', "Check version";
+ is $provides->{'Simple::Simon'}{version}, 'v0.61.129', "Check version";
+ is ref($provides->{'Simple'}{version}), '', "Versions from prepare_metadata() aren't refs";
+ is ref($provides->{'Simple::Simon'}{version}), '', "Versions from prepare_metadata() aren't refs";
+}
+
# Single file with multiple differing packages, no corresponding package
# Simple.pm => Foo
use strict;
use lib $ENV{PERL_CORE} ? '../lib/Module/Build/t/lib' : 't/lib';
-use MBTest tests => 75;
+use MBTest tests => 81;
use Cwd ();
my $cwd = Cwd::cwd;
package Simple;
use version; our $VERSION = qv('1.230');
---
-
+ <<'---', # Two version assignments, should ignore second one
+ $Simple::VERSION = '1.230';
+ $Simple::VERSION = eval $Simple::VERSION;
+---
);
my( $i, $n ) = ( 1, scalar( @modules ) );
{
- # examine properties of a module: name, pod, etc
+ # Make sure processing stops after __DATA__
$dist->change_file( 'lib/Simple.pm', <<'---' );
package Simple;
$VERSION = '0.01';
is_deeply(\@packages, ['Simple']);
}
+{
+ # Make sure we handle version.pm $VERSIONs well
+ $dist->change_file( 'lib/Simple.pm', <<'---' );
+package Simple;
+$VERSION = version->new('0.60.' . qw$Revision: 128 $[1]);
+package Simple::Simon;
+$VERSION = version->new('0.61.' . qw$Revision: 129 $[1]);
+---
+ $dist->regen;
+
+ $pm_info = Module::Build::ModuleInfo->new_from_file('lib/Simple.pm');
+ is( $pm_info->name, 'Simple', 'found default package' );
+ is( $pm_info->version, 'v0.60.128', 'version for default package' );
+ my @packages = $pm_info->packages_inside;
+ is_deeply([sort @packages], ['Simple', 'Simple::Simon']);
+ is( $pm_info->version('Simple::Simon'), 'v0.61.129', 'version for embedded package' );
+}
+
# cleanup
chdir( $cwd ) or die "Can't chdir to '$cwd': $!";
eval {$mb->dispatch('clean')};
is $@, '';
+
$mb->create_build_script;
- ok -e 'Build';
+ my $script = $mb->build_script;
+ ok -e $script;
- eval {$mb->run_perl_script('Build')};
+ eval {$mb->run_perl_script($script)};
is $@, '';
}
skip( "skipping a Unixish-only tests", 1 )
unless $mb->os_type eq 'Unix';
- local $mb->{config}{ld} = "FOO=BAR $mb->{config}{ld}";
+ $mb->{config}->push(ld => "FOO=BAR ".$mb->config('ld'));
eval {$mb->dispatch('build')};
is $@, '';
+ $mb->{config}->pop('ld');
}
eval {$mb->dispatch('realclean')};