lib/Module/Build/ConfigData.pm Module::Build
lib/Module/Build/Config.pm Module::Build
lib/Module/Build/Cookbook.pm Module::Build
+lib/Module/Build/Dumper.pm Module::Build
lib/Module/Build/ModuleInfo.pm Module::Build
lib/Module/Build/Notes.pm Module::Build
lib/Module/Build/Platform/aix.pm Module::Build
lifetime of that command. Per-action command line parameters take
precedence over parameters specified at C<perl Build.PL> time.
-The build process also relies heavily on the C<Config.pm> module, and
-all the key=value pairs in C<Config.pm> are available in
-
-C<< $self->{config} >>. If the user wishes to override any of the
+The build process also relies heavily on the C<Config.pm> module.
+If the user wishes to override any of the
values in C<Config.pm>, she may specify them like so:
perl Build.PL --config cc=gcc --config ld=gcc
[version 0.28]
This action is identical to the C<install> action. In the future,
-though, if C<install> starts writing to the file file
+though, when C<install> starts writing to the file
F<$(INSTALLARCHLIB)/perllocal.pod>, C<pure_install> won't, and that
will be the only difference between them.
This method returns a reasonable facsimile of the currently-executing
C<Module::Build> object representing the current build. You can use
-this object to query its C<notes()> method, inquire about installed
+this object to query its L</notes()> method, inquire about installed
modules, and so on. This is a great way to share information between
different parts of your build process. For instance, you can ask
the user a question during C<perl Build.PL>, then use their answer
Creates a new Module::Build object. Arguments to the new() method are
listed below. Most arguments are optional, but you must provide
-either the C<module_name> argument, or C<dist_name> and one of
-C<dist_version> or C<dist_version_from>. In other words, you must
+either the L</module_name> argument, or L</dist_name> and one of
+L</dist_version> or L</dist_version_from>. In other words, you must
provide enough information to determine both a distribution name and
version.
[version 0.19]
An array reference of files to be cleaned up when the C<clean> action
-is performed. See also the add_to_cleanup() method.
+is performed. See also the L<add_to_cleanup()|/"add_to_cleanup(@files)">
+method.
=item auto_features
[version 0.26]
This parameter supports the setting of features (see
-L<feature($name)>) automatically based on a set of prerequisites. For
+L</feature($name)>) automatically based on a set of prerequisites. For
instance, for a module that could optionally use either MySQL or
PostgreSQL databases, you might use C<auto_features> like this:
Otherwise the failures will be displayed to the user and the feature
will be disabled (set to C<0>).
-See the documentation for L<requires> for the details of how
+See the documentation for L</requires> for the details of how
requirements can be specified.
=item autosplit
[version 0.04]
An optional C<autosplit> argument specifies a file which should be run
-through the C<Autosplit::autosplit()> function. If multiple files
-should be split, the argument may be given as an array of the files to
-split.
+through the L<AutoSplit::autosplit()|AutoSplit/autosplit> function.
+If multiple files should be split, the argument may be given as an
+array of the files to split.
In general I don't consider autosplitting a great idea, because it's
not always clear that autosplitting achieves its intended performance
[version 0.28]
-The Module::Build class or subclass to use in the build
-script. Defaults to "Module::Build" or the class name passed to or
-created by a call to C<subclass()>. This property is useful if you're
+The Module::Build class or subclass to use in the build script.
+Defaults to "Module::Build" or the class name passed to or created by
+a call to L</subclass()>. This property is useful if you're
writing a custom Module::Build subclass and have a bootstrapping
problem--that is, your subclass requires modules that may not be
installed when C<perl Build.PL> is executed, but you've listed in
-C<build_requires> so that they should be available when C<./Build> is
+L</build_requires> so that they should be available when C<./Build> is
executed.
=item build_requires
This parameter lets you use Module::Build::Compat during the
C<distdir> (or C<dist>) action to automatically create a Makefile.PL
for compatibility with ExtUtils::MakeMaker. The parameter's value
-should be one of the styles named in the Module::Build::Compat
+should be one of the styles named in the L<Module::Build::Compat>
documentation.
=item create_readme
[version 0.11]
-Specifies a version number for the distribution. See C<module_name>
-or C<dist_version_from> for ways to have this set automatically from a
+Specifies a version number for the distribution. See L</module_name>
+or L</dist_version_from> for ways to have this set automatically from a
C<$VERSION> variable in a module. One way or another, a version
number needs to be set.
[version 0.11]
Specifies a file to look for the distribution version in. Most
-authors won't need to set this directly, they can use C<module_name>
+authors won't need to set this directly, they can use L</module_name>
to set it to a reasonable default.
The version is extracted from the specified file according to the same
-rules as C<ExtUtils::MakeMaker> and C<CPAN.pm>. It involves finding
+rules as L<ExtUtils::MakeMaker> and C<CPAN.pm>. It involves finding
the first line that matches the regular expression
/([\$*])(([\w\:\']*)\bVERSION)\b.*\=/
treat it as 1 (true), because this is a safer way to behave.
Currently C<Module::Build> doesn't actually do anything with this flag
-- it's up to higher-level tools like C<CPAN.pm> to do
-something useful with it. It can potentially bring lots of security,
-packaging, and convenience improvements.
+- it's up to higher-level tools like C<CPAN.pm> to do something useful
+with it. It can potentially bring lots of security, packaging, and
+convenience improvements.
=item extra_compiler_flags
You can pass arbitrary command line options to F<Build.PL> or
F<Build>, and they will be stored in the Module::Build object and can
-be accessed via the C<args()> method. However, sometimes you want
+be accessed via the L</args()> method. However, sometimes you want
more flexibility out of your argument processing than this allows. In
such cases, use the C<get_options> parameter to pass in a hash
reference of argument specifications, and the list of arguments to
=item apache
The distribution is licensed under the Apache Software License
-(http://opensource.org/licenses/apachepl.php).
+(L<http://opensource.org/licenses/apachepl.php>).
=item artistic
The distribution is licensed under the Artistic License, as specified
-by the F<Artistic> file in the standard perl distribution.
+by the F<Artistic> file in the standard Perl distribution.
+
+=item artistic_2
+
+The distribution is licensed under the Artistic 2.0 License
+(L<http://opensource.org/licenses/artistic-license-2.0.php>.)
=item bsd
The distribution is licensed under the BSD License
-(http://www.opensource.org/licenses/bsd-license.php).
+(L<http://www.opensource.org/licenses/bsd-license.php>).
=item gpl
-The distribution is licensed under the terms of the Gnu General
-Public License (http://www.opensource.org/licenses/gpl-license.php).
+The distribution is licensed under the terms of the GNU General
+Public License (L<http://www.opensource.org/licenses/gpl-license.php>).
=item lgpl
-The distribution is licensed under the terms of the Gnu Lesser
+The distribution is licensed under the terms of the GNU Lesser
General Public License
-(http://www.opensource.org/licenses/lgpl-license.php).
+(L<http://www.opensource.org/licenses/lgpl-license.php>).
=item mit
The distribution is licensed under the MIT License
-(http://opensource.org/licenses/mit-license.php).
+(L<http://opensource.org/licenses/mit-license.php>).
=item mozilla
The distribution is licensed under the Mozilla Public
-License. (http://opensource.org/licenses/mozilla1.0.php or
-http://opensource.org/licenses/mozilla1.1.php)
+License. (L<http://opensource.org/licenses/mozilla1.0.php> or
+L<http://opensource.org/licenses/mozilla1.1.php>)
=item open_source
The distribution is licensed under some other Open Source
Initiative-approved license listed at
-http://www.opensource.org/licenses/ .
+L<http://www.opensource.org/licenses/>.
=item perl
The distribution may be copied and redistributed under the same terms
-as perl itself (this is by far the most common licensing option for
+as Perl itself (this is by far the most common licensing option for
modules on CPAN). This is a dual license, in which the user may
choose between either the GPL or the Artistic license.
during the C<distmeta> action. Any existing entries with the same
names will be overridden.
+See the L</"MODULE METADATA"> section for details.
+
=item meta_merge
[version 0.28]
C<meta_merge> will merge the supplied data into the existing hash or
array value.
+See the L</"MODULE METADATA"> section for details.
+
=item module_name
[version 0.03]
[version 0.08]
-This is just like the C<requires> argument, except that modules listed
+This is just like the L</requires> argument, except that modules listed
in this section aren't essential, just a good idea. We'll just print
a friendly warning if one of these modules aren't found, but we'll
continue running.
One note: currently C<Module::Build> doesn't actually I<require> the
user to have dependencies installed, it just strongly urges. In the
-future we may require it. There's also a C<recommends> section for
+future we may require it. There's also a L</recommends> section for
things that aren't absolutely required.
Automated tools like CPAN.pm should refuse to install a module if one
[version 0.18]
An optional parameter specifying a set of files that should be
-installed as executable perl scripts when the module is installed.
+installed as executable Perl scripts when the module is installed.
May be given as an array reference of the files, or as a hash
reference whose keys are the files (and whose values will currently be
ignored).
[version 0.16]
-If a true value is specified for this parameter, C<Module::Signature>
+If a true value is specified for this parameter, L<Module::Signature>
will be used (via the 'distsign' action) to create a SIGNATURE file
for your distribution during the 'distdir' action, and to add the
SIGNATURE file to the MANIFEST (therefore, don't add it yourself).
[version 0.28]
-Invokes the C<AutoSplit> module on the C<$from> file, sending the
+Invokes the L<AutoSplit> module on the C<$from> file, sending the
output to the C<lib/auto> directory inside C<$to>. C<$to> is
typically the C<blib/> directory.
This method returns a hash reference indicating whether a version
dependency on a certain module is satisfied. The C<$module> argument
is given as a string like C<"Data::Dumper"> or C<"perl">, and the
-C<$version> argument can take any of the forms described in L<requires>
+C<$version> argument can take any of the forms described in L</requires>
above. This allows very fine-grained version checking.
The returned hash reference has the following structure:
This method may be called either as an object method
(C<< $build->check_installed_status($module, $version) >>)
-or as a class method
+or as a class method
(C<< Module::Build->check_installed_status($module, $version) >>).
=item check_installed_version($module, $version)
[version 0.05]
-Like C<check_installed_status()>, but simply returns true or false
-depending on whether module C<$module> satisfies the dependency
-C<$version>.
+Like L<check_installed_status()|/"check_installed_status($module, $version)">,
+but simply returns true or false depending on whether module
+C<$module> satisfies the dependency C<$version>.
If the check succeeds, the return value is the actual version of
C<$module> installed on the system. This allows you to do the
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.
+has specified.
With C<$key> and C<$value> arguments, sets the value for future
callers of C<config($key)>.
With a single argument, returns the value of the configuration
variable C<$name>. With two arguments, sets the given configuration
-variable to the given value. The value may be any perl scalar that's
+variable to the given value. The value may be any Perl scalar that's
serializable with C<Data::Dumper>. For instance, if you write a
module that can use a MySQL or PostgreSQL back-end, you might create
configuration variables called C<mysql_connect> and
installation via the generated C<...::ConfigData> module, as
C<< ...::ConfigData->config($name) >>.
-The C<feature()> and C<config_data()> methods represent
+The L<feature()|/"feature($name)"> and C<config_data()> methods represent
Module::Build's main support for configuration of installed modules.
See also L<Module::Build::Authoring/"SAVING CONFIGURATION INFORMATION">.
Among the files created in C<_build/> is a F<_build/prereqs> file
containing the set of prerequisites for this distribution, as a hash
of hashes. This file may be C<eval()>-ed to obtain the authoritative
-set of prereqs, which might be different from the contents of META.yml
-(because F<Build.PL> might have set them dynamically). But fancy
-developers take heed: do not put any fancy custom runtime code in the
-F<_build/prereqs> file, leave it as a static declaration containing
-only strings and numbers. Similarly, do not alter the structure of
-the internal C<< $self->{properties}{requires} >> (etc.) data members,
-because that's where this data comes from.
+set of prereqs, which might be different from the contents of
+F<META.yml> (because F<Build.PL> might have set them dynamically).
+But fancy developers take heed: do not put any fancy custom runtime
+code in the F<_build/prereqs> file, leave it as a static declaration
+containing only strings and numbers. Similarly, do not alter the
+structure of the internal C<< $self->{properties}{requires} >> (etc.)
+data members, because that's where this data comes from.
=item current_action()
action has completed, current_action() will again return "test".
If you need to know the name of the original action invoked by the
-user, see L<invoked_action()> below.
+user, see L</invoked_action()> below.
=item depends_on(@actions)
better or worse (perhaps better!) we were still thinking in
C<make>-like dependency terms when we created this method.
-See also C<dispatch()>. The main distinction between the two is that
-C<depends_on()> is meant to call an action from inside another action,
-whereas C<dispatch()> is meant to set the very top action in motion.
+See also L<dispatch()|/"dispatch($action, %args)">. The main
+distinction between the two is that C<depends_on()> is meant to call
+an action from inside another action, whereas C<dispatch()> is meant
+to set the very top action in motion.
=item dir_contains($first_dir, $second_dir)
actions, e.g. by applications controlling Module::Build-based builds
rather than by subclasses.
-See also C<depends_on()>. The main distinction between the two is that
-C<depends_on()> is meant to call an action from inside another action,
-whereas C<dispatch()> is meant to set the very top action in motion.
+See also L<depends_on()|/"depends_on(@actions)">. The main
+distinction between the two is that C<depends_on()> is meant to call
+an action from inside another action, whereas C<dispatch()> is meant
+to set the very top action in motion.
=item dist_dir()
Features set in this way using the Module::Build object will be
available for querying during the build/test process and after
-installation via the generated C<...::ConfigData> module, as
+installation via the generated C<...::ConfigData> module, as
C<< ...::ConfigData->feature($name) >>.
The C<feature()> and C<config_data()> methods represent
[version 0.28]
Returns the directory in which items of type C<$type> (e.g. C<lib>,
-C<arch>, C<bin>, or anything else returned by the C<install_types()>
+C<arch>, C<bin>, or anything else returned by the L</install_types()>
method) will be installed during the C<install> action. Any settings
for C<install_path>, C<install_base>, and C<prefix> are taken into
account when determining the return value.
This is the name of the original action invoked by the user. This
value is set when the user invokes F<Build.PL>, the F<Build> script,
-or programatically through the L<dispatch()> method. It does not
-change as sub-actions are executed as dependencies are evaluated.
+or programatically through the L<dispatch()|/"dispatch($action, %args)">
+method. It does not change as sub-actions are executed as
+dependencies are evaluated.
To get the name of the currently executing dependency, see
-L<current_action()> above.
+L</current_action()> above.
=item notes()
# All the *.pm files in lib/
$m->rscan_dir('lib', qr/\.pm$/)
-
+
# All the files in blib/ that aren't *.html files
$m->rscan_dir('blib', sub {-f $_ and not /\.html$/});
=item config_dir()
+=item configure_requires()
+
=item conflicts()
=item create_makefile_pl()
=back
+=head1 MODULE METADATA
+
+If you would like to add other useful metadata, C<Module::Build>
+supports this with the C<meta_add> and C<meta_merge> arguments to
+L</new>. The authoritative list of supported metadata can be found at
+L<http://module-build.sourceforge.net/META-spec-current.html>, but for
+convenience - here are a few of the more useful ones:
+
+=over 4
+
+=item keywords
+
+For describing the distribution using keyword (or "tags") in order to
+make CPAN.org indexing and search more efficient and useful.
+
+See L<http://module-build.sourceforge.net/META-spec-current.html#keywords>.
+
+=item resources
+
+A list of additional resources available for users of the
+distribution. This can include links to a homepage on the web, a
+bugtracker, the repository location, a even subscription page for the
+distribution mailing list.
+
+See L<http://module-build.sourceforge.net/META-spec-current.html#resources>.
+
+=back
+
+
=head1 AUTHOR
Ken Williams <kwilliams@cpan.org>
=head1 PREREQUISITES
-There are three basic types of prerequisites that can be defined: 1)
-"requires" - are versions of modules that are required for certain
-functionality to be available; 2) "recommends" - are versions of
-modules that are recommended to provide enhanced functionality; and 3)
-"conflicts" - are versions of modules that conflict with, and that can
-cause problems with the distribution.
+=head2 Types of prerequisites
-Each of the three types of prerequisites listed above can be applied
-to different aspects of the Build process. For the module distribution
-itself you simply define "requires", "recommends", or "conflicts". The
-types can also apply to other aspects of the Build process. Currently,
-only "build_requires" is defined which is used for modules which are
-required during the Build process.
+To specify what versions of other modules are used by this
+distribution, several types of prerequisites can be defined with the
+following parameters:
+=over 3
+
+=item configure_requires
+
+Items that must be installed I<before> configuring this distribution
+(i.e. before running the F<Build.PL> script). This might be a
+specific minimum version of C<Module::Build> or any other module the
+F<Build.PL> needs in order to do its stuff. Clients like C<CPAN.pm>
+or C<CPANPLUS> will be expected to pick C<configure_requires> out of the
+F<META.yml> file and install these items before running the
+C<Build.PL>.
+
+*TODO* auto-add M::B? In what circumstances?
+
+=item build_requires
+
+Items that are necessary for building and testing this distribution,
+but aren't necessary after installation. This can help users who only
+want to install these items temporarily. It also helps reduce the
+size of the CPAN dependency graph if everything isn't smooshed into
+C<requires>.
+
+=item requires
+
+Items that are necessary for basic functioning.
+
+=item recommends
+
+Items that are recommended for enhanced functionality, but there are
+ways to use this distribution without having them installed. You
+might also think of this as "can use" or "is aware of" or "changes
+behavior in the presence of".
+
+=item conflicts
+
+Items that can cause problems with this distribution when installed.
+This is pretty rare.
+
+=back
=head2 Format of prerequisites
perl => '5.6.0'
},
-These four version specifiers have different effects. The value
+The above four version specifiers have different effects. The value
C<'2.4'> means that B<at least> version 2.4 of C<Foo::Module> must be
installed. The value C<0> means that B<any> version of C<Bar::Module>
is acceptable, even if C<Bar::Module> doesn't define a version. The
dependency-checking semantics are available, except that we also
understand perl's new double-dotted version numbers.
+=head2 XS Extensions
+
+Modules which need to compile XS code should list C<ExtUtils::CBuilder>
+as a C<build_requires> element.
+
=head1 SAVING CONFIGURATION INFORMATION
part).
These days, C<h2xs> has largely been superseded by modules like
-C<ExtUtils::ModuleMaker>, C<Module::Starter>, and C<Module::Maker>.
-They have varying degrees of support for C<Module::Build>.
+C<ExtUtils::ModuleMaker>, and C<Module::Starter>. They have varying
+degrees of support for C<Module::Build>.
=head1 AUTOMATION
package Module::Build::Base;
use strict;
+use vars qw($VERSION);
+$VERSION = '0.2808_01';
+$VERSION = eval $VERSION;
BEGIN { require 5.00503 }
use Carp;
-use Config;
use File::Copy ();
use File::Find ();
use File::Path ();
use File::Basename ();
use File::Spec 0.82 ();
use File::Compare ();
-use Data::Dumper ();
+use Module::Build::Dumper ();
use IO::File ();
use Text::ParseWords ();
die "Too early to specify a build action '$self->{action}'. Do 'Build $self->{action}' instead.\n"
if $self->{action} && $self->{action} ne 'Build_PL';
- $self->dist_name;
- $self->dist_version;
-
$self->check_manifest;
$self->check_prereq;
$self->check_autofeatures;
+ $self->dist_name;
+ $self->dist_version;
+
$self->_set_install_paths;
$self->_find_nested_builds;
return $self->_backticks(@cmd) eq Config->myconfig;
}
+# cache _discover_perl_interpreter() results
+{
+ my $known_perl;
+ sub find_perl_interpreter {
+ my $self = shift;
+
+ return $known_perl if defined($known_perl);
+ return $known_perl = $self->_discover_perl_interpreter;
+ }
+}
+
# Returns the absolute path of the perl interperter used to invoke
# this process. The path is derived from $^X or $Config{perlpath}. On
# some platforms $^X contains the complete absolute path of the
# executable extension on platforms that use one. It's a fatal error
# if the interpreter can't be found because it can result in undefined
# behavior by routines that depend on it (generating errors or
-# invoking the wrong perl.
-sub find_perl_interpreter {
+# invoking the wrong perl.)
+sub _discover_perl_interpreter {
my $proto = shift;
my $c = ref($proto) ? $proto->{config} : 'Module::Build::Config';
} else {
- # Try 3.B, First look in $Config{perlpath}, then search the users
+ # Try 3.B, First look in $Config{perlpath}, then search the user's
# PATH. We do not want to do either if we are running from an
# uninstalled perl in a perl source tree.
my $exe = $c->get('exe_ext');
foreach my $thisperl ( @potential_perls ) {
- if (defined $exe and $proto->os_type ne 'VMS') {
+ if (defined $exe) {
$thisperl .= $exe unless $thisperl =~ m/$exe$/i;
}
return wantarray ? %features : \%features;
}
-BEGIN { *feature = \&features }
+BEGIN { *feature = \&features } # Alias
sub _mb_feature {
my $self = shift;
meta_merge
original_prefix
prefix_relpaths
+ configure_requires
);
__PACKAGE__->add_property($_) for qw(
die ("Can't determine distribution version, must supply either 'dist_version',\n".
"'dist_version_from', or 'module_name' parameter")
- unless $p->{dist_version};
+ unless defined $p->{dist_version};
return $p->{dist_version};
}
my $file = $self->config_file($filename);
my $fh = IO::File->new("> $file") or die "Can't create '$file': $!";
- local $Data::Dumper::Terse = 1;
- print $fh ref($data) ? Data::Dumper::Dumper($data) : $data;
+ unless (ref($data)) { # e.g. magicnum
+ print $fh $data;
+ return;
+ }
+
+ print {$fh} Module::Build::Dumper->_data_dump($data);
}
sub write_config {
sub perl_version_to_float {
my ($self, $version) = @_;
+ return $version if grep( /\./, $version ) < 2;
$version =~ s/\./../;
$version =~ s/\.(\d+)/sprintf '%03d', $1/eg;
return $version;
}
$status{have} = $pm_info->version();
- if ($spec and !$status{have}) {
+ if ($spec and !defined($status{have})) {
@status{ qw(have message) } = (undef, "Couldn't find a \$VERSION in prerequisite $modname");
return \%status;
}
my $case_tolerant = 0+(File::Spec->can('case_tolerant')
&& File::Spec->case_tolerant);
$q{base_dir} = uc $q{base_dir} if $case_tolerant;
- $q{base_dir} = Win32::GetShortPathName($q{base_dir}) if $^O eq 'MSWin32';
+ $q{base_dir} = Win32::GetShortPathName($q{base_dir}) if $self->is_windowsish;
$q{magic_numfile} = $self->config_file('magicnum');
return \%args, $action;
}
-
-# (bash shell won't expand tildes mid-word: "--foo=~/thing")
-# TODO: handle ~user/foo
-sub _detildefy {
- my ($self, $arg) = @_;
-
- return $arg =~ /^~/ ? (glob $arg)[0] : $arg;
-}
+# Default: do nothing. Overridden for Unix & Windows.
+sub _detildefy {}
# merge Module::Build argument lists that have already been parsed
my $vspace = q{ } x ($ver_len - length $mod->{need});
my $f = $mod->{ok} ? ' ' : '!';
$output .=
- " $f $mod->{name} $space $mod->{need} $vspace $mod->{have}\n";
+ " $f $mod->{name} $space $mod->{need} $vspace ".
+ (defined($mod->{have}) ? $mod->{have} : "")."\n";
}
}
return $output;
while (my ($file, $to) = each %$files) {
unless ($self->up_to_date( $file, $to )) {
- $self->run_perl_script($file, [], [@$to]);
+ $self->run_perl_script($file, [], [@$to]) or die "$file failed";
$self->add_to_cleanup(@$to);
}
}
File::Spec->abs2rel( File::Spec->rel2abs( $file ),
File::Spec->rel2abs( $dir ) );
my $to_file =
- File::Spec->catfile( $ppm, 'blib',
+ File::Spec->catdir( $ppm, 'blib',
exists( $types{$type} ) ? $types{$type} : $type,
$rel_file );
$self->copy_if_modified( from => $file, to => $to_file );
# create a tarball;
# the directory tar'ed must be blib so we need to do a chdir first
- my $start_wd = $self->cwd;
- chdir( $ppm ) or die "Can't chdir to $ppm";
- $self->make_tarball( 'blib', File::Spec->catfile( $start_wd, $ppm ) );
- chdir( $start_wd ) or die "Can't chdir to $start_wd";
+ my $target = File::Spec->catfile( File::Spec->updir, $ppm );
+ $self->_do_in_dir( $ppm, sub { $self->make_tarball( 'blib', $target ) } );
$self->depends_on( 'ppd' );
$self->_add_to_manifest($manifest, "SIGNATURE Added here by Module::Build");
}
- # We protect the signing with an eval{} to make sure we get back to
- # the right directory after a signature failure. Would be nice if
- # Module::Signature took a directory argument.
+ # Would be nice if Module::Signature took a directory argument.
+ $self->_do_in_dir($dir, sub {local $Module::Signature::Quiet = 1; Module::Signature::sign()});
+}
+
+sub _do_in_dir {
+ my ($self, $dir, $do) = @_;
+
my $start_dir = $self->cwd;
chdir $dir or die "Can't chdir() to $dir: $!";
- eval {local $Module::Signature::Quiet = 1; Module::Signature::sign()};
+ eval {$do->()};
my @err = $@ ? ($@) : ();
chdir $start_dir or push @err, "Can't chdir() back to $start_dir: $!";
die join "\n", @err if @err;
$self->depends_on('distdir');
- my $start_dir = $self->cwd;
- my $dist_dir = $self->dist_dir;
- chdir $dist_dir or die "Cannot chdir to $dist_dir: $!";
- # XXX could be different names for scripts
+ $self->_do_in_dir
+ ( $self->dist_dir,
+ sub {
+ # XXX could be different names for scripts
- $self->run_perl_script('Build.PL') # XXX Should this be run w/ --nouse-rcfile
- or die "Error executing 'Build.PL' in dist directory: $!";
- $self->run_perl_script('Build')
- or die "Error executing 'Build' in dist directory: $!";
- $self->run_perl_script('Build', [], ['test'])
- or die "Error executing 'Build test' in dist directory";
- chdir $start_dir;
+ $self->run_perl_script('Build.PL') # XXX Should this be run w/ --nouse-rcfile
+ or die "Error executing 'Build.PL' in dist directory: $!";
+ $self->run_perl_script('Build')
+ or die "Error executing 'Build' in dist directory: $!";
+ $self->run_perl_script('Build', [], ['test'])
+ or die "Error executing 'Build test' in dist directory";
+ });
}
sub _write_default_maniskip {
return $_ = {$_ => 1};
}
- return $_ = { map {$_,1} $self->_files_in( File::Spec->catdir( $self->base_dir, 'bin' ) ) };
+ return $_ = { map {$_,1} $self->_files_in('bin') };
}
BEGIN { *scripts = \&script_files; }
{
- my %licenses =
- (
- perl => 'http://dev.perl.org/licenses/',
- gpl => 'http://www.opensource.org/licenses/gpl-license.php',
- apache => 'http://apache.org/licenses/LICENSE-2.0',
- artistic => 'http://opensource.org/licenses/artistic-license.php',
- lgpl => 'http://opensource.org/licenses/artistic-license.php',
- bsd => 'http://www.opensource.org/licenses/bsd-license.php',
- gpl => 'http://www.opensource.org/licenses/gpl-license.php',
- mit => 'http://opensource.org/licenses/mit-license.php',
- mozilla => 'http://opensource.org/licenses/mozilla1.1.php',
- open_source => undef,
- unrestricted => undef,
- restrictive => undef,
- unknown => undef,
- );
+ my %licenses = (
+ perl => 'http://dev.perl.org/licenses/',
+ apache => 'http://apache.org/licenses/LICENSE-2.0',
+ artistic => 'http://opensource.org/licenses/artistic-license.php',
+ artistic_2 => 'http://opensource.org/licenses/artistic-license-2.0.php',
+ lgpl => 'http://opensource.org/licenses/lgpl-license.php',
+ bsd => 'http://opensource.org/licenses/bsd-license.php',
+ gpl => 'http://opensource.org/licenses/gpl-license.php',
+ mit => 'http://opensource.org/licenses/mit-license.php',
+ mozilla => 'http://opensource.org/licenses/mozilla1.1.php',
+ open_source => undef,
+ unrestricted => undef,
+ restrictive => undef,
+ unknown => undef,
+ );
sub valid_licenses {
return \%licenses;
}
$node->{resources}{license} = $url;
}
- foreach ( @{$self->prereq_action_types} ) {
+ if (exists $p->{configure_requires}) {
+ foreach my $spec (keys %{$p->{configure_requires}}) {
+ warn ("Warning: $spec is listed in 'configure_requires', but ".
+ "it is not found in any of the other prereq fields.\n")
+ unless grep exists $p->{$_}{$spec},
+ grep !/conflicts$/, @{$self->prereq_action_types};
+ }
+ }
+
+ foreach ( 'configure_requires', @{$self->prereq_action_types} ) {
if (exists $p->{$_} and keys %{ $p->{$_} }) {
$add_node->($_, $p->{$_});
}
Revision history for Perl extension Module::Build.
+ - All .pm files in the Module-Build distribution (except for
+ M::B::Version.pm, which is kind of tied to version.pm) now have the
+ same $VERSION number explicitly specified.
+
+ - When checking prerequisites, the required version of perl is now
+ checked before we start finding the $VERSION declaration of the
+ distribution, which results in much more intuitive error messages
+ e.g. if the author is using 5.6-isms in their declaration but the
+ user doesn't have 5.6. [Slaven Rezic]
+
+ - Added 'artistic_2' license, corrected 'lgpl' license url (bug #29783)
+ [David Thomas]
+
+ - VMS find_perl_interpreter() is just $^X (bug #29810) [Craig A. Berry]
+
+ - Some large VMS fixes, mostly having to do with the non-case-
+ preserving nature of most VMS filesystems, but also correcting for
+ illegal characters in VMS file specs. [John E. Malmberg and Craig
+ A. Berry]
+
+ - Fixed the _detildefy() method on VMS. [John E. Malmberg and Craig
+ A. Berry]
+
+ - We now use a much more reliable method when Data::Dumper-ing saved
+ state data. [Yves]
+
+ - When a module had 0.000 as its version, a few places in the code
+ thought the module had no version at all. This is now
+ fixed. [Andrew "Zefram" Main]
+
+ - When finding the default set of script_files, we now compute them
+ as relative paths, not absolute. [Spotted by Curtis "Ovid" Poe]
+
+ - Got rid of a call to eliminate_macros, which isn't needed in
+ Module::Build since there is no external make utility involved.
+ Override expand_test_dir to make up for the fact that the
+ home-grown glob() returns absolute, not relative, paths. [Craig
+ A. Berry]
+
+ - Fixed a catdir() that needed to be catfile() in the .packlist
+ creation code. [John E. Malmberg]
+
+ - If a *.PL file ended abnormally during the build, processing should
+ have stopped, but it didn't. Fixed. [Matthew Cast and David
+ Golden]
+
+ - Module::Build::Compat adds "require 5.XXXXX" to Makefile.PL when
+ 'perl' is specified as a 'requires' prerequisite [David Golden]
+
+ - Refactored t/compat.t for modularity and transparency; added
+ labels for all tests; supressed subprocess output to
+ STDOUT and STDERR [David Golden]
+
+ - Fixed bug in perl_version_to_float when version is already a float
+ [David Golden]
+
+ - Removed a mention of $build->{config} from the documentation, the
+ official interface to Config.pm settings is now via the
+ $build->config() and has been for some time. [Suggested by Michael
+ Schwern]
+
+ - Tweaked some text in the Cookbook to bring it into the modern age,
+ and added a recipe for accessing Config.pm settings. [Ibid]
+
+ - Lots of POD link/readability improvements to the Module::Build::API
+ documentation [Salve J. Nilsen]
+
+ - Added configure_requires as a new type of prereq. [Suggested by Adam
+ Kennedy]
+
+ - Patch 31156 from bleadperl: some filename dot and extension help
+ for Module::Build on VMS. [Craig Berry]
+
+ - Reworked the _detildefy() method so it doesn't depend on glob()
+ anymore. This gets rid of a problem with spaces or other special
+ shell characters in things like 'prefix' or 'install_path'
+ entries. [Prodding by Eric Wilhelm]
+
+ - Added midnightbsd to the list of Unix-like OSes we know about
+ [Rafael Garcia-Suarez]
+
+0.2808 - Sat Apr 28 12:59:43 2007
+
+ - Added is_vmsish(), is_windowsish(), and is_unixish() boolean
+ convenience functions. Fixes some test failures on platforms where
+ $^O is set to a value we don't know about (like 'gnu').
+
+ - Upgraded to version.pm 0.7203. [John Peacock]
+
+ - Support get_action_docs() =head2 style. [ewilhelm]
+
+ - Workaround Test::Pod::Coverage @INC bug. [Eric Wilhelm]
+
+ - Fixed the command-line args --extra_compiler_flags and
+ --extra_linker_flags so they properly shell-split their arguments.
+
+0.2807 - Sat Mar 24 22:19:02 2007
+
+ - Upgraded to version.pm 0.71. [John Peacock]
+
+ - Removed a couple small constructs in the tests ("use warnings;" and
+ "qw$foo bar$[1]") that caused test failures under perl 5.005.
+
+ - Added support for an explicit default value of undef in prompt().
+ [Eric Wilhelm]
+
+ - Improved our prompt() method, which could sometimes hang before the
+ user got a chance to see a prompt. [Andreas Koenig]
+
+ - Added a note about --allow_mb_mismatch to the error message that
+ happens right before someone might want to use that parameter.
+
+ - Added DragonflyBSD to the list of known Unix OSes.
+
+ - get_action_docs() dies on error rather than twiddling $@
+
+ - Made ModuleInfo's _evaluate_version_line() compatible with 'use
+ version ...$VERSION' lines. [Eric Wilhelm]
+
+ - Added some verbiage in Module::Build::API that officially blesses
+ the _build/prereqs file for external consumption. [Suggested by Andreas Koenig]
+
+ - Added test profiles support via the test_types property and "testall"
+ target. [Eric Wilhelm, Jeff Lavallee]
+
+ - Use syscopy() on OS/2 in copy_if_modified() so we make sure to
+ overwrite any existing target file. [Ilya Zakharevich]
+
+ - Removed seemingly silly '~~' test in t/tilde.t.
+
+ - In our test-time utility library t/lib/MBTest.pm, we need to know
+ about a few .exe-like extensions on OS/2. [Ilya Zakharevich]
+
+ - In t/ppm.t, use DynaLoader::mod2fname() (if available) to determine
+ the correct translation of our test module's name into a DLL
+ name. [Ilya Zakharevich]
+
+ - Avoid an unlink() error on OS/2 when fixing shebang lines. [Ilya
+ Zakharevich]
+
+ - When we're protecting the world from the evils of long RedHat
+ $ENV{PERL5LIB} variables, don't assume $ENV{PERL5LIB} is already
+ defined. This gets rid of a huge number of warnings for some
+ people. [Dave Rolsky]
+
+0.2806 - Fri Dec 15 22:20:14 2006
+
- 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.
use strict;
use vars qw($VERSION);
-$VERSION = '0.03';
+$VERSION = '0.2808_01';
use File::Spec;
use IO::File;
print {$fh} "# Note: this file was auto-generated by ", __PACKAGE__, " version $VERSION\n";
+ # Minimum perl version should be specified as "require 5.XXXXXX" in
+ # Makefile.PL
+ my $requires = $build->requires;
+ if ( my $minimum_perl = $requires->{perl} ) {
+ print {$fh} "require $minimum_perl;\n";
+ }
+
# If a *bundled* custom subclass is being used, make sure we add its
# directory to @INC.
my $subclass_load = '';
package Module::Build::Config;
use strict;
+use vars qw($VERSION);
+$VERSION = '0.2808_01';
+$VERSION = eval $VERSION;
use Config;
sub new {
=head1 DESCRIPTION
C<Module::Build> isn't conceptually very complicated, but examples are
-always helpful. I got the idea for writing this cookbook when
-attending Brian Ingerson's "Extreme Programming Tools for Module
-Authors" presentation at YAPC 2003, when he said, straightforwardly,
-"Write A Cookbook."
-
-The definitional of how stuff works is in the main C<Module::Build>
-documentation. It's best to get familiar with that too.
+always helpful. The following recipes should help developers and/or
+installers put together the pieces from the other parts of the
+documentation.
=head1 BASIC RECIPES
-=head2 The basic installation recipe for modules that use Module::Build
+=head2 Installing modules that use Module::Build
In most cases, you can just issue the following commands:
then double-click on the F<Build> script to run its C<build>, C<test>,
and C<install> actions.
-The F<Build> script knows what perl was used to run C<Build.PL>, so
+The F<Build> script knows what perl was used to run F<Build.PL>, so
you don't need to re-invoke the F<Build> script with the complete perl
path each time. If you invoke it with the I<wrong> perl path, you'll
get a warning or a fatal error.
+=head2 Modifying Config.pm values
-=head2 Making a CPAN.pm-compatible distribution
+C<Module::Build> relies heavily on various values from perl's
+C<Config.pm> to do its work. For example, default installation paths
+are given by C<installsitelib> and C<installvendorman3dir> and
+friends, C linker & compiler settings are given by C<ld>,
+C<lddlflags>, C<cc>, C<ccflags>, and so on. I<If you're pretty sure
+you know what you're doing>, you can tell C<Module::Build> to pretend
+there are different values in F<Config.pm> than what's really there,
+by passing arguments for the C<--config> parameter on the command
+line:
-New versions of CPAN.pm understand how to use a F<Build.PL> script,
-but old versions don't. If you want to help users who have old
-versions, do the following:
+ perl Build.PL --config cc=gcc --config ld=gcc
-Create a file in your distribution named F<Makefile.PL>, with the
-following contents:
+Inside the C<Build.PL> script the same thing can be accomplished by
+passing values for the C<config> parameter to C<new()>:
- use Module::Build::Compat;
- Module::Build::Compat->run_build_pl(args => \@ARGV);
- Module::Build::Compat->write_makefile();
+ my $build = Module::Build->new
+ (
+ ...
+ config => { cc => 'gcc', ld => 'gcc' },
+ ...
+ );
-Now CPAN will work as usual, i.e.: `perl Makefile.PL`, `make`, `make
-test`, and `make install`, provided the end-user already has
-C<Module::Build> installed.
+In custom build code, the same thing can be accomplished by calling
+the L<Module::Build/config> method:
-If the end-user might not have C<Module::Build> installed, it's
-probably best to supply a "traditional" F<Makefile.PL>. The
-C<Module::Build::Compat> module has some very helpful tools for
-keeping a F<Makefile.PL> in sync with a F<Build.PL>. See its
-documentation, and also the C<create_makefile_pl> parameter to the
-C<< Module::Build->new() >> method.
+ $build->config( cc => 'gcc' ); # Set
+ $build->config( ld => 'gcc' ); # Set
+ ...
+ my $linker = $build->config('ld'); # Get
=head2 Installing modules using the programmatic interface
To install to a non-standard directory (for example, if you don't have
permission to install in the system-wide directories), you can use the
-C<install_base>:
+C<install_base> or C<prefix> parameters:
./Build install --install_base /foo/bar
First, ensure you have at least version 0.28 of Module::Build
installed and 6.31 of ExtUtils::MakeMaker. Prior versions have
-differing installation behaviors.
+differing (and in some cases quite strange) installation behaviors.
The following installation flags are equivalent between
ExtUtils::MakeMaker and Module::Build.
=head3 C<prefix> vs C<install_base>
-The behavior of C<prefix> is complicated and depends closely on
+The behavior of C<prefix> is complicated and depends on
how your Perl is configured. The resulting installation locations
will vary from machine to machine and even different installations of
-Perl on the same machine. Because of this, its difficult to document
+Perl on the same machine. Because of this, it's difficult to document
where C<prefix> will place your modules.
In contrast, C<install_base> has predictable, easy to explain
./Build test --test_files t/mytest.t --verbose 1
-I run this so frequently that I actually define the following shell alias:
+I run this so frequently that I define the following shell alias:
alias t './Build test --verbose 1 --test_files'
=head1 ADVANCED RECIPES
+=head2 Making a CPAN.pm-compatible distribution
+
+New versions of CPAN.pm understand how to use a F<Build.PL> script,
+but old versions don't. If authors want to help users who have old
+versions, some form of F<Makefile.PL> should be supplied. The easiest
+way to accomplish this is to use the C<create_makefile_pl> parameter to
+C<< Module::Build->new() >> in the C<Build.PL> script, which can
+create various flavors of F<Makefile.PL> during the C<dist> action.
+
+As a best practice, we recommend using the "traditional" style of
+F<Makefile.PL> unless your distribution has needs that can't be
+accomplished that way.
+
+The C<Module::Build::Compat> module, which is part of
+C<Module::Build>'s distribution, is responsible for creating these
+F<Makefile.PL>s. Please see L<Module::Build::Compat> for the details.
+
+
=head2 Changing the order of the build process
The C<build_elements> property specifies the steps C<Module::Build>
Sometimes you might have extra types of files that you want to install
alongside the standard types like F<.pm> and F<.pod> files. For
instance, you might have a F<Bar.dat> file containing some data
-related to the C<Foo::Bar> module. Assuming the data doesn't need to
-be created on the fly, the best place for it to end up is probably as
+related to the C<Foo::Bar> module and you'd like for it to end up as
F<Foo/Bar.dat> somewhere in perl's C<@INC> path so C<Foo::Bar> can
access it easily at runtime. The following code from a sample
C<Build.PL> file demonstrates how to accomplish this:
to the F<blib/lib/> directory during the C<build> action, and install
them during the C<install> action.
-If your extra files aren't in the C<lib/> directory, you can
-explicitly say where they are, just as you'd do with F<.pm> or F<.pod>
-files:
+If your extra files aren't located in the C<lib/> directory in your
+distribution, you can explicitly say where they are, just as you'd do
+with F<.pm> or F<.pod> files:
use Module::Build;
my $build = new Module::Build
If your extra files actually need to be created on the user's machine,
or if they need some other kind of special processing, you'll probably
-want to create a special method to do so, named
-C<process_${kind}_files()>:
+want to subclass C<Module::Build> and create a special method to
+process them, named C<process_${kind}_files()>:
use Module::Build;
my $class = Module::Build->subclass(code => <<'EOF');
get them installed.
Please note that these examples use some capabilities of Module::Build
-that first appeared in version 0.26. Before that it could certainly
+that first appeared in version 0.26. Before that it could
still be done, but the simple cases took a bit more work.
=head2 Adding new elements to the install process
-By default, Module::Build creates seven subdirectories of the F<blib/>
-directory during the build process: F<lib/>, F<arch/>, F<bin/>,
-F<script/>, F<bindoc/>, F<libdoc/>, and F<html/> (some of these may be
+By default, Module::Build creates seven subdirectories of the F<blib>
+directory during the build process: F<lib>, F<arch>, F<bin>,
+F<script>, F<bindoc>, F<libdoc>, and F<html> (some of these may be
missing or empty if there's nothing to go in them). Anything copied
to these directories during the build will eventually be installed
during the C<install> action (see L<Module::Build/"INSTALL PATHS">.
-If you need to create a new type of installable element, e.g. C<conf>,
+If you need to create a new custom type of installable element, e.g. C<conf>,
then you need to tell Module::Build where things in F<blib/conf/>
should be installed. To do this, use the C<install_path> parameter to
the C<new()> method:
Or you can call the C<install_path()> method later:
- $build->install_path->{conf} || $installation_path;
-
-(Sneakily, or perhaps uglily, C<install_path()> returns a reference to
-a hash of install paths, and you can modify that hash to your heart's
-content.)
+ $build->install_path(conf => $installation_path);
The user may also specify the path on the command line:
The important part, though, is that I<somehow> the install path needs
to be set, or else nothing in the F<blib/conf/> directory will get
-installed.
+installed, and a runtime error during the C<install> action will
+result.
See also L<"Adding new file types to the build process"> for how to
create the stuff in F<blib/conf/> in the first place.
ownership of a file or do something else peculiar to your application.
You can subclass C<Module::Build> on the fly using the C<subclass()>
-method and override the methods that perform the actions. You may need
-to read through C<Module::Build::Authoring> to find the methods you
-want to override, but the general pattern is C<ACTION_> followed by
-the name of the action you want to modify. Here's an example of how
-it would work for C<install>:
+method and override the methods that perform the actions. You may
+need to read through C<Module::Build::Authoring> and
+C<Module::Build::API> to find the methods you want to override. All
+"action" methods are implemented by a method called "ACTION_" followed
+by the action's name, so here's an example of how it would work for
+the C<install> action:
# Build.PL
use Module::Build;
# rest of the usual Module::Build parameters
)->create_build_script;
-See the L<Module::Build::Authoring> pod in 0.27 or above for more
-complete documentation on this.
-
=head1 AUTHOR
--- /dev/null
+package Module::Build::Dumper;
+
+# This is just a split-out of a wrapper function to do Data::Dumper
+# stuff "the right way". See:
+# http://groups.google.com/group/perl.module.build/browse_thread/thread/c8065052b2e0d741
+
+use Data::Dumper;
+
+sub _data_dump {
+ my ($self, $data) = @_;
+ return ("do{ my "
+ . Data::Dumper->new([$data],['x'])->Purity(1)->Dump()
+ . '$x; }')
+}
+
+1;
# parrot future to look at other types of modules).
use strict;
+use vars qw($VERSION);
+$VERSION = '0.2808_01';
+$VERSION = eval $VERSION;
use File::Spec;
use IO::File;
# A class for persistent hashes
use strict;
+use vars qw($VERSION);
+$VERSION = '0.2808_01';
+$VERSION = eval $VERSION;
use Data::Dumper;
use IO::File;
+use Module::Build::Dumper;
sub new {
my ($class, %args) = @_;
my ($self, $file, $data) = @_;
my $fh = IO::File->new("> $file") or die "Can't create '$file': $!";
- local $Data::Dumper::Terse = 1;
- print $fh Data::Dumper::Dumper($data);
+ print {$fh} Module::Build::Dumper->_data_dump($data);
}
sub write_config_data {
sub write {
my $me = __FILE__;
require IO::File;
+
+ # Can't use Module::Build::Dumper here because M::B is only a
+ # build-time prereq of this module
require Data::Dumper;
my $mode_orig = (stat $me)[2] & 07777;
}
die "Couldn't find __DATA__ token in $me" if eof($fh);
- local $Data::Dumper::Terse = 1;
seek($fh, tell($fh), 0);
- $fh->print( Data::Dumper::Dumper([$config, $features, $auto_features]) );
+ my $data = [$config, $features, $auto_features];
+ $fh->print( 'do{ my '
+ . Data::Dumper->new([$data],['x'])->Purity(1)->Dump()
+ . '$x; }' );
truncate($fh, tell($fh));
$fh->close;
EOF
- local $Data::Dumper::Terse = 1;
- print $fh Data::Dumper::Dumper([$args{config_data}, $args{feature}, $args{auto_features}]);
+ print {$fh} Module::Build::Dumper->_data_dump([$args{config_data}, $args{feature}, $args{auto_features}]);
}
1;
package Module::Build::PPMMaker;
use strict;
+use vars qw($VERSION);
+$VERSION = '0.2808_01';
+$VERSION = eval $VERSION;
# This code is mostly borrowed from ExtUtils::MM_Unix 6.10_03, with a
# few tweaks based on the PPD spec at
package Module::Build::Platform::Amiga;
use strict;
+use vars qw($VERSION);
+$VERSION = '0.2808_01';
+$VERSION = eval $VERSION;
use Module::Build::Base;
use vars qw(@ISA);
package Module::Build::Platform::Default;
use strict;
+use vars qw($VERSION);
+$VERSION = '0.2808_01';
+$VERSION = eval $VERSION;
use Module::Build::Base;
use vars qw(@ISA);
package Module::Build::Platform::EBCDIC;
use strict;
+use vars qw($VERSION);
+$VERSION = '0.2808_01';
+$VERSION = eval $VERSION;
use Module::Build::Base;
use vars qw(@ISA);
package Module::Build::Platform::MPEiX;
use strict;
+use vars qw($VERSION);
+$VERSION = '0.2808_01';
+$VERSION = eval $VERSION;
use Module::Build::Base;
use vars qw(@ISA);
package Module::Build::Platform::MacOS;
use strict;
+use vars qw($VERSION);
+$VERSION = '0.2808_01';
+$VERSION = eval $VERSION;
use Module::Build::Base;
use vars qw(@ISA);
@ISA = qw(Module::Build::Base);
package Module::Build::Platform::RiscOS;
use strict;
+use vars qw($VERSION);
+$VERSION = '0.2808_01';
+$VERSION = eval $VERSION;
use Module::Build::Base;
use vars qw(@ISA);
package Module::Build::Platform::Unix;
use strict;
+use vars qw($VERSION);
+$VERSION = '0.2808_01';
+$VERSION = eval $VERSION;
use Module::Build::Base;
use vars qw(@ISA);
return $self;
}
+sub _detildefy {
+ my ($self, $value) = @_;
+ $value =~ s[^~(\w*)(?=/|$)] # tilde with optional username
+ [$1 ?
+ ((getpwnam $1)[7] || "~$1") :
+ (getpwuid $>)[7]
+ ]ex;
+ return $value;
+}
+
1;
__END__
package Module::Build::Platform::VMS;
use strict;
+use vars qw($VERSION);
+$VERSION = '0.2808_01';
+$VERSION = eval $VERSION;
use Module::Build::Base;
use vars qw(@ISA);
=item find_perl_interpreter
-On VMS, $^X returns the fully qualified absolute path including version number.
-It's logically impossible to improve on it for getting the perl we're currently
-running, and attempting to manipulate it is usually lossy.
+On VMS, $^X returns the fully qualified absolute path including version
+number. It's logically impossible to improve on it for getting the perl
+we're currently running, and attempting to manipulate it is usually
+lossy.
=cut
package Module::Build::Platform::VOS;
use strict;
+use vars qw($VERSION);
+$VERSION = '0.2808_01';
+$VERSION = eval $VERSION;
use Module::Build::Base;
use vars qw(@ISA);
package Module::Build::Platform::Windows;
use strict;
+use vars qw($VERSION);
+$VERSION = '0.2808_01';
+$VERSION = eval $VERSION;
use Config;
use File::Basename;
sub have_forkpipe { 0 }
+sub _detildefy {
+ my ($self, $value) = @_;
+ $value =~ s,^~(?= [/\\] | $ ),$ENV{HOME},x
+ if $ENV{HOME};
+ return $value;
+}
+
sub ACTION_realclean {
my ($self) = @_;
package Module::Build::Platform::aix;
use strict;
+use vars qw($VERSION);
+$VERSION = '0.2808_01';
+$VERSION = eval $VERSION;
use Module::Build::Platform::Unix;
use vars qw(@ISA);
package Module::Build::Platform::cygwin;
use strict;
+use vars qw($VERSION);
+$VERSION = '0.2808_01';
+$VERSION = eval $VERSION;
use Module::Build::Platform::Unix;
use vars qw(@ISA);
package Module::Build::Platform::darwin;
use strict;
+use vars qw($VERSION);
+$VERSION = '0.2808_01';
+$VERSION = eval $VERSION;
use Module::Build::Platform::Unix;
use vars qw(@ISA);
package Module::Build::Platform::os2;
use strict;
+use vars qw($VERSION);
+$VERSION = '0.2808_01';
+$VERSION = eval $VERSION;
use Module::Build::Platform::Unix;
use vars qw(@ISA);
package Module::Build::PodParser;
use strict;
+use vars qw($VERSION);
+$VERSION = '0.2808_01';
+$VERSION = eval $VERSION;
use vars qw(@ISA);
sub new {
use vars qw($VERSION);
$VERSION = 0.7203;
-use base qw/version/;
+
+eval "use version $VERSION";
+if ($@) { # can't locate version files, use our own
+
+ # Avoid redefined warnings if an old version.pm was available
+ delete $version::{$_} foreach keys %version::;
+
+ # first we get the stub version module
+ my $version;
+ while (<DATA>) {
+ s/(\$VERSION)\s=\s\d+/\$VERSION = 0/;
+ $version .= $_ if $_;
+ last if /^1;$/;
+ }
+
+ # and now get the current version::vpp code
+ my $vpp;
+ while (<DATA>) {
+ s/(\$VERSION)\s=\s\d+/\$VERSION = 0/;
+ $vpp .= $_ if $_;
+ last if /^1;$/;
+ }
+
+ # but we eval them in reverse order since version depends on
+ # version::vpp to already exist
+ eval $vpp; die $@ if $@;
+ $INC{'version/vpp.pm'} = 'inside Module::Build::Version';
+ eval $version; die $@ if $@;
+ $INC{'version.pm'} = 'inside Module::Build::Version';
+}
+
+# now we can safely subclass version, installed or not
+use vars qw(@ISA);
+@ISA = qw(version);
+
+1;
+__DATA__
+# stub version module to make everything else happy
+package version;
+
+use 5.005_04;
+use strict;
+
+use vars qw(@ISA $VERSION $CLASS *qv);
+
+$VERSION = 0.000;
+
+$CLASS = 'version';
+
+push @ISA, "version::vpp";
+*version::qv = \&version::vpp::qv;
+
+# Preloaded methods go here.
+sub import {
+ my ($class) = @_;
+ my $callpkg = caller();
+ no strict 'refs';
+
+ *{$callpkg."::qv"} =
+ sub {return bless version::qv(shift), $class }
+ unless defined(&{"$callpkg\::qv"});
+
+}
+
+1;
+# replace everything from here to the end with the current version/vpp.pm
+
+package version::vpp;
+use strict;
+
+use locale;
+use vars qw ($VERSION @ISA @REGEXS);
+$VERSION = 0.7203;
+
+push @REGEXS, qr/
+ ^v? # optional leading 'v'
+ (\d*) # major revision not required
+ \. # requires at least one decimal
+ (?:(\d+)\.?){1,}
+ /x;
+
+use overload (
+ '""' => \&stringify,
+ '0+' => \&numify,
+ 'cmp' => \&vcmp,
+ '<=>' => \&vcmp,
+ 'bool' => \&vbool,
+ 'nomethod' => \&vnoop,
+);
+
+sub new
+{
+ my ($class, $value) = @_;
+ my $self = bless ({}, ref ($class) || $class);
+
+ if ( ref($value) && eval("$value->isa('version')") ) {
+ # Can copy the elements directly
+ $self->{version} = [ @{$value->{version} } ];
+ $self->{qv} = 1 if $value->{qv};
+ $self->{alpha} = 1 if $value->{alpha};
+ $self->{original} = ''.$value->{original};
+ return $self;
+ }
+
+ require POSIX;
+ my $currlocale = POSIX::setlocale(&POSIX::LC_ALL);
+ my $radix_comma = ( POSIX::localeconv()->{decimal_point} eq ',' );
+
+ if ( not defined $value or $value =~ /^undef$/ ) {
+ # RT #19517 - special case for undef comparison
+ # or someone forgot to pass a value
+ push @{$self->{version}}, 0;
+ $self->{original} = "0";
+ return ($self);
+ }
+
+ if ( $#_ == 2 ) { # must be CVS-style
+ $value = 'v'.$_[2];
+ }
+
+ $value = _un_vstring($value);
+
+ # exponential notation
+ if ( $value =~ /\d+.?\d*e-?\d+/ ) {
+ $value = sprintf("%.9f",$value);
+ $value =~ s/(0+)$//;
+ }
+
+ # if the original locale used commas for decimal points, we
+ # just replace commas with decimal places, rather than changing
+ # locales
+ if ( $radix_comma ) {
+ $value =~ tr/,/./;
+ }
+
+ # This is not very efficient, but it is morally equivalent
+ # to the XS code (as that is the reference implementation).
+ # See vutil/vutil.c for details
+ my $qv = 0;
+ my $alpha = 0;
+ my $width = 3;
+ my $saw_period = 0;
+ my ($start, $last, $pos, $s);
+ $s = 0;
+
+ while ( substr($value,$s,1) =~ /\s/ ) { # leading whitespace is OK
+ $s++;
+ }
+
+ if (substr($value,$s,1) eq 'v') {
+ $s++; # get past 'v'
+ $qv = 1; # force quoted version processing
+ }
+
+ $start = $last = $pos = $s;
+
+ # pre-scan the input string to check for decimals/underbars
+ while ( substr($value,$pos,1) =~ /[._\d]/ ) {
+ if ( substr($value,$pos,1) eq '.' ) {
+ if ($alpha) {
+ require Carp;
+ Carp::croak("Invalid version format ".
+ "(underscores before decimal)");
+ }
+ $saw_period++;
+ $last = $pos;
+ }
+ elsif ( substr($value,$pos,1) eq '_' ) {
+ if ($alpha) {
+ require Carp;
+ Carp::croak("Invalid version format ".
+ "(multiple underscores)");
+ }
+ $alpha = 1;
+ $width = $pos - $last - 1; # natural width of sub-version
+ }
+ $pos++;
+ }
+
+ if ( $alpha && !$saw_period ) {
+ require Carp;
+ Carp::croak("Invalid version format (alpha without decimal)");
+ }
+
+ if ( $alpha && $saw_period && $width == 0 ) {
+ require Carp;
+ Carp::croak("Invalid version format (misplaced _ in number)");
+ }
+
+ if ( $saw_period > 1 ) {
+ $qv = 1; # force quoted version processing
+ }
+
+ $pos = $s;
+
+ if ( $qv ) {
+ $self->{qv} = 1;
+ }
+
+ if ( $alpha ) {
+ $self->{alpha} = 1;
+ }
+
+ if ( !$qv && $width < 3 ) {
+ $self->{width} = $width;
+ }
+
+ while ( substr($value,$pos,1) =~ /\d/ ) {
+ $pos++;
+ }
+
+ if ( substr($value,$pos,1) !~ /[a-z]/ ) { ### FIX THIS ###
+ my $rev;
+
+ while (1) {
+ $rev = 0;
+ {
+
+ # this is atoi() that delimits on underscores
+ my $end = $pos;
+ my $mult = 1;
+ my $orev;
+
+ # the following if() will only be true after the decimal
+ # point of a version originally created with a bare
+ # floating point number, i.e. not quoted in any way
+ if ( !$qv && $s > $start && $saw_period == 1 ) {
+ $mult *= 100;
+ while ( $s < $end ) {
+ $orev = $rev;
+ $rev += substr($value,$s,1) * $mult;
+ $mult /= 10;
+ if ( abs($orev) > abs($rev) ) {
+ require Carp;
+ Carp::croak("Integer overflow in version");
+ }
+ $s++;
+ if ( substr($value,$s,1) eq '_' ) {
+ $s++;
+ }
+ }
+ }
+ else {
+ while (--$end >= $s) {
+ $orev = $rev;
+ $rev += substr($value,$end,1) * $mult;
+ $mult *= 10;
+ if ( abs($orev) > abs($rev) ) {
+ require Carp;
+ Carp::croak("Integer overflow in version");
+ }
+ }
+ }
+ }
+
+ # Append revision
+ push @{$self->{version}}, $rev;
+ if ( substr($value,$pos,1) eq '.'
+ && substr($value,$pos+1,1) =~ /\d/ ) {
+ $s = ++$pos;
+ }
+ elsif ( substr($value,$pos,1) eq '_'
+ && substr($value,$pos+1,1) =~ /\d/ ) {
+ $s = ++$pos;
+ }
+ elsif ( substr($value,$pos,1) =~ /\d/ ) {
+ $s = $pos;
+ }
+ else {
+ $s = $pos;
+ last;
+ }
+ if ( $qv ) {
+ while ( substr($value,$pos,1) =~ /\d/ ) {
+ $pos++;
+ }
+ }
+ else {
+ my $digits = 0;
+ while (substr($value,$pos,1) =~ /[\d_]/ && $digits < 3) {
+ if ( substr($value,$pos,1) ne '_' ) {
+ $digits++;
+ }
+ $pos++;
+ }
+ }
+ }
+ }
+ if ( $qv ) { # quoted versions always get at least three terms
+ my $len = scalar @{$self->{version}};
+ $len = 3 - $len;
+ while ($len-- > 0) {
+ push @{$self->{version}}, 0;
+ }
+ }
+
+ if ( substr($value,$pos) ) { # any remaining text
+ warn "Version string '$value' contains invalid data; ".
+ "ignoring: '".substr($value,$pos)."'";
+ }
+
+ # cache the original value for use when stringification
+ $self->{original} = substr($value,0,$pos);
+
+ return ($self);
+}
+
+sub numify
+{
+ my ($self) = @_;
+ unless (_verify($self)) {
+ require Carp;
+ Carp::croak("Invalid version object");
+ }
+ my $width = $self->{width} || 3;
+ my $alpha = $self->{alpha} || "";
+ my $len = $#{$self->{version}};
+ my $digit = $self->{version}[0];
+ my $string = sprintf("%d.", $digit );
+
+ for ( my $i = 1 ; $i < $len ; $i++ ) {
+ $digit = $self->{version}[$i];
+ if ( $width < 3 ) {
+ my $denom = 10**(3-$width);
+ my $quot = int($digit/$denom);
+ my $rem = $digit - ($quot * $denom);
+ $string .= sprintf("%0".$width."d_%d", $quot, $rem);
+ }
+ else {
+ $string .= sprintf("%03d", $digit);
+ }
+ }
+
+ if ( $len > 0 ) {
+ $digit = $self->{version}[$len];
+ if ( $alpha && $width == 3 ) {
+ $string .= "_";
+ }
+ $string .= sprintf("%0".$width."d", $digit);
+ }
+ else # $len = 0
+ {
+ $string .= sprintf("000");
+ }
+
+ return $string;
+}
+
+sub normal
+{
+ my ($self) = @_;
+ unless (_verify($self)) {
+ require Carp;
+ Carp::croak("Invalid version object");
+ }
+ my $alpha = $self->{alpha} || "";
+ my $len = $#{$self->{version}};
+ my $digit = $self->{version}[0];
+ my $string = sprintf("v%d", $digit );
+
+ for ( my $i = 1 ; $i < $len ; $i++ ) {
+ $digit = $self->{version}[$i];
+ $string .= sprintf(".%d", $digit);
+ }
+
+ if ( $len > 0 ) {
+ $digit = $self->{version}[$len];
+ if ( $alpha ) {
+ $string .= sprintf("_%0d", $digit);
+ }
+ else {
+ $string .= sprintf(".%0d", $digit);
+ }
+ }
+
+ if ( $len <= 2 ) {
+ for ( $len = 2 - $len; $len != 0; $len-- ) {
+ $string .= sprintf(".%0d", 0);
+ }
+ }
+
+ return $string;
+}
+
+sub stringify
+{
+ my ($self) = @_;
+ unless (_verify($self)) {
+ require Carp;
+ Carp::croak("Invalid version object");
+ }
+ return $self->{original};
+}
+
+sub vcmp
+{
+ require UNIVERSAL;
+ my ($left,$right,$swap) = @_;
+ my $class = ref($left);
+ unless ( UNIVERSAL::isa($right, $class) ) {
+ $right = $class->new($right);
+ }
+
+ if ( $swap ) {
+ ($left, $right) = ($right, $left);
+ }
+ unless (_verify($left)) {
+ require Carp;
+ Carp::croak("Invalid version object");
+ }
+ unless (_verify($right)) {
+ require Carp;
+ Carp::croak("Invalid version object");
+ }
+ my $l = $#{$left->{version}};
+ my $r = $#{$right->{version}};
+ my $m = $l < $r ? $l : $r;
+ my $lalpha = $left->is_alpha;
+ my $ralpha = $right->is_alpha;
+ my $retval = 0;
+ my $i = 0;
+ while ( $i <= $m && $retval == 0 ) {
+ $retval = $left->{version}[$i] <=> $right->{version}[$i];
+ $i++;
+ }
+
+ # tiebreaker for alpha with identical terms
+ if ( $retval == 0
+ && $l == $r
+ && $left->{version}[$m] == $right->{version}[$m]
+ && ( $lalpha || $ralpha ) ) {
+
+ if ( $lalpha && !$ralpha ) {
+ $retval = -1;
+ }
+ elsif ( $ralpha && !$lalpha) {
+ $retval = +1;
+ }
+ }
+
+ # possible match except for trailing 0's
+ if ( $retval == 0 && $l != $r ) {
+ if ( $l < $r ) {
+ while ( $i <= $r && $retval == 0 ) {
+ if ( $right->{version}[$i] != 0 ) {
+ $retval = -1; # not a match after all
+ }
+ $i++;
+ }
+ }
+ else {
+ while ( $i <= $l && $retval == 0 ) {
+ if ( $left->{version}[$i] != 0 ) {
+ $retval = +1; # not a match after all
+ }
+ $i++;
+ }
+ }
+ }
+
+ return $retval;
+}
+
+sub vbool {
+ my ($self) = @_;
+ return vcmp($self,$self->new("0"),1);
+}
+
+sub vnoop {
+ require Carp;
+ Carp::croak("operation not supported with version object");
+}
+
+sub is_alpha {
+ my ($self) = @_;
+ return (exists $self->{alpha});
+}
+
+sub qv {
+ my ($value) = @_;
+
+ $value = _un_vstring($value);
+ $value = 'v'.$value unless $value =~ /(^v|\d+\.\d+\.\d)/;
+ my $version = version->new($value); # always use base class
+ return $version;
+}
+
+sub is_qv {
+ my ($self) = @_;
+ return (exists $self->{qv});
+}
+
+
+sub _verify {
+ my ($self) = @_;
+ if ( ref($self)
+ && eval { exists $self->{version} }
+ && ref($self->{version}) eq 'ARRAY'
+ ) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
+
+sub _un_vstring {
+ my $value = shift;
+ # may be a v-string
+ if ( $] >= 5.006_000 && length($value) >= 3 && $value !~ /[._]/ ) {
+ my $tvalue = sprintf("v%vd",$value);
+ if ( $tvalue =~ /^v\d+\.\d+\.\d+$/ ) {
+ # must be a v-string
+ $value = $tvalue;
+ }
+ }
+ return $value;
+}
+
+# Thanks to Yitzchak Scott-Thoennes for this mode of operation
+{
+ local $^W;
+ *UNIVERSAL::VERSION = sub {
+ my ($obj, $req) = @_;
+ my $class = ref($obj) || $obj;
+
+ no strict 'refs';
+ eval "require $class" unless %{"$class\::"}; # already existing
+ return undef if $@ =~ /Can't locate/ and not defined $req;
+
+ if ( not %{"$class\::"} and $] >= 5.008) { # file but no package
+ require Carp;
+ Carp::croak( "$class defines neither package nor VERSION"
+ ."--version check failed");
+ }
+
+ my $version = eval "\$$class\::VERSION";
+ if ( defined $version ) {
+ local $^W if $] <= 5.008;
+ $version = version::vpp->new($version);
+ }
+
+ if ( defined $req ) {
+ unless ( defined $version ) {
+ require Carp;
+ my $msg = $] < 5.006
+ ? "$class version $req required--this is only version "
+ : "$class does not define \$$class\::VERSION"
+ ."--version check failed";
+
+ if ( $ENV{VERSION_DEBUG} ) {
+ Carp::confess($msg);
+ }
+ else {
+ Carp::croak($msg);
+ }
+ }
+
+ $req = version::vpp->new($req);
+
+ if ( $req > $version ) {
+ require Carp;
+ if ( $req->is_qv ) {
+ Carp::croak(
+ sprintf ("%s version %s required--".
+ "this is only version %s", $class,
+ $req->normal, $version->normal)
+ );
+ }
+ else {
+ Carp::croak(
+ sprintf ("%s version %s required--".
+ "this is only version %s", $class,
+ $req->stringify, $version->stringify)
+ );
+ }
+ }
+ }
+
+ return defined $version ? $version->stringify : undef;
+ };
+}
+
+1; #this line is important and will help the module return a true value
package Module::Build::YAML;
use strict;
+use vars qw($VERSION);
+$VERSION = '0.2808_01';
+$VERSION = eval $VERSION;
use vars qw($VERSION @EXPORT @EXPORT_OK);
$VERSION = "0.50";
use Cwd ();
my $cwd = Cwd::cwd;
-my $tmp = File::Spec->catdir( $cwd, 't', '_tmp' );
+my $tmp = MBTest->tmpdir;
use DistGen;
my $dist = DistGen->new( dir => $tmp );
# Getopt::Long specs work as expected.
{
use Config;
- $dist->change_file( 'Build.PL', <<"---" );
-use Module::Build;
-
-my \$build = Module::Build->new(
- module_name => @{[$dist->name]},
- license => 'perl',
- get_options => { foo => {},
- bar => { type => '+' },
- bat => { type => '=s' },
- dee => { type => '=s',
- default => 'goo'
- },
- }
-);
-
-\$build->create_build_script;
----
+ $dist->change_build_pl
+ ({
+ module_name => @{[$dist->name]},
+ license => 'perl',
+ get_options => { foo => {},
+ bar => { type => '+' },
+ bat => { type => '=s' },
+ dee => { type => '=s',
+ default => 'goo'
+ },
+ }
+ });
$dist->regen;
eval {Module::Build->run_perl_script('Build.PL', [], ['--nouse-rcfile', '--config', "foocakes=barcakes", '--foo', '--bar', '--bar', '-bat=hello', 'gee=whiz', '--any', 'hey', '--destdir', 'yo', '--verbose', '1'])};
#
# Author: Christopher J. Madsen <cjm@pobox.com>
# Created: 08 Nov 1997
-# $Revision: 1849 $ $Date: 2006-03-21T13:27:29.000000Z $
+# $Revision: 5841 $ $Date: 2006-03-21 07:27:29 -0600 (Tue, 21 Mar 2006) $
#
# This program is free software; you can redistribute it and/or modify
# it under the same terms as Perl itself.
use lib $ENV{PERL_CORE} ? '../lib/Module/Build/t/lib' : 't/lib';
use MBTest;
use File::Spec;
+use IO::File;
use Config;
# Don't let our own verbosity/test_file get mixed up with our subprocess's
delete @ENV{@makefile_keys};
my @makefile_types = qw(small passthrough traditional);
-my $tests_per_type = 10;
+my $tests_per_type = 14;
if ( $Config{make} && find_in_path($Config{make}) ) {
- plan tests => 30 + @makefile_types*$tests_per_type;
+ plan tests => 38 + @makefile_types*$tests_per_type*2;
} else {
plan skip_all => "Don't know how to invoke 'make'";
}
-ok(1); # Loaded
+ok 1, "Loaded";
#########################
use Cwd ();
my $cwd = Cwd::cwd;
-my $tmp = File::Spec->catdir( $cwd, 't', '_tmp' );
+my $tmp = MBTest->tmpdir;
+# Create test distribution; set requires and build_requires
use DistGen;
my $dist = DistGen->new( dir => $tmp );
$dist->regen;
#########################
+# Test without requires
-my $mb = Module::Build->new_from_context;
-ok $mb;
+test_makefile_types();
+
+# Test with requires
+
+my $distname = $dist->name;
+$dist->change_build_pl({
+ module_name => $distname,
+ license => 'perl',
+ requires => {
+ 'perl' => $],
+ 'File::Spec' => 0,
+ },
+ build_requires => {
+ 'Test::More' => 0,
+ },
+});
+
+$dist->regen;
+
+test_makefile_types( requires => {
+ 'perl' => $],
+ 'File::Spec' => 0,
+ 'Test::More' => 0,
+});
+
+######################
+
+$dist->change_build_pl({
+ module_name => $distname,
+ license => 'perl',
+});
+$dist->regen;
+
+# Create M::B instance but don't pollute STDOUT
+my $mb;
+stdout_of( sub {
+ $mb = Module::Build->new_from_context;
+});
+ok $mb, "Module::Build->new_from_context";
-foreach my $type (@makefile_types) {
- Module::Build::Compat->create_makefile_pl($type, $mb);
- test_makefile_creation($mb);
-
- ok $mb->do_system(@make);
-
- # Can't let 'test' STDOUT go to our STDOUT, or it'll confuse Test::Harness.
- my $success;
- my $output = stdout_of( sub {
- $success = $mb->do_system(@make, 'test');
- } );
- ok $success;
- like uc $output, qr{DONE\.|SUCCESS};
-
- ok $mb->do_system(@make, 'realclean');
-
- # Try again with some Makefile.PL arguments
- test_makefile_creation($mb, [], 'INSTALLDIRS=vendor', 1);
-
- 1 while unlink 'Makefile.PL';
- ok ! -e 'Makefile.PL';
-}
{
# Make sure fake_makefile() can run without 'build_class', as it may be
my $warning = '';
local $SIG{__WARN__} = sub { $warning = shift; };
my $maketext = eval { Module::Build::Compat->fake_makefile(makefile => 'Makefile') };
- is $@, '';
- like $maketext, qr/^realclean/m;
- like $warning, qr/build_class/;
+ is $@, '', "fake_makefile lived";
+ like $maketext, qr/^realclean/m, "found 'realclean' in fake_makefile output";
+ like $warning, qr/build_class/, "saw warning about 'build_class'";
}
{
# Make sure custom builder subclass is used in the created
# Makefile.PL - make sure it fails in the right way here.
local @Foo::Builder::ISA = qw(Module::Build);
- my $foo_builder = Foo::Builder->new_from_context;
+ my $foo_builder;
+ stdout_of( sub {
+ $foo_builder = Foo::Builder->new_from_context;
+ });
foreach my $style ('passthrough', 'small') {
Module::Build::Compat->create_makefile_pl($style, $foo_builder);
- ok -e 'Makefile.PL';
+ ok -e 'Makefile.PL', "$style Makefile.PL created";
# Should fail with "can't find Foo/Builder.pm"
- my $warning = stderr_of
- (sub {
- my $result = $mb->run_perl_script('Makefile.PL');
- ok ! $result;
- });
- like $warning, qr{Foo/Builder.pm};
+ my $result;
+ my ($stdout, $stderr ) = stdout_stderr_of (sub {
+ $result = $mb->run_perl_script('Makefile.PL');
+ });
+ ok ! $result, "Makefile.PL failed";
+ like $stderr, qr{Foo/Builder.pm}, "custom builder wasn't found";
}
# Now make sure it can actually work.
- my $bar_builder = Module::Build->subclass( class => 'Bar::Builder' )->new_from_context;
+ my $bar_builder;
+ stdout_of( sub {
+ $bar_builder = Module::Build->subclass( class => 'Bar::Builder' )->new_from_context;
+ });
foreach my $style ('passthrough', 'small') {
Module::Build::Compat->create_makefile_pl($style, $bar_builder);
- ok -e 'Makefile.PL';
- ok $mb->run_perl_script('Makefile.PL');
+ ok -e 'Makefile.PL', "$style Makefile.PL created via subclass";
+ my $result;
+ stdout_of( sub {
+ $result = $mb->run_perl_script('Makefile.PL');
+ });
+ ok $result, "Makefile.PL ran without error";
}
}
Module::Build::Compat->create_makefile_pl('passthrough', $mb);
my $libdir = File::Spec->catdir( $cwd, 't', 'libdir' );
- my $result = $mb->run_perl_script('Makefile.PL', [],
- [
- "LIB=$libdir",
- 'TEST_VERBOSE=1',
- 'INSTALLDIRS=perl',
- 'POLLUTE=1',
- ]
- );
- ok $result;
- ok -e 'Build.PL';
+ my $result;
+ stdout_of( sub {
+ $result = $mb->run_perl_script('Makefile.PL', [],
+ [
+ "LIB=$libdir",
+ 'TEST_VERBOSE=1',
+ 'INSTALLDIRS=perl',
+ 'POLLUTE=1',
+ ]
+ );
+ });
+ ok $result, "passthrough Makefile.PL ran with arguments";
+ ok -e 'Build.PL', "Build.PL generated";
my $new_build = Module::Build->resume();
- is $new_build->installdirs, 'core';
- is $new_build->verbose, 1;
- is $new_build->install_destination('lib'), $libdir;
- is $new_build->extra_compiler_flags->[0], '-DPERL_POLLUTE';
+ is $new_build->installdirs, 'core', "installdirs is core";
+ is $new_build->verbose, 1, "tests set for verbose";
+ is $new_build->install_destination('lib'), $libdir, "custom libdir";
+ is $new_build->extra_compiler_flags->[0], '-DPERL_POLLUTE', "PERL_POLLUTE set";
# Make sure those switches actually had an effect
my ($ran_ok, $output);
$output = stdout_of( sub { $ran_ok = $new_build->do_system(@make, 'test') } );
- ok $ran_ok;
+ ok $ran_ok, "make test ran without error";
$output =~ s/^/# /gm; # Don't confuse our own test output
like $output, qr/(?:# ok \d+\s+)+/, 'Should be verbose';
# Make sure various Makefile arguments are supported
$output = stdout_of( sub { $ran_ok = $mb->do_system(@make, 'test', 'TEST_VERBOSE=0') } );
- ok $ran_ok;
+ ok $ran_ok, "make test without verbose ran ok";
$output =~ s/^/# /gm; # Don't confuse our own test output
like $output, qr/(?:# .+basic\.+ok\s+(?:[\d.]+\s*m?s\s*)?)# All tests/,
'Should be non-verbose';
$mb->delete_filetree($libdir);
ok ! -e $libdir, "Sample installation directory should be cleaned up";
- $mb->do_system(@make, 'realclean');
+ stdout_of( sub { $mb->do_system(@make, 'realclean'); } );
ok ! -e 'Makefile', "Makefile shouldn't exist";
1 while unlink 'Makefile.PL';
- ok ! -e 'Makefile.PL';
+ ok ! -e 'Makefile.PL', "Makefile.PL cleaned up";
}
{ # Make sure tilde-expansion works
Module::Build::Compat->create_makefile_pl('passthrough', $mb);
- $mb->run_perl_script('Makefile.PL', [], ['INSTALL_BASE=~/foo']);
+ stdout_of( sub {
+ $mb->run_perl_script('Makefile.PL', [], ['INSTALL_BASE=~/foo']);
+ });
my $b2 = Module::Build->current;
- ok $b2->install_base;
+ ok $b2->install_base, "install_base set";
unlike $b2->install_base, qr/^~/, "Tildes should be expanded";
- $mb->do_system(@make, 'realclean');
+ stdout_of( sub { $mb->do_system(@make, 'realclean'); } );
+ ok ! -e 'Makefile', "Makefile shouldn't exist";
+
1 while unlink 'Makefile.PL';
+ ok ! -e 'Makefile.PL', "Makefile.PL cleaned up";
}
+
#########################################################
+sub test_makefile_types {
+ my %opts = @_;
+ $opts{requires} ||= {};
+
+ foreach my $type (@makefile_types) {
+ # Create M::B instance
+ my $mb;
+ stdout_of( sub {
+ $mb = Module::Build->new_from_context;
+ });
+ ok $mb, "Module::Build->new_from_context";
+
+ # Create and test Makefile.PL
+ Module::Build::Compat->create_makefile_pl($type, $mb);
+ ok -e 'Makefile.PL', "$type Makefile.PL created";
+ test_makefile_pl_requires_perl( $opts{requires}{perl} );
+ test_makefile_creation($mb);
+ test_makefile_prereq_pm( $opts{requires} );
+
+ my ($output,$success);
+ # Capture output to keep our STDOUT clean
+ $output = stdout_of( sub {
+ $success = $mb->do_system(@make);
+ });
+ ok $success, "make ran without error";
+
+ # Can't let 'test' STDOUT go to our STDOUT, or it'll confuse Test::Harness.
+ $output = stdout_of( sub {
+ $success = $mb->do_system(@make, 'test');
+ });
+ ok $success, "make test ran without error";
+ like uc $output, qr{DONE\.|SUCCESS}, "make test output indicated success";
+
+ $output = stdout_of( sub {
+ $success = $mb->do_system(@make, 'realclean');
+ });
+ ok $success, "make realclean ran without error";
+
+ # Try again with some Makefile.PL arguments
+ test_makefile_creation($mb, [], 'INSTALLDIRS=vendor', 1);
+
+ 1 while unlink 'Makefile.PL';
+ ok ! -e 'Makefile.PL', "cleaned up Makefile";
+ }
+}
+
sub test_makefile_creation {
my ($build, $preargs, $postargs, $cleanup) = @_;
- my $result = $build->run_perl_script('Makefile.PL', $preargs, $postargs);
- ok $result;
- ok -e 'Makefile', "Makefile should exist";
+ my ($output, $result);
+ # capture output to avoid polluting our test output
+ $output = stdout_of( sub {
+ $result = $build->run_perl_script('Makefile.PL', $preargs, $postargs);
+ });
+ my $label = "Makefile.PL ran without error";
+ if ( defined $postargs && length $postargs ) {
+ $label .= " (postargs: $postargs)";
+ }
+ ok $result, $label;
+ ok -e 'Makefile', "Makefile exists";
if ($cleanup) {
- $build->do_system(@make, 'realclean');
- ok ! -e 'Makefile', "Makefile shouldn't exist";
+ $output = stdout_of( sub {
+ $build->do_system(@make, 'realclean');
+ });
+ ok ! -e 'Makefile', "Makefile cleaned up";
+ }
+ else {
+ pass '(skipping cleanup)'; # keep test count constant
}
}
+sub test_makefile_prereq_pm {
+ my %requires = %{ $_[0] };
+ delete $requires{perl}; # until EU::MM supports this
+ SKIP: {
+ skip 'Makefile not found', 1 unless -e 'Makefile';
+ my $prereq_pm = find_makefile_prereq_pm();
+ is_deeply $prereq_pm, \%requires,
+ "Makefile has correct PREREQ_PM line";
+ }
+}
+
+sub test_makefile_pl_requires_perl {
+ my $perl_version = shift || q{};
+ SKIP: {
+ skip 'Makefile.PL not found', 1 unless -e 'Makefile.PL';
+ my $file_contents = slurp 'Makefile.PL';
+ my $found_requires = $file_contents =~ m{^require $perl_version;}ms;
+ if (length $perl_version) {
+ ok $found_requires, "Makefile.PL has 'require $perl_version;'"
+ or diag "Makefile.PL:\n$file_contents";
+ }
+ else {
+ ok ! $found_requires, "Makefile.PL does not require a perl version";
+ }
+ }
+}
+
+# Following subroutine adapted from code in CPAN.pm
+# by Andreas Koenig and A. Speer.
+sub find_makefile_prereq_pm {
+ my $fh = IO::File->new( 'Makefile', 'r' )
+ or die "Can't read Makefile: $!";
+ my $req = {};
+ local($/) = "\n";
+ while (<$fh>) {
+ # locate PREREQ_PM
+ last if /MakeMaker post_initialize section/;
+ my($p) = m{^[\#]
+ \s+PREREQ_PM\s+=>\s+(.+)
+ }x;
+ next unless $p;
+
+ # extract modules
+ while ( $p =~ m/(?:\s)([\w\:]+)=>(q\[.*?\]|undef),?/g ){
+ my($m,$n) = ($1,$2);
+ if ($n =~ /^q\[(.*?)\]$/) {
+ $n = $1;
+ }
+ $req->{$m} = $n;
+ }
+ last;
+ }
+ return $req;
+}
# cleanup
chdir( $cwd ) or die "Can''t chdir to '$cwd': $!";
use Cwd ();
my $cwd = Cwd::cwd;
-my $tmp = File::Spec->catdir( $cwd, 't', '_tmp' );
+my $tmp = MBTest->tmpdir;
use DistGen;
my $dist = DistGen->new( dir => $tmp );
use Config;
-use File::Spec::Functions qw( catdir splitdir splitpath );
+use File::Spec::Functions qw( catdir splitdir );
#########################
my ($dir1, $dir2, $message) = @_;
$dir1 =~ s{/$}{} if $^O eq 'cygwin'; # remove any trailing slash
- my (undef, $dirs1, undef) = splitpath $dir1;
- my @dir1 = splitdir $dirs1;
+ my @dir1 = splitdir $dir1;
$dir2 =~ s{/$}{} if $^O eq 'cygwin'; # remove any trailing slash
- my (undef, $dirs2, undef) = splitpath $dir2;
- my @dir2 = splitdir $dirs2;
+ my @dir2 = splitdir $dir2;
is $dir1[-1], $dir2[-1], $message;
}
use Cwd ();
my $cwd = Cwd::cwd;
-my $tmp = File::Spec->catdir( $cwd, 't', '_tmp' );
+my $tmp = MBTest->tmpdir;
use DistGen;
my $dist = DistGen->new( dir => $tmp );
use Cwd ();
my $cwd = Cwd::cwd;
-my $tmp = File::Spec->catdir( $cwd, 't', '_tmp' );
+my $tmp = MBTest->tmpdir;
use DistGen;
my $dist = DistGen->new( dir => $tmp );
use File::Path ();
my $cwd = Cwd::cwd();
-my $tmp = File::Spec->catdir($cwd, 't', '_tmp');
+my $tmp = MBTest->tmpdir;
use DistGen;
use Cwd ();
my $cwd = Cwd::cwd;
-my $tmp = File::Spec->catdir( $cwd, 't', '_tmp' );
+my $tmp = MBTest->tmpdir;
use DistGen;
my $dist = DistGen->new( dir => $tmp );
#!perl -w
print "Hello, World!\n";
---
-$dist->change_file( 'Build.PL', <<"---" );
-use Module::Build;
-
-my \$build = new Module::Build(
- module_name => @{[$dist->name]},
+$dist->change_build_pl
+({
+ module_name => $dist->name,
scripts => [ 'script' ],
license => 'perl',
requires => { 'File::Spec' => 0 },
-);
-\$build->create_build_script;
----
+});
$dist->regen;
ok $mb;
-my $destdir = File::Spec->catdir($cwd, 't', 'install_test');
+my $destdir = File::Spec->catdir($cwd, 't', 'install_test.' . $$);
$mb->add_to_cleanup($destdir);
{
use strict;
-use vars qw( $VERSION $VERBOSE );
+use vars qw( $VERSION $VERBOSE @EXPORT_OK);
$VERSION = '0.01';
$VERBOSE = 0;
use File::Spec ();
use IO::File ();
use Tie::CPHash;
+use Data::Dumper;
BEGIN {
if( $^O eq 'VMS' ) {
VMS::Filespec->import;
}
}
+BEGIN {
+ require Exporter;
+ *{import} = \&Exporter::import;
+ @EXPORT_OK = qw(
+ undent
+ );
+}
sub new {
my $package = shift;
return $self;
}
+# not a method
+sub undent {
+ my ($string) = @_;
+
+ my ($space) = $string =~ m/^(\s+)/;
+ $string =~ s/^$space//gm;
+
+ return($string);
+}
sub _gen_default_filedata {
my $self = shift;
- $self->add_file( 'Build.PL', <<"---" ) unless $self->{filedata}{'Build.PL'};
-use strict;
-use Module::Build;
+ # TODO maybe a public method like this (but with a better name?)
+ my $add_unless = sub {
+ my $self = shift;
+ my ($member, $data) = @_;
+ $self->add_file($member, $data) unless($self->{filedata}{$member});
+ };
+
+ $self->$add_unless('Build.PL', undent(<<" ---"));
+ use strict;
+ use Module::Build;
-my \$builder = Module::Build->new(
- module_name => '$self->{name}',
- license => 'perl',
-);
+ my \$builder = Module::Build->new(
+ module_name => '$self->{name}',
+ license => 'perl',
+ );
-\$builder->create_build_script();
----
+ \$builder->create_build_script();
+ ---
my $module_filename =
join( '/', ('lib', split(/::/, $self->{name})) ) . '.pm';
unless ( $self->{xs} ) {
- $self->add_file( $module_filename, <<"---" ) unless $self->{filedata}{$module_filename};
-package $self->{name};
+ $self->$add_unless($module_filename, undent(<<" ---"));
+ package $self->{name};
-use vars qw( \$VERSION );
-\$VERSION = '0.01';
+ use vars qw( \$VERSION );
+ \$VERSION = '0.01';
-use strict;
+ use strict;
-1;
+ 1;
-__END__
+ __END__
-=head1 NAME
+ =head1 NAME
-$self->{name} - Perl extension for blah blah blah
+ $self->{name} - Perl extension for blah blah blah
-=head1 DESCRIPTION
+ =head1 DESCRIPTION
-Stub documentation for $self->{name}.
+ Stub documentation for $self->{name}.
-=head1 AUTHOR
+ =head1 AUTHOR
-A. U. Thor, a.u.thor\@a.galaxy.far.far.away
+ A. U. Thor, a.u.thor\@a.galaxy.far.far.away
-=cut
----
+ =cut
+ ---
- $self->add_file( 't/basic.t', <<"---" ) unless $self->{filedata}{'t/basic.t'};
-use Test::More tests => 1;
-use strict;
+ $self->$add_unless('t/basic.t', undent(<<" ---"));
+ use Test::More tests => 1;
+ use strict;
-use $self->{name};
-ok 1;
----
+ use $self->{name};
+ ok 1;
+ ---
} else {
- $self->add_file( $module_filename, <<"---" ) unless $self->{filedata}{$module_filename};
-package $self->{name};
+ $self->$add_unless($module_filename, undent(<<" ---"));
+ package $self->{name};
-\$VERSION = '0.01';
+ \$VERSION = '0.01';
-require Exporter;
-require DynaLoader;
+ require Exporter;
+ require DynaLoader;
-\@ISA = qw(Exporter DynaLoader);
-\@EXPORT_OK = qw( okay );
+ \@ISA = qw(Exporter DynaLoader);
+ \@EXPORT_OK = qw( okay );
-bootstrap $self->{name} \$VERSION;
+ bootstrap $self->{name} \$VERSION;
-1;
+ 1;
-__END__
+ __END__
-=head1 NAME
+ =head1 NAME
-$self->{name} - Perl extension for blah blah blah
+ $self->{name} - Perl extension for blah blah blah
-=head1 DESCRIPTION
+ =head1 DESCRIPTION
-Stub documentation for $self->{name}.
+ Stub documentation for $self->{name}.
-=head1 AUTHOR
+ =head1 AUTHOR
-A. U. Thor, a.u.thor\@a.galaxy.far.far.away
+ A. U. Thor, a.u.thor\@a.galaxy.far.far.away
-=cut
----
+ =cut
+ ---
my $xs_filename =
join( '/', ('lib', split(/::/, $self->{name})) ) . '.xs';
- $self->add_file( $xs_filename, <<"---" ) unless $self->{filedata}{$xs_filename};
-#include "EXTERN.h"
-#include "perl.h"
-#include "XSUB.h"
-
-MODULE = $self->{name} PACKAGE = $self->{name}
-
-SV *
-okay()
- CODE:
- RETVAL = newSVpv( "ok", 0 );
- OUTPUT:
+ $self->$add_unless($xs_filename, undent(<<" ---"));
+ #include "EXTERN.h"
+ #include "perl.h"
+ #include "XSUB.h"
+
+ MODULE = $self->{name} PACKAGE = $self->{name}
+
+ SV *
+ okay()
+ CODE:
+ RETVAL = newSVpv( "ok", 0 );
+ OUTPUT:
+ RETVAL
+
+ char *
+ xs_version()
+ CODE:
+ RETVAL = XS_VERSION;
+ OUTPUT:
RETVAL
-char *
-xs_version()
- CODE:
- RETVAL = XS_VERSION;
- OUTPUT:
- RETVAL
-
-char *
-version()
- CODE:
- RETVAL = VERSION;
- OUTPUT:
- RETVAL
----
-
- $self->add_file( 't/basic.t', <<"---" ) unless $self->{filedata}{'t/basic.t'};
-use Test::More tests => 2;
-use strict;
+ char *
+ version()
+ CODE:
+ RETVAL = VERSION;
+ OUTPUT:
+ RETVAL
+ ---
-use $self->{name};
-ok 1;
+ $self->$add_unless('t/basic.t', undent(<<" ---"));
+ use Test::More tests => 2;
+ use strict;
-ok( $self->{name}::okay() eq 'ok' );
----
+ use $self->{name};
+ ok 1;
+
+ ok( $self->{name}::okay() eq 'ok' );
+ ---
}
}
$self->{pending}{remove}{$file} = 1;
}
+sub change_build_pl {
+ my ($self, $opts) = @_;
+
+ local $Data::Dumper::Terse = 1;
+ (my $args = Dumper($opts)) =~ s/^\s*\{|\}\s*$//g;
+
+ $self->change_file( 'Build.PL', undent(<<" ---") );
+ use strict;
+ use Module::Build;
+ my \$b = Module::Build->new(
+ $args
+ );
+ \$b->create_build_script();
+ ---
+}
+
sub change_file {
my $self = shift;
my $file = shift;
DistGen - Creates simple distributions for testing.
+=head1 SYNOPSIS
-=head1 DESCRIPTION
+ use DistGen;
+ my $dist = DistGen->new(dir => $tmp);
+ ...
+ $dist->add_file('t/some_test.t', $contents);
+ ...
+ $dist->regen;
+ chdir($dist->dirname) or
+ die "Cannot chdir to '@{[$dist->dirname]}': $!";
+ ...
+ $dist->clean;
+ ...
+ chdir($cwd) or die "cannot return to $cwd";
+ $dist->remove;
=head1 API
-
=head2 Constructor
=head3 new()
-Create a new distribution generator. Does not actually write the
-contents.
+Create a new object. Does not write its contents (see L</regen()>.)
+
+ my $tmp = MBTest->tmpdir;
+ my $dist = DistGen->new(
+ name => 'Foo::Bar',
+ dir => $tmp,
+ xs => 1,
+ );
+
+The parameters are as follows.
=over
=item name
The name of the module this distribution represents. The default is
-'Simple'.
+'Simple'. This should be a "Foo::Bar" (module) name, not a "Foo-Bar"
+dist name.
=item dir
-The directory in which to create the distribution directory. The
-default is File::Spec->curdir.
+The (parent) directory in which to create the distribution directory.
+The default is File::Spec->curdir. The distribution will be created
+under this according to the "dist" form of C<name> (e.g. "Foo-Bar".)
=item xs
-Generates an XS based module.
+If true, generates an XS based module.
=back
-
=head2 Manipulating the Distribution
-=head3 regen( [OPTIONS] )
-
-Regenerate all files that are missing or that have changed. If the
-optional C<clean> argument is given, it also removes any extraneous
-files that do not belong to the distribution.
+These methods immediately affect the filesystem.
-=over
+=head3 regen()
-=item clean
+Regenerate all missing or changed files.
-When true, removes any files not part of the distribution while
-regenerating.
+ $dist->regen(clean => 1);
-=back
+If the optional C<clean> argument is given, it also removes any
+extraneous files that do not belong to the distribution.
=head3 clean()
Removes any files that are not part of the distribution.
-=head3 revert( [$filename] )
+ $dist->clean;
+
+=begin TODO
+
+=head3 revert()
[Unimplemented] Returns the object to its initial state, or given a
$filename it returns that file to it's initial state if it is one of
the built-in files.
-=head3 remove()
+ $dist->revert;
+ $dist->revert($filename);
+
+=end TODO
-Removes the complete distribution.
+=head3 remove()
+Removes the entire distribution directory.
=head2 Editing Files
-Note that all ${filename}s should be specified with unix-style paths,
+Note that C<$filename> should always be specified with unix-style paths,
and are relative to the distribution root directory. Eg 'lib/Module.pm'
-=head3 add_file( $filename, $content )
+No filesystem action is performed until the distribution is regenerated.
+
+=head3 add_file()
+
+Add a $filename containing $content to the distribution.
+
+ $dist->add_file( $filename, $content );
-Add a $filename containg $content to the distribution. No action is
-performed until the distribution is regenerated.
+=head3 remove_file()
-=head3 remove_file( $filename )
+Removes C<$filename> from the distribution.
-Removes $filename from the distribution. No action is performed until
-the distribution is regenerated.
+ $dist->remove_file( $filename );
-=head3 change_file( $filename, $content )
+=head3 change_file()
Changes the contents of $filename to $content. No action is performed
until the distribution is regenerated.
+ $dist->change_file( $filename, $content );
=head2 Properties
=head3 dirname()
-Returns the directory name where the distribution is created.
+Returns the directory where the distribution is created.
+
+ $dist->dirname; # e.g. t/_tmp/Simple
+
+=head2 Functions
+
+=head3 undent()
+
+Removes leading whitespace from a multi-line string according to the
+amount of whitespace on the first line.
+
+ my $string = undent(" foo(\n bar => 'baz'\n )");
+ $string eq "foo(
+ bar => 'baz'
+ )";
=cut
+
+# vim:ts=2:sw=2:et:sta
use strict;
use File::Spec;
+use File::Path ();
BEGIN {
# Make sure none of our tests load the users ~/.modulebuildrc file
# Test::More" in the test script.
my $t_lib = File::Spec->catdir('t', 'bundled');
- if (!$ENV{PERL_CORE}) {
+ unless ($ENV{PERL_CORE}) {
push @INC, $t_lib; # Let user's installed version override
} else {
# We change directories, so expand @INC to absolute paths
use Exporter;
use Test::More;
use Config;
+use Cwd ();
# We pass everything through to Test::More
use vars qw($VERSION @ISA @EXPORT %EXPORT_TAGS $TODO);
# We have a few extra exports, but Test::More has a special import()
# that won't take extra additions.
-my @extra_exports = qw(stdout_of stderr_of slurp find_in_path check_compiler have_module);
+my @extra_exports = qw(
+ stdout_of
+ stderr_of
+ stdout_stderr_of
+ slurp
+ find_in_path
+ check_compiler
+ have_module
+);
push @EXPORT, @extra_exports;
__PACKAGE__->export(scalar caller, @extra_exports);
+# XXX ^-- that should really happen in import()
+########################################################################
+
+{ # Setup a temp directory if it doesn't exist
+ my $cwd = Cwd::cwd;
+ my $tmp = File::Spec->catdir( $cwd, 't', '_tmp.' . $$);
+ mkdir $tmp, 0777 unless -d $tmp;
+
+ sub tmpdir { $tmp }
+ END {
+ if(-d $tmp) {
+ File::Path::rmtree($tmp) or warn "cannot clean dir '$tmp'";
+ }
+ }
+}
+########################################################################
+{ # backwards compatible temp filename recipe adapted from perlfaq
+ my $tmp_count = 0;
+ my $tmp_base_name = sprintf("%d-%d", $$, time());
+ sub temp_file_name {
+ sprintf("%s-%04d", $tmp_base_name, ++$tmp_count)
+ }
+}
+########################################################################
sub save_handle {
my ($handle, $subr) = @_;
- my $outfile = 'save_out';
+ my $outfile = temp_file_name();
local *SAVEOUT;
- open SAVEOUT, ">&" . fileno($handle) or die "Can't save output handle: $!";
+ open SAVEOUT, ">&" . fileno($handle)
+ or die "Can't save output handle: $!";
open $handle, "> $outfile" or die "Can't create $outfile: $!";
eval {$subr->()};
sub stdout_of { save_handle(\*STDOUT, @_) }
sub stderr_of { save_handle(\*STDERR, @_) }
+sub stdout_stderr_of {
+ my $subr = shift;
+ my ($stdout, $stderr);
+ $stdout = stdout_of ( sub {
+ $stderr = stderr_of( $subr )
+ });
+ return ($stdout, $stderr);
+}
sub slurp {
my $fh = IO::File->new($_[0]) or die "Can't open $_[0]: $!";
return scalar <$fh>;
}
+# Some extensions we should know about if we're looking for executables
sub exe_exts {
- # Some extensions we should know about if we're looking for executables
if ($^O eq 'MSWin32') {
return split($Config{path_sep}, $ENV{PATHEXT} || '.com;.exe;.bat');
}
1;
+# vim:ts=2:sw=2:et:sta
use Cwd ();
my $cwd = Cwd::cwd;
-my $tmp = File::Spec->catdir( $cwd, 't', '_tmp' );
+my $tmp = MBTest->tmpdir;
use DistGen;
my $dist = DistGen->new( dir => $tmp );
chdir( $dist->dirname ) or die "Can't chdir to '@{[$dist->dirname]}': $!";
use File::Spec::Functions qw( catdir );
-my $destdir = catdir($cwd, 't', 'install_test');
+my $destdir = catdir($cwd, 't', 'install_test.' . $$);
my $mb = Module::Build->new(
next;
}
- my $to = File::Spec->catfile('blib', ($from =~ /^[\.\/\[]*lib/ ? 'libdoc' : 'bindoc'), $v);
+ my $to = File::Spec->catfile('blib', ($from =~ /^lib/ ? 'libdoc' : 'bindoc'), $v);
ok $mb->contains_pod($from), "$from should contain POD";
ok -e $to, "Created $to manpage";
}
use strict;
use lib $ENV{PERL_CORE} ? '../lib/Module/Build/t/lib' : 't/lib';
-use MBTest tests => 47;
+use MBTest tests => 49;
use Cwd ();
my $cwd = Cwd::cwd;
-my $tmp = File::Spec->catdir( $cwd, 't', '_tmp' );
+my $tmp = MBTest->tmpdir;
use Module::Build;
use Module::Build::ConfigData;
-my $has_YAML = Module::Build::ConfigData->feature('YAML_support');
+
+my %metadata =
+ (
+ module_name => 'Simple',
+ dist_version => '3.14159265',
+ dist_author => [ 'Simple Simon <ss\@somewhere.priv>' ],
+ dist_abstract => 'Something interesting',
+ license => 'perl',
+ meta_add => {
+ keywords => [qw(super duper something)],
+ resources => {homepage => 'http://foo.example.com'},
+ },
+ );
use DistGen;
my $dist = DistGen->new( dir => $tmp );
-$dist->change_file( 'Build.PL', <<"---" );
-
-my \$builder = Module::Build->new(
- module_name => '@{[$dist->name]}',
- dist_version => '3.14159265',
- dist_author => [ 'Simple Simon <ss\@somewhere.priv>' ],
- dist_abstract => 'Something interesting',
- license => 'perl',
-);
-
-\$builder->create_build_script();
----
+$dist->change_build_pl( \%metadata );
$dist->regen;
my $simple_file = 'lib/Simple.pm';
#
# Test for valid META.yml
-SKIP: {
- skip( 'YAML_support feature is not enabled', 8 ) unless $has_YAML;
-
- require YAML;
- require YAML::Node;
- my $node = YAML::Node->new({});
- $node = $mb->prepare_metadata( $node );
+{
+ my $node = $mb->prepare_metadata( {} );
# exists() doesn't seem to work here
- ok defined( $node->{name} ), "'name' field present in META.yml";
- ok defined( $node->{version} ), "'version' field present in META.yml";
- ok defined( $node->{abstract} ), "'abstract' field present in META.yml";
- ok defined( $node->{author} ), "'author' field present in META.yml";
- ok defined( $node->{license} ), "'license' field present in META.yml";
- ok defined( $node->{generated_by} ),
- "'generated_by' field present in META.yml";
+ is $node->{name}, $metadata{module_name};
+ is $node->{version}, $metadata{dist_version};
+ is $node->{abstract}, $metadata{dist_abstract};
+ is_deeply $node->{author}, $metadata{dist_author};
+ is $node->{license}, $metadata{license};
+ like $node->{generated_by}, qr{Module::Build};
ok defined( $node->{'meta-spec'}{version} ),
"'meta-spec' -> 'version' field present in META.yml";
ok defined( $node->{'meta-spec'}{url} ),
"'meta-spec' -> 'url' field present in META.yml";
-
- # TODO : find a way to test for failure when above fields are not present
+ is_deeply $node->{keywords}, $metadata{meta_add}{keywords};
+ is_deeply $node->{resources}, $metadata{meta_add}{resources};
}
$dist->clean;
use Cwd ();
my $cwd = Cwd::cwd;
-my $tmp = File::Spec->catdir( $cwd, 't', '_tmp' );
+my $tmp = MBTest->tmpdir;
use Module::Build;
use Module::Build::ConfigData;
my $dist = DistGen->new( dir => $tmp );
-$dist->change_file( 'Build.PL', <<"---" );
-use Module::Build;
-my \$builder = Module::Build->new(
- module_name => '@{[$dist->name]}',
+$dist->change_build_pl
+({
+ module_name => $dist->name,
dist_version => '3.14159265',
license => 'perl',
create_readme => 1,
-);
-
-\$builder->create_build_script();
----
+});
$dist->regen;
chdir( $dist->dirname ) or die "Can't chdir to '@{[$dist->dirname]}': $!";
use Cwd ();
my $cwd = Cwd::cwd;
-my $tmp = File::Spec->catdir( $cwd, 't', '_tmp' );
+my $tmp = MBTest->tmpdir;
use DistGen;
my $dist = DistGen->new( dir => $tmp );
use Cwd ();
my $cwd = Cwd::cwd;
-my $tmp = File::Spec->catdir( $cwd, 't', '_tmp' );
+my $tmp = MBTest->tmpdir;
use DistGen;
my $dist = DistGen->new( dir => $tmp );
use Cwd ();
my $cwd = Cwd::cwd;
-my $tmp = File::Spec->catdir( $cwd, 't', '_tmp' );
+my $tmp = MBTest->tmpdir;
use DistGen;
my $dist = DistGen->new( dir => $tmp );
use Cwd ();
my $cwd = Cwd::cwd;
-my $tmp = File::Spec->catdir( $cwd, 't', '_tmp' );
+my $tmp = MBTest->tmpdir;
use DistGen;
=cut
---
-$dist->change_file( 'Build.PL', <<"---" );
-
-my \$build = new Module::Build(
- module_name => @{[$dist->name]},
+$dist->change_build_pl
+({
+ module_name => $dist->name,
license => 'perl',
scripts => [ 'hello' ],
-);
-
-\$build->create_build_script;
----
+});
$dist->regen;
chdir( $dist->dirname ) or die "Can't chdir to '@{[$dist->dirname]}': $!";
use Cwd ();
my $cwd = Cwd::cwd;
-my $tmp = File::Spec->catdir( $cwd, 't', '_tmp' );
+my $tmp = MBTest->tmpdir;
use DistGen;
my $dist = DistGen->new( dir => $tmp );
$dist->remove_file( 't/basic.t' );
-$dist->change_file( 'Build.PL', <<'---' );
-use Module::Build;
-
-my $build = new Module::Build(
+$dist->change_build_pl
+({
module_name => 'Simple',
scripts => [ 'script' ],
license => 'perl',
requires => { 'File::Spec' => 0 },
-);
-$build->create_build_script;
----
+});
+
$dist->add_file( 'script', <<'---' );
#!perl -w
print "Hello, World!\n";
my $blib_script = File::Spec->catfile( qw( blib script script ) );
ok -e $blib_script;
- SKIP: {
+ SKIP: {
skip("We do not rewrite shebang on VMS", 1) if $^O eq 'VMS';
- my $fh = IO::File->new($blib_script);
- my $first_line = <$fh>;
- isnt $first_line, "#!perl -w\n", "should rewrite the shebang line";
+ my $fh = IO::File->new($blib_script);
+ my $first_line = <$fh>;
+ isnt $first_line, "#!perl -w\n", "should rewrite the shebang line";
}
}
---
$dist = DistGen->new( dir => $tmp );
- $dist->change_file( 'Build.PL', <<'---' );
-use Module::Build;
-my $build = new Module::Build(
- module_name => 'Simple',
- scripts => [ 'bin/script.bat' ],
- license => 'perl',
-);
-$build->create_build_script;
----
+ $dist->change_build_pl({
+ module_name => 'Simple',
+ scripts => [ 'bin/script.bat' ],
+ license => 'perl',
+ });
+
$dist->add_file( 'bin/script.bat', $script_data );
$dist->regen;
use Cwd ();
my $cwd = Cwd::cwd;
-my $tmp = File::Spec->catdir( $cwd, 't', '_tmp' );
+my $tmp = MBTest->tmpdir;
use DistGen;
use Cwd ();
my $cwd = Cwd::cwd();
-my $tmp = File::Spec->catdir($cwd, 't', '_tmp');
+my $tmp = MBTest->tmpdir;
use DistGen;
use strict;
use lib $ENV{PERL_CORE} ? '../lib/Module/Build/t/lib' : 't/lib';
-use MBTest tests => 14;
+use MBTest tests => 15;
use Cwd ();
my $cwd = Cwd::cwd;
-my $tmp = File::Spec->catdir( $cwd, 't', '_tmp' );
+my $tmp = MBTest->tmpdir;
use DistGen;
my $dist = DistGen->new( dir => $tmp );
}
-{
- local $ENV{HOME} = 'home';
+my $p = 'install_base';
- my $mb;
-
- $mb = run_sample( install_base => '~' );
- is( $mb->install_base, $ENV{HOME} );
-
- $mb = run_sample( install_base => '~/foo' );
- is( $mb->install_base, "$ENV{HOME}/foo" );
+SKIP: {
+ my $home = $ENV{HOME} ? $ENV{HOME} : undef;
+ unless (defined $home) {
+ my @info = eval { getpwuid $> };
+ skip "No home directory for tilde-expansion tests", 14 if $@;
+ $home = $info[7];
+ }
- $mb = run_sample( install_base => '~~' );
- is( $mb->install_base, '~~' );
+ is( run_sample( $p => '~' )->$p(), $home );
- TODO: {
- local $TODO = "Not handling spaces in _detildefy() properly yet";
+ is( run_sample( $p => '~/foo' )->$p(), "$home/foo" );
- $mb = run_sample( install_base => '~ foo' );
- is( $mb->install_base, '~ foo' );
+ is( run_sample( $p => '~~' )->$p(), '~~' );
- # glob() doesn't work on non-existent paths with spaces
- $mb = run_sample( install_base => '~/ foo' );
- is( $mb->install_base, "$ENV{HOME}/ foo" );
+ is( run_sample( $p => '~ foo' )->$p(), '~ foo' );
- $mb = run_sample( install_base => '~/fo o' );
- is( $mb->install_base, "$ENV{HOME}/fo o" );
- }
+ is( run_sample( $p => '~/ foo')->$p(), "$home/ foo" );
+
+ is( run_sample( $p => '~/fo o')->$p(), "$home/fo o" );
- $mb = run_sample( install_base => 'foo~' );
- is( $mb->install_base, 'foo~' );
+ is( run_sample( $p => 'foo~' )->$p(), 'foo~' );
- $mb = run_sample( prefix => '~' );
- is( $mb->prefix, $ENV{HOME} );
+ is( run_sample( prefix => '~' )->prefix,
+ $home );
- $mb = run_sample( install_path => { html => '~/html',
- lib => '~/lib' }
- );
- is( $mb->install_destination('lib'), "$ENV{HOME}/lib" );
+ my $mb = run_sample( install_path => { html => '~/html',
+ lib => '~/lib' }
+ );
+ is( $mb->install_destination('lib'), "$home/lib" );
# 'html' is translated to 'binhtml' & 'libhtml'
- is( $mb->install_destination('binhtml'), "$ENV{HOME}/html" );
- is( $mb->install_destination('libhtml'), "$ENV{HOME}/html" );
+ is( $mb->install_destination('binhtml'), "$home/html" );
+ is( $mb->install_destination('libhtml'), "$home/html" );
$mb = run_sample( install_path => { lib => '~/lib' } );
- is( $mb->install_destination('lib'), "$ENV{HOME}/lib" );
+ is( $mb->install_destination('lib'), "$home/lib" );
$mb = run_sample( destdir => '~' );
- is( $mb->destdir, $ENV{HOME} );
+ is( $mb->destdir, $home );
+
+ $mb->$p('~');
+ is( $mb->$p(), '~', 'API does not expand tildes' );
+}
- $mb->install_base('~');
- is( $mb->install_base, '~', 'API does not expand tildes' );
+# Again, with named users
+SKIP: {
+ my @info = eval { getpwuid $> };
+ skip "No home directory for tilde-expansion tests", 1 if $@;
+ my ($me, $home) = @info[0,7];
+
+ is( run_sample( $p => "~$me/foo")->$p(), "$home/foo" );
}
use Cwd ();
my $cwd = Cwd::cwd;
-my $tmp = File::Spec->catdir( $cwd, 't', '_tmp' );
+my $tmp = MBTest->tmpdir;
use DistGen;
my $dist = DistGen->new( dir => $tmp );
use Cwd ();
my $cwd = Cwd::cwd;
-my $tmp = File::Spec->catdir( $cwd, 't', '_tmp' );
+my $tmp = MBTest->tmpdir;
use DistGen;
my $dist = DistGen->new( dir => $tmp, xs => 1 );
# Try a XS distro with a deep namespace
-$dist = DistGen->new( name => 'Simple::With::Deep::Name',
+$dist = DistGen->new( name => 'Simple::With::Deep::Namespace',
dir => $tmp, xs => 1 );
$dist->regen;
chdir( $dist->dirname ) or die "Can't chdir to '@{[$dist->dirname]}': $!";
$dist->remove_file('lib/Dist-Name.pm');
$dist->remove_file('lib/Dist-Name.xs');
-$dist->change_file('Build.PL', <<"---");
-use strict;
-use Module::Build;
-
-my \$builder = Module::Build->new(
+$dist->change_build_pl
+ ({
dist_name => 'Dist-Name',
dist_version_from => 'Simple.pm',
pm_files => { 'Simple.pm' => 'lib/Simple.pm' },
xs_files => { 'Simple.xs' => 'lib/Simple.xs' },
-);
+ });
-\$builder->create_build_script();
----
$dist->add_file('Simple.xs', <<"---");
#include "EXTERN.h"
#include "perl.h"