Update ExtUtils-MakeMaker to CPAN version 7.18
authorChris 'BinGOs' Williams <chris@bingosnet.co.uk>
Tue, 24 May 2016 10:39:59 +0000 (11:39 +0100)
committerChris 'BinGOs' Williams <chris@bingosnet.co.uk>
Tue, 24 May 2016 10:43:37 +0000 (11:43 +0100)
  [DELTA]

7.18  Mon May 23 15:55:26 BST 2016

    No changes since 7.17_03

7.17_03 Wed May 11 18:22:06 BST 2016

    Dist fixes:
    - remove build_requires on ourselves

7.17_02 Mon May  9 23:55:09 BST 2016

    Bug fixes:
    - Resolve a regression in c_o with trailing spaces

7.17_01 Mon May  9 20:02:02 BST 2016

    Test fixes:
    - Resolve issues with tests when running in core

7.16  Sat May  7 10:13:05 BST 2016

    No changes since 7.15_03

7.15_03 Sun May  1 14:13:44 BST 2016

    Bug fixes:
    - lazy load Time::HiRes in ExtUtils::Command::MM
    - fix 5.6 compat by removing indexed sprintf

7.15_02 Thu Apr 28 12:54:23 BST 2016

    Bug fixes:
    - Fix regression with small fractional numeric versions

7.15_01 Wed Apr 27 19:13:46 BST 2016

    Bug fixes:
    - Fix regression with SKIP and dynamic and static targets

7.14  Sun Apr 24 13:53:33 BST 2016

  No changes since 7.13_01

7.13_01 Sat Apr 23 16:41:20 BST 2016

    Bug fixes:
    - Make dynamic depend on config again, fixes issues with Inline

7.12 Tue Apr 19 12:24:41 BST 2016

    Enhancements:
    - version ranges are now supported for PREREQS, etc.
    - Metadata is now represented internally as Meta Spec 2.0
    - ExtUtils::Command has been re-incorporated at 1.19 of that module
    - Refactored XS handling
    - XSMULTI=>1 - put multiple *.xs under lib, it "just works" and XSBUILD
      for refined control of XSMULTI
    - can do "make test" without first doing "make"

    Bug fixes:
    - Handle new warnings from File::Path
    - Resolve RT#106572 specifying AUTHOR via command-line is broken
    - Warning on missing TEST_REQUIRES and CONFIGURE_REQUIRES
    - Sanitise make_type on Win32
    - Cygwin rebase fixes
    - Makefile starting comments reflect decoded @ARGV, not raw
    - Add various targets to .PHONY to avoid disk IO with dmake
    - Fixed race condition in realclean
    - improve static-build lib detection
    - Eliminate non-error STDERR
    - Make WriteEmptyMakefile Makefile functional when called in subdir
    - manifypods fixes
    - perllocal.pod generation "Perl in Space" fix
    - PASTHRU fixes
    - Fix distsignature dependencies for parallel make
    - Check exit status for commands in "make ci" target
    - Less noisey output during building sub-modules
    - Fix dos2unix() on Windows
    - stop makeaperl from polluting @ARGV in cases where ARGV contains args with spaces
    - Fix regression when both test.pl and t/*.t are present
    - Refactored internals to remove DirHandle usage
    - MM_Unix::find_perl() dont repeatedly stat the same path in a loop
    - No longer repeatedly attempt to load CPAN::Meta if it is now available

    VMS fixes:
    - Made MM_VMS::oneline build continuation lines properly
    - Implemented XSMULTI and XSBUILD
    - Resurrect PASTHRU on VMS
    - make_macro should handle multiple macros
    - Fix regression with File::Spec changes in previous release

    Win32 fixes:
    - t/echo.t needs SHELL env for Win32 gmake

    Dist fixes:
    - Made %ExtraPrereqs match bundled prereqs
    - Included MANIFEST.SKIP from ExtUtils::Manifest
    - The bundled Encode::Locale has been updated to 1.04

    Test fixes:
    - test PL_FILES of a "module"
    - Various tests no longer require a separate .pm file for testing
    - Support v5.6.1 in various tests
    - test static build if $ENV{AUTHOR_TESTING}
    - XS tests now pluggable
    - test for "Perl in Space"

    Doc fixes:
    - better document for PL_FILES, oneliner method
    - FAQ updated

86 files changed:
MANIFEST
Porting/Maintainers.pl
cpan/ExtUtils-MakeMaker/lib/ExtUtils/Command.pm
cpan/ExtUtils-MakeMaker/lib/ExtUtils/Command/MM.pm
cpan/ExtUtils-MakeMaker/lib/ExtUtils/Liblist.pm
cpan/ExtUtils-MakeMaker/lib/ExtUtils/Liblist/Kid.pm
cpan/ExtUtils-MakeMaker/lib/ExtUtils/MM.pm
cpan/ExtUtils-MakeMaker/lib/ExtUtils/MM_AIX.pm
cpan/ExtUtils-MakeMaker/lib/ExtUtils/MM_Any.pm
cpan/ExtUtils-MakeMaker/lib/ExtUtils/MM_BeOS.pm
cpan/ExtUtils-MakeMaker/lib/ExtUtils/MM_Cygwin.pm
cpan/ExtUtils-MakeMaker/lib/ExtUtils/MM_DOS.pm
cpan/ExtUtils-MakeMaker/lib/ExtUtils/MM_Darwin.pm
cpan/ExtUtils-MakeMaker/lib/ExtUtils/MM_MacOS.pm
cpan/ExtUtils-MakeMaker/lib/ExtUtils/MM_NW5.pm
cpan/ExtUtils-MakeMaker/lib/ExtUtils/MM_OS2.pm
cpan/ExtUtils-MakeMaker/lib/ExtUtils/MM_QNX.pm
cpan/ExtUtils-MakeMaker/lib/ExtUtils/MM_UWIN.pm
cpan/ExtUtils-MakeMaker/lib/ExtUtils/MM_Unix.pm
cpan/ExtUtils-MakeMaker/lib/ExtUtils/MM_VMS.pm
cpan/ExtUtils-MakeMaker/lib/ExtUtils/MM_VOS.pm
cpan/ExtUtils-MakeMaker/lib/ExtUtils/MM_Win32.pm
cpan/ExtUtils-MakeMaker/lib/ExtUtils/MM_Win95.pm
cpan/ExtUtils-MakeMaker/lib/ExtUtils/MY.pm
cpan/ExtUtils-MakeMaker/lib/ExtUtils/MakeMaker.pm
cpan/ExtUtils-MakeMaker/lib/ExtUtils/MakeMaker/Config.pm
cpan/ExtUtils-MakeMaker/lib/ExtUtils/MakeMaker/FAQ.pod
cpan/ExtUtils-MakeMaker/lib/ExtUtils/MakeMaker/Locale.pm
cpan/ExtUtils-MakeMaker/lib/ExtUtils/MakeMaker/Tutorial.pod
cpan/ExtUtils-MakeMaker/lib/ExtUtils/MakeMaker/version.pm
cpan/ExtUtils-MakeMaker/lib/ExtUtils/MakeMaker/version/regex.pm
cpan/ExtUtils-MakeMaker/lib/ExtUtils/Mkbootstrap.pm
cpan/ExtUtils-MakeMaker/lib/ExtUtils/Mksymlists.pm
cpan/ExtUtils-MakeMaker/lib/ExtUtils/testlib.pm
cpan/ExtUtils-MakeMaker/t/01perl_bugs.t
cpan/ExtUtils-MakeMaker/t/02-xsdynamic.t [new file with mode: 0644]
cpan/ExtUtils-MakeMaker/t/03-xsstatic.t [new file with mode: 0644]
cpan/ExtUtils-MakeMaker/t/FIRST_MAKEFILE.t
cpan/ExtUtils-MakeMaker/t/INST.t
cpan/ExtUtils-MakeMaker/t/INSTALL_BASE.t
cpan/ExtUtils-MakeMaker/t/INST_PREFIX.t
cpan/ExtUtils-MakeMaker/t/MM_Cygwin.t
cpan/ExtUtils-MakeMaker/t/MM_NW5.t
cpan/ExtUtils-MakeMaker/t/MM_OS2.t
cpan/ExtUtils-MakeMaker/t/MM_Unix.t
cpan/ExtUtils-MakeMaker/t/MM_Win32.t
cpan/ExtUtils-MakeMaker/t/MakeMaker_Parameters.t
cpan/ExtUtils-MakeMaker/t/Mkbootstrap.t
cpan/ExtUtils-MakeMaker/t/PL_FILES.t
cpan/ExtUtils-MakeMaker/t/WriteEmptyMakefile.t
cpan/ExtUtils-MakeMaker/t/basic.t
cpan/ExtUtils-MakeMaker/t/build_man.t
cpan/ExtUtils-MakeMaker/t/cd.t
cpan/ExtUtils-MakeMaker/t/dir_target.t
cpan/ExtUtils-MakeMaker/t/echo.t
cpan/ExtUtils-MakeMaker/t/fixin.t
cpan/ExtUtils-MakeMaker/t/hints.t
cpan/ExtUtils-MakeMaker/t/installed_file.t
cpan/ExtUtils-MakeMaker/t/lib/MakeMaker/Test/Setup/BFD.pm
cpan/ExtUtils-MakeMaker/t/lib/MakeMaker/Test/Setup/MPV.pm [deleted file]
cpan/ExtUtils-MakeMaker/t/lib/MakeMaker/Test/Setup/PL_FILES.pm [deleted file]
cpan/ExtUtils-MakeMaker/t/lib/MakeMaker/Test/Setup/Problem.pm [deleted file]
cpan/ExtUtils-MakeMaker/t/lib/MakeMaker/Test/Setup/Recurs.pm [deleted file]
cpan/ExtUtils-MakeMaker/t/lib/MakeMaker/Test/Setup/SAS.pm [deleted file]
cpan/ExtUtils-MakeMaker/t/lib/MakeMaker/Test/Setup/Unicode.pm [deleted file]
cpan/ExtUtils-MakeMaker/t/lib/MakeMaker/Test/Setup/XS.pm
cpan/ExtUtils-MakeMaker/t/lib/MakeMaker/Test/Utils.pm
cpan/ExtUtils-MakeMaker/t/meta_convert.t
cpan/ExtUtils-MakeMaker/t/metafile_data.t
cpan/ExtUtils-MakeMaker/t/min_perl_version.t
cpan/ExtUtils-MakeMaker/t/parse_abstract.t
cpan/ExtUtils-MakeMaker/t/parse_version.t
cpan/ExtUtils-MakeMaker/t/pm_to_blib.t
cpan/ExtUtils-MakeMaker/t/postamble.t
cpan/ExtUtils-MakeMaker/t/prereq.t
cpan/ExtUtils-MakeMaker/t/prereq_print.t
cpan/ExtUtils-MakeMaker/t/problems.t
cpan/ExtUtils-MakeMaker/t/prompt.t
cpan/ExtUtils-MakeMaker/t/recurs.t
cpan/ExtUtils-MakeMaker/t/several_authors.t
cpan/ExtUtils-MakeMaker/t/test_boilerplate.t
cpan/ExtUtils-MakeMaker/t/unicode.t
cpan/ExtUtils-MakeMaker/t/vstrings.t
cpan/ExtUtils-MakeMaker/t/writemakefile_args.t
cpan/ExtUtils-MakeMaker/t/xs.t [deleted file]
t/porting/customized.dat

index cb53872..5e9eb7b 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -1089,6 +1089,8 @@ cpan/ExtUtils-MakeMaker/lib/ExtUtils/MY.pm                        MakeMaker user override class
 cpan/ExtUtils-MakeMaker/lib/ExtUtils/testlib.pm                        Fixes up @INC to use just-built extension
 cpan/ExtUtils-MakeMaker/t/00compile.t                          See if MakeMaker modules compile
 cpan/ExtUtils-MakeMaker/t/01perl_bugs.t
+cpan/ExtUtils-MakeMaker/t/02-xsdynamic.t
+cpan/ExtUtils-MakeMaker/t/03-xsstatic.t
 cpan/ExtUtils-MakeMaker/t/arch_check.t                         Test MakeMaker's arch_check()
 cpan/ExtUtils-MakeMaker/t/backwards.t                          Check MakeMaker's backwards compatibility
 cpan/ExtUtils-MakeMaker/t/basic.t                              See if MakeMaker can build a module
@@ -1111,12 +1113,6 @@ cpan/ExtUtils-MakeMaker/t/is_of_type.t                           Test for ExtUtils::MakeMaker
 cpan/ExtUtils-MakeMaker/t/Liblist.t                            See if ExtUtils::Liblist works
 cpan/ExtUtils-MakeMaker/t/lib/MakeMaker/Test/NoXS.pm           MakeMaker test utilities
 cpan/ExtUtils-MakeMaker/t/lib/MakeMaker/Test/Setup/BFD.pm      MakeMaker test utilities
-cpan/ExtUtils-MakeMaker/t/lib/MakeMaker/Test/Setup/MPV.pm      MakeMaker test utilities
-cpan/ExtUtils-MakeMaker/t/lib/MakeMaker/Test/Setup/PL_FILES.pm MakeMaker test utilities
-cpan/ExtUtils-MakeMaker/t/lib/MakeMaker/Test/Setup/Problem.pm  MakeMaker test utilities
-cpan/ExtUtils-MakeMaker/t/lib/MakeMaker/Test/Setup/Recurs.pm   MakeMaker test utilities
-cpan/ExtUtils-MakeMaker/t/lib/MakeMaker/Test/Setup/SAS.pm      MakeMaker test utilities
-cpan/ExtUtils-MakeMaker/t/lib/MakeMaker/Test/Setup/Unicode.pm
 cpan/ExtUtils-MakeMaker/t/lib/MakeMaker/Test/Setup/XS.pm       MakeMaker test utilities
 cpan/ExtUtils-MakeMaker/t/lib/MakeMaker/Test/Utils.pm          MakeMaker test utilities
 cpan/ExtUtils-MakeMaker/t/lib/TieIn.pm                         Testing library for dummy input handles
@@ -1167,7 +1163,6 @@ cpan/ExtUtils-MakeMaker/t/VERSION_FROM.t                  See if MakeMaker's VERSION_FROM works
 cpan/ExtUtils-MakeMaker/t/vstrings.t
 cpan/ExtUtils-MakeMaker/t/WriteEmptyMakefile.t                 See if WriteEmptyMakefile works
 cpan/ExtUtils-MakeMaker/t/writemakefile_args.t                 See if WriteMakefile works
-cpan/ExtUtils-MakeMaker/t/xs.t                                 Part of MakeMaker's test suite
 cpan/ExtUtils-Manifest/lib/ExtUtils/Manifest.pm                        Utilities to write MANIFEST files
 cpan/ExtUtils-Manifest/lib/ExtUtils/MANIFEST.SKIP              The default MANIFEST.SKIP
 cpan/ExtUtils-Manifest/t/Manifest.t                            See if ExtUtils::Manifest works
index d5d673b..369b3f3 100755 (executable)
@@ -464,7 +464,7 @@ use File::Glob qw(:case);
     },
 
     'ExtUtils::MakeMaker' => {
-        'DISTRIBUTION' => 'BINGOS/ExtUtils-MakeMaker-7.10.tar.gz',
+        'DISTRIBUTION' => 'BINGOS/ExtUtils-MakeMaker-7.18.tar.gz',
         'FILES'        => q[cpan/ExtUtils-MakeMaker],
         'EXCLUDED'     => [
             qr{^t/lib/Test/},
@@ -476,48 +476,6 @@ use File::Glob qw(:case);
             'README.packaging',
             'lib/ExtUtils/MakeMaker/version/vpp.pm',
         ],
-        # Upstreamed as https://github.com/Perl-Toolchain-Gang/ExtUtils-MakeMaker/commit/ede9ea4a
-        'CUSTOMIZED'   => [
-            qq[lib/ExtUtils/MakeMaker.pm],
-            qq[t/prereq.t],
-            qq[t/vstrings.t],
-        # Upstreamed as https://github.com/Perl-Toolchain-Gang/ExtUtils-MakeMaker/commit/dd1e236ab
-            qq[lib/ExtUtils/MM_VMS.pm],
-        # Not yet submitted
-            qq[t/lib/MakeMaker/Test/NoXS.pm],
-        # Backported commits from upstream
-            qw(lib/ExtUtils/Command/MM.pm
-               lib/ExtUtils/Liblist.pm
-               lib/ExtUtils/Liblist/Kid.pm
-               lib/ExtUtils/MM.pm
-               lib/ExtUtils/MM_AIX.pm
-               lib/ExtUtils/MM_Any.pm
-               lib/ExtUtils/MM_BeOS.pm
-               lib/ExtUtils/MM_Cygwin.pm
-               lib/ExtUtils/MM_DOS.pm
-               lib/ExtUtils/MM_Darwin.pm
-               lib/ExtUtils/MM_MacOS.pm
-               lib/ExtUtils/MM_NW5.pm
-               lib/ExtUtils/MM_OS2.pm
-               lib/ExtUtils/MM_QNX.pm
-               lib/ExtUtils/MM_UWIN.pm
-               lib/ExtUtils/MM_Unix.pm
-               lib/ExtUtils/MM_VOS.pm
-               lib/ExtUtils/MM_Win32.pm
-               lib/ExtUtils/MM_Win95.pm
-               lib/ExtUtils/MY.pm
-               lib/ExtUtils/MakeMaker/Config.pm
-               lib/ExtUtils/MakeMaker/FAQ.pod
-               lib/ExtUtils/MakeMaker/Tutorial.pod
-               lib/ExtUtils/MakeMaker/version.pm
-               lib/ExtUtils/MakeMaker/version/regex.pm
-               lib/ExtUtils/Mkbootstrap.pm
-               lib/ExtUtils/Mksymlists.pm
-               lib/ExtUtils/testlib.pm
-               t/cd.t
-               t/echo.t
-               ),
-        ],
     },
 
     'ExtUtils::Manifest' => {
index ba79592..98395d2 100644 (file)
@@ -7,7 +7,7 @@ use vars qw(@ISA @EXPORT @EXPORT_OK $VERSION);
 @ISA       = qw(Exporter);
 @EXPORT    = qw(cp rm_f rm_rf mv cat eqtime mkpath touch test_f test_d chmod
                 dos2unix);
-$VERSION = '7.10';
+$VERSION = '7.18';
 $VERSION = eval $VERSION;
 
 my $Is_VMS   = $^O eq 'VMS';
@@ -347,6 +347,7 @@ sub dos2unix {
        open ORIG, $_ or do { warn "dos2unix can't open $_: $!"; return };
        open TEMP, ">$temp" or
            do { warn "dos2unix can't create .dos2unix_tmp: $!"; return };
+        binmode ORIG; binmode TEMP;
         while (my $line = <ORIG>) {
             $line =~ s/\015\012/\012/g;
             print TEMP $line;
index 9184471..d9fbb5d 100644 (file)
@@ -10,14 +10,20 @@ our @ISA = qw(Exporter);
 
 our @EXPORT  = qw(test_harness pod2man perllocal_install uninstall
                   warn_if_old_packlist test_s cp_nonempty);
-our $VERSION = '7.10_01';
+our $VERSION = '7.18';
+$VERSION = eval $VERSION;
 
 my $Is_VMS = $^O eq 'VMS';
 
-eval {  require Time::HiRes; die unless Time::HiRes->can("stat"); };
-*mtime = $@ ?
- sub { [             stat($_[0])]->[9] } :
- sub { [Time::HiRes::stat($_[0])]->[9] } ;
+sub mtime {
+  no warnings 'redefine';
+  local $@;
+  *mtime = (eval { require Time::HiRes } && defined &Time::HiRes::stat)
+    ? sub { (Time::HiRes::stat($_[0]))[9] }
+    : sub { (             stat($_[0]))[9] }
+  ;
+  goto &mtime;
+}
 
 =head1 NAME
 
@@ -213,8 +219,8 @@ sub perllocal_install {
                            : @ARGV;
 
     my $pod;
-    $pod = sprintf <<POD, scalar localtime;
- =head2 %s: C<$type> L<$name|$name>
+    $pod = sprintf <<'POD', scalar(localtime), $type, $name, $name;
+ =head2 %s: C<%s> L<%s|%s>
 
  =over 4
 
index 3bb49d2..56fc355 100644 (file)
@@ -2,7 +2,8 @@ package ExtUtils::Liblist;
 
 use strict;
 
-our $VERSION = '7.10_01';
+our $VERSION = '7.18';
+$VERSION = eval $VERSION;
 
 use File::Spec;
 require ExtUtils::Liblist::Kid;
@@ -16,9 +17,9 @@ sub ext {
 sub lsdir {
   shift;
   my $rex = qr/$_[1]/;
-  opendir DIR, $_[0];
-  my @out = grep /$rex/, readdir DIR;
-  closedir DIR;
+  opendir my $dir_fh, $_[0];
+  my @out = grep /$rex/, readdir $dir_fh;
+  closedir $dir_fh;
   return @out;
 }
 
index 43d554e..23708e2 100644 (file)
@@ -11,7 +11,8 @@ use 5.006;
 
 use strict;
 use warnings;
-our $VERSION = '7.10_01';
+our $VERSION = '7.18';
+$VERSION = eval $VERSION;
 
 use ExtUtils::MakeMaker::Config;
 use Cwd 'cwd';
@@ -337,7 +338,7 @@ sub _win32_ext {
         $libs_seen{$fullname} = 1 if $path;    # why is this a special case?
     }
 
-    my @libs = keys %libs_seen;
+    my @libs = sort keys %libs_seen;
 
     return ( '', '', '', '', ( $give_libs ? \@libs : () ) ) unless @extralibs;
 
index fa5f72c..0b2835c 100644 (file)
@@ -3,7 +3,8 @@ package ExtUtils::MM;
 use strict;
 use ExtUtils::MakeMaker::Config;
 
-our $VERSION = '7.10_01';
+our $VERSION = '7.18';
+$VERSION = eval $VERSION;
 
 require ExtUtils::Liblist;
 require ExtUtils::MakeMaker;
index ec3a2fc..0db269b 100644 (file)
@@ -1,14 +1,12 @@
 package ExtUtils::MM_AIX;
 
 use strict;
-our $VERSION = '7.10_01';
+our $VERSION = '7.18';
+$VERSION = eval $VERSION;
 
 require ExtUtils::MM_Unix;
 our @ISA = qw(ExtUtils::MM_Unix);
 
-use ExtUtils::MakeMaker qw(neatvalue);
-
-
 =head1 NAME
 
 ExtUtils::MM_AIX - AIX specific subclass of ExtUtils::MM_Unix
@@ -35,36 +33,26 @@ Define DL_FUNCS and DL_VARS and write the *.exp files.
 
 sub dlsyms {
     my($self,%attribs) = @_;
+    return '' unless $self->needs_linking;
+    my @m;
+    # these will need XSMULTI-fying but maybe that already happens
+    push @m,"\ndynamic :: $self->{BASEEXT}.exp\n\n"
+      unless $self->{SKIPHASH}{'dynamic'}; # dynamic and static are subs, so...
+    push @m,"\nstatic :: $self->{BASEEXT}.exp\n\n"
+      unless $self->{SKIPHASH}{'static'};  # we avoid a warning if we tick them
+    join "\n", @m, $self->xs_dlsyms_iterator(\%attribs);
+}
 
-    return '' unless $self->needs_linking();
-
-    my($funcs) = $attribs{DL_FUNCS} || $self->{DL_FUNCS} || {};
-    my($vars)  = $attribs{DL_VARS} || $self->{DL_VARS} || [];
-    my($funclist)  = $attribs{FUNCLIST} || $self->{FUNCLIST} || [];
-    my(@m);
-
-    push(@m,"
-dynamic :: $self->{BASEEXT}.exp
-
-") unless $self->{SKIPHASH}{'dynamic'}; # dynamic and static are subs, so...
-
-    push(@m,"
-static :: $self->{BASEEXT}.exp
+=head3 xs_dlsyms_ext
 
-") unless $self->{SKIPHASH}{'static'};  # we avoid a warning if we tick them
+On AIX, is C<.exp>.
 
-    push(@m,"
-$self->{BASEEXT}.exp: Makefile.PL
-",'    $(PERLRUN) -e \'use ExtUtils::Mksymlists; \\
-       Mksymlists("NAME" => "',$self->{NAME},'", "DL_FUNCS" => ',
-       neatvalue($funcs), ', "FUNCLIST" => ', neatvalue($funclist),
-       ', "DL_VARS" => ', neatvalue($vars), ');\'
-');
+=cut
 
-    join('',@m);
+sub xs_dlsyms_ext {
+    '.exp';
 }
 
-
 =head1 AUTHOR
 
 Michael G Schwern <schwern@pobox.com> with code from ExtUtils::MM_Unix
index 129ad9e..7320aee 100644 (file)
@@ -1,7 +1,8 @@
 package ExtUtils::MM_Any;
 
 use strict;
-our $VERSION = '7.10_01';
+our $VERSION = '7.18';
+$VERSION = eval $VERSION;
 
 use Carp;
 use File::Spec;
@@ -9,7 +10,7 @@ use File::Basename;
 BEGIN { our @ISA = qw(File::Spec); }
 
 # We need $Verbose
-use ExtUtils::MakeMaker qw($Verbose);
+use ExtUtils::MakeMaker qw($Verbose neatvalue _sprintf562);
 
 use ExtUtils::MakeMaker::Config;
 
@@ -17,9 +18,10 @@ use ExtUtils::MakeMaker::Config;
 # So we don't have to keep calling the methods over and over again,
 # we have these globals to cache the values.  Faster and shrtr.
 my $Curdir  = __PACKAGE__->curdir;
-my $Rootdir = __PACKAGE__->rootdir;
-my $Updir   = __PACKAGE__->updir;
+#my $Updir   = __PACKAGE__->updir;
 
+my $METASPEC_URL = 'https://metacpan.org/pod/CPAN::Meta::Spec';
+my $METASPEC_V = 2;
 
 =head1 NAME
 
@@ -348,6 +350,34 @@ sub _expand_macros {
 }
 
 
+=head3 make_type
+
+Returns a suitable string describing the type of makefile being written.
+
+=cut
+
+# override if this isn't suitable!
+sub make_type { return 'Unix-style'; }
+
+
+=head3 stashmeta
+
+    my @recipelines = $MM->stashmeta($text, $file);
+
+Generates a set of C<@recipelines> which will result in the literal
+C<$text> ending up in literal C<$file> when the recipe is executed. Call
+it once, with all the text you want in C<$file>. Make macros will not
+be expanded, so the locations will be fixed at configure-time, not
+at build-time.
+
+=cut
+
+sub stashmeta {
+    my($self, $text, $file) = @_;
+    $self->echo($text, $file, { allow_variables => 0, append => 0 });
+}
+
+
 =head3 echo
 
     my @commands = $MM->echo($text);
@@ -367,7 +397,7 @@ all C<$>.
 
 Example of use:
 
-    my $make = map "\t$_\n", $MM->echo($text, $file);
+    my $make = join '', map "\t$_\n", $MM->echo($text, $file);
 
 =cut
 
@@ -480,13 +510,14 @@ Usage might be something like:
     $oneliner = $MM->oneliner('print "Foo\n"');
     $make = '$oneliner > somefile';
 
-All dollar signs must be doubled in the $perl_code if you expect them
-to be interpreted normally, otherwise it will be considered a make
-macro.  Also remember to quote make macros else it might be used as a
-bareword.  For example:
+Dollar signs in the $perl_code will be protected from make using the
+C<quote_literal> method, unless they are recognised as being a make
+variable, C<$(varname)>, in which case they will be left for make
+to expand. Remember to quote make macros else it might be used as a
+bareword. For example:
 
     # Assign the value of the $(VERSION_FROM) make macro to $vf.
-    $oneliner = $MM->oneliner('$$vf = "$(VERSION_FROM)"');
+    $oneliner = $MM->oneliner('$vf = "$(VERSION_FROM)"');
 
 Its currently very simple and may be expanded sometime in the figure
 to include more flexible code and switches.
@@ -620,6 +651,11 @@ The blibdirs.ts target is deprecated.  Depend on blibdirs instead.
 
 =cut
 
+sub _xs_list_basenames {
+    my ($self) = @_;
+    map { (my $b = $_) =~ s/\.xs$//; $b } sort keys %{ $self->{XS} };
+}
+
 sub blibdirs_target {
     my $self = shift;
 
@@ -628,6 +664,14 @@ sub blibdirs_target {
                                            bin script
                                            man1dir man3dir
                                           );
+    if ($self->{XSMULTI}) {
+        for my $ext ($self->_xs_list_basenames) {
+            my ($v, $d, $f) = File::Spec->splitpath($ext);
+            my @d = File::Spec->splitdir($d);
+            shift @d if $d[0] eq 'lib';
+            push @dirs, $self->catdir('$(INST_ARCHLIB)', 'auto', @d, $f);
+       }
+    }
 
     my @exists = map { $_.'$(DFSEP).exists' } @dirs;
 
@@ -666,6 +710,10 @@ clean :: clean_subdirs
 ');
 
     my @files = sort values %{$self->{XS}}; # .c files from *.xs files
+    push @files, map {
+       my $file = $_;
+       map { $file.$_ } $self->{OBJ_EXT}, qw(.def _def.old .bs .bso .exp .base);
+    } $self->_xs_list_basenames;
     my @dirs  = qw(blib);
 
     # Normally these are all under blib but they might have been
@@ -862,6 +910,110 @@ MAKE_FRAG
 }
 
 
+=head3 xs_dlsyms_ext
+
+Returns file-extension for C<xs_make_dlsyms> method's output file,
+including any "." character.
+
+=cut
+
+sub xs_dlsyms_ext {
+    die "Pure virtual method";
+}
+
+=head3 xs_dlsyms_extra
+
+Returns any extra text to be prepended to the C<$extra> argument of
+C<xs_make_dlsyms>.
+
+=cut
+
+sub xs_dlsyms_extra {
+    '';
+}
+
+=head3 xs_dlsyms_iterator
+
+Iterates over necessary shared objects, calling C<xs_make_dlsyms> method
+for each with appropriate arguments.
+
+=cut
+
+sub xs_dlsyms_iterator {
+    my ($self, $attribs) = @_;
+    if ($self->{XSMULTI}) {
+        my @m;
+        for my $ext ($self->_xs_list_basenames) {
+            my @parts = File::Spec->splitdir($ext);
+            shift @parts if $parts[0] eq 'lib';
+            my $name = join '::', @parts;
+            push @m, $self->xs_make_dlsyms(
+                $attribs,
+                $ext . $self->xs_dlsyms_ext,
+                "$ext.xs",
+                $name,
+                $parts[-1],
+                {}, [], {}, [],
+                $self->xs_dlsyms_extra . q!, 'FILE' => ! . neatvalue($ext),
+            );
+        }
+        return join "\n", @m;
+    } else {
+        return $self->xs_make_dlsyms(
+            $attribs,
+            $self->{BASEEXT} . $self->xs_dlsyms_ext,
+            'Makefile.PL',
+            $self->{NAME},
+            $self->{DLBASE},
+            $attribs->{DL_FUNCS} || $self->{DL_FUNCS} || {},
+            $attribs->{FUNCLIST} || $self->{FUNCLIST} || [],
+            $attribs->{IMPORTS} || $self->{IMPORTS} || {},
+            $attribs->{DL_VARS} || $self->{DL_VARS} || [],
+            $self->xs_dlsyms_extra,
+        );
+    }
+}
+
+=head3 xs_make_dlsyms
+
+    $self->xs_make_dlsyms(
+        \%attribs, # hashref from %attribs in caller
+        "$self->{BASEEXT}.def", # output file for Makefile target
+        'Makefile.PL', # dependency
+        $self->{NAME}, # shared object's "name"
+        $self->{DLBASE}, # last ::-separated part of name
+        $attribs{DL_FUNCS} || $self->{DL_FUNCS} || {}, # various params
+        $attribs{FUNCLIST} || $self->{FUNCLIST} || [],
+        $attribs{IMPORTS} || $self->{IMPORTS} || {},
+        $attribs{DL_VARS} || $self->{DL_VARS} || [],
+        # optional extra param that will be added as param to Mksymlists
+    );
+
+Utility method that returns Makefile snippet to call C<Mksymlists>.
+
+=cut
+
+sub xs_make_dlsyms {
+    my ($self, $attribs, $target, $dep, $name, $dlbase, $funcs, $funclist, $imports, $vars, $extra) = @_;
+    my @m = (
+     "\n$target: $dep\n",
+     q!        $(PERLRUN) -MExtUtils::Mksymlists \\
+     -e "Mksymlists('NAME'=>\"!, $name,
+     q!\", 'DLBASE' => '!,$dlbase,
+     # The above two lines quoted differently to work around
+     # a bug in the 4DOS/4NT command line interpreter.  The visible
+     # result of the bug was files named q('extension_name',) *with the
+     # single quotes and the comma* in the extension build directories.
+     q!', 'DL_FUNCS' => !,neatvalue($funcs),
+     q!, 'FUNCLIST' => !,neatvalue($funclist),
+     q!, 'IMPORTS' => !,neatvalue($imports),
+     q!, 'DL_VARS' => !, neatvalue($vars)
+    );
+    push @m, $extra if defined $extra;
+    push @m, qq!);"\n!;
+    join '', @m;
+}
+
 =head3 dynamic (o)
 
 Defines the dynamic target.
@@ -873,7 +1025,7 @@ sub dynamic {
 
     my($self) = shift;
     '
-dynamic :: $(FIRST_MAKEFILE) $(BOOTSTRAP) $(INST_DYNAMIC)
+dynamic :: $(FIRST_MAKEFILE) config $(INST_BOOT) $(INST_DYNAMIC)
        $(NOECHO) $(NOOP)
 ';
 }
@@ -921,14 +1073,14 @@ sub manifypods_target {
     }
 
     my $manify = <<END;
-manifypods : pure_all $dependencies
+manifypods : pure_all config $dependencies
 END
 
     my @man_cmds;
     foreach my $section (qw(1 3)) {
         my $pods = $self->{"MAN${section}PODS"};
-        my $p2m = sprintf <<CMD, $] > 5.008 ? " -u" : "";
-       \$(NOECHO) \$(POD2MAN) --section=$section --perm_rw=\$(PERM_RW)%s
+        my $p2m = sprintf <<'CMD', $section, $] > 5.008 ? " -u" : "";
+       $(NOECHO) $(POD2MAN) --section=%s --perm_rw=$(PERM_RW)%s
 CMD
         push @man_cmds, $self->split_command($p2m, map {($_,$pods->{$_})} sort keys %$pods);
     }
@@ -939,12 +1091,16 @@ CMD
     return $manify;
 }
 
-sub _has_cpan_meta {
-    return eval {
-      require CPAN::Meta;
-      CPAN::Meta->VERSION(2.112150);
-      1;
-    };
+{
+    my $has_cpan_meta;
+    sub _has_cpan_meta {
+        return $has_cpan_meta if defined $has_cpan_meta;
+        return $has_cpan_meta = !!eval {
+            require CPAN::Meta;
+            CPAN::Meta->VERSION(2.112150);
+            1;
+        };
+    }
 }
 
 =head3 metafile_target
@@ -966,34 +1122,18 @@ metafile :
        $(NOECHO) $(NOOP)
 MAKE_FRAG
 
-    my %metadata   = $self->metafile_data(
+    my $metadata   = $self->metafile_data(
         $self->{META_ADD}   || {},
         $self->{META_MERGE} || {},
     );
 
-    _fix_metadata_before_conversion( \%metadata );
-
-    # paper over validation issues, but still complain, necessary because
-    # there's no guarantee that the above will fix ALL errors
-    my $meta = eval { CPAN::Meta->create( \%metadata, { lazy_validation => 1 } ) };
-    warn $@ if $@ and
-               $@ !~ /encountered CODE.*, but JSON can only represent references to arrays or hashes/;
+    my $meta = $self->_fix_metadata_before_conversion( $metadata );
 
-    # use the original metadata straight if the conversion failed
-    # or if it can't be stringified.
-    if( !$meta                                                  ||
-        !eval { $meta->as_string( { version => "1.4" } ) }      ||
-        !eval { $meta->as_string }
-    )
-    {
-        $meta = bless \%metadata, 'CPAN::Meta';
-    }
-
-    my @write_metayml = $self->echo(
+    my @write_metayml = $self->stashmeta(
       $meta->as_string({version => "1.4"}), 'META_new.yml'
     );
-    my @write_metajson = $self->echo(
-      $meta->as_string(), 'META_new.json'
+    my @write_metajson = $self->stashmeta(
+      $meta->as_string({version => "2.0"}), 'META_new.json'
     );
 
     my $metayml = join("\n\t", @write_metayml);
@@ -1014,7 +1154,7 @@ MAKE_FRAG
 
 =head3 _fix_metadata_before_conversion
 
-    _fix_metadata_before_conversion( \%metadata );
+    $mm->_fix_metadata_before_conversion( \%metadata );
 
 Fixes errors in the metadata before it's handed off to CPAN::Meta for
 conversion. This hopefully results in something that can be used further
@@ -1025,7 +1165,7 @@ on, no guarantee is made though.
 =cut
 
 sub _fix_metadata_before_conversion {
-    my ( $metadata ) = @_;
+    my ( $self, $metadata ) = @_;
 
     # we should never be called unless this already passed but
     # prefer to be defensive in case somebody else calls this
@@ -1034,18 +1174,24 @@ sub _fix_metadata_before_conversion {
 
     my $bad_version = $metadata->{version} &&
                       !CPAN::Meta::Validator->new->version( 'version', $metadata->{version} );
-
     # just delete all invalid versions
     if( $bad_version ) {
         warn "Can't parse version '$metadata->{version}'\n";
         $metadata->{version} = '';
     }
 
-    my $validator = CPAN::Meta::Validator->new( $metadata );
-    return if $validator->is_valid;
-
+    my $validator2 = CPAN::Meta::Validator->new( $metadata );
+    my @errors;
+    push @errors, $validator2->errors if !$validator2->is_valid;
+    my $validator14 = CPAN::Meta::Validator->new(
+        {
+            %$metadata,
+            'meta-spec' => { version => 1.4 },
+        }
+    );
+    push @errors, $validator14->errors if !$validator14->is_valid;
     # fix non-camelcase custom resource keys (only other trick we know)
-    for my $error ( $validator->errors ) {
+    for my $error ( @errors ) {
         my ( $key ) = ( $error =~ /Custom resource '(.*)' must be in CamelCase./ );
         next if !$key;
 
@@ -1053,17 +1199,39 @@ sub _fix_metadata_before_conversion {
         ( my $new_key = $key ) =~ s/[^_a-zA-Z]//g;
 
         # if that doesn't work, uppercase first one
-        $new_key = ucfirst $new_key if !$validator->custom_1( $new_key );
+        $new_key = ucfirst $new_key if !$validator14->custom_1( $new_key );
 
         # copy to new key if that worked
         $metadata->{resources}{$new_key} = $metadata->{resources}{$key}
-          if $validator->custom_1( $new_key );
+          if $validator14->custom_1( $new_key );
 
         # and delete old one in any case
         delete $metadata->{resources}{$key};
     }
 
-    return;
+    # paper over validation issues, but still complain, necessary because
+    # there's no guarantee that the above will fix ALL errors
+    my $meta = eval { CPAN::Meta->create( $metadata, { lazy_validation => 1 } ) };
+    warn $@ if $@ and
+               $@ !~ /encountered CODE.*, but JSON can only represent references to arrays or hashes/;
+
+    # use the original metadata straight if the conversion failed
+    # or if it can't be stringified.
+    if( !$meta                                                  ||
+        !eval { $meta->as_string( { version => $METASPEC_V } ) }      ||
+        !eval { $meta->as_string }
+    ) {
+        $meta = bless $metadata, 'CPAN::Meta';
+    }
+
+    my $now_license = $meta->as_struct({ version => 2 })->{license};
+    if ($self->{LICENSE} and $self->{LICENSE} ne 'unknown' and
+        @{$now_license} == 1 and $now_license->[0] eq 'unknown'
+    ) {
+        warn "Invalid LICENSE value '$self->{LICENSE}' ignored\n";
+    }
+
+    $meta;
 }
 
 
@@ -1104,10 +1272,10 @@ sub _hash_merge {
 
 =head3 metafile_data
 
-    my @metadata_pairs = $mm->metafile_data(\%meta_add, \%meta_merge);
+    my $metadata_hashref = $mm->metafile_data(\%meta_add, \%meta_merge);
 
 Returns the data which MakeMaker turns into the META.yml file 
-and the META.json file.
+and the META.json file. It is always in version 2.0 of the format.
 
 Values of %meta_add will overwrite any existing metadata in those
 keys.  %meta_merge will be merged with them.
@@ -1118,48 +1286,59 @@ sub metafile_data {
     my $self = shift;
     my($meta_add, $meta_merge) = @_;
 
+    $meta_add ||= {};
+    $meta_merge ||= {};
+
+    my $version = _normalize_version($self->{VERSION});
+    my $release_status = ($version =~ /_/) ? 'unstable' : 'stable';
     my %meta = (
         # required
-        name         => $self->{DISTNAME},
-        version      => _normalize_version($self->{VERSION}),
         abstract     => $self->{ABSTRACT} || 'unknown',
-        license      => $self->{LICENSE} || 'unknown',
+        author       => defined($self->{AUTHOR}) ? $self->{AUTHOR} : ['unknown'],
         dynamic_config => 1,
-
-        # optional
-        distribution_type => $self->{PM} ? 'module' : 'script',
-
-        no_index     => {
-            directory   => [qw(t inc)]
-        },
-
         generated_by => "ExtUtils::MakeMaker version $ExtUtils::MakeMaker::VERSION",
+        license      => [ $self->{LICENSE} || 'unknown' ],
         'meta-spec'  => {
-            url         => 'http://module-build.sourceforge.net/META-spec-v1.4.html',
-            version     => 1.4
+            url         => $METASPEC_URL,
+            version     => $METASPEC_V,
         },
+        name         => $self->{DISTNAME},
+        release_status => $release_status,
+        version      => $version,
+
+        # optional
+        no_index     => { directory => [qw(t inc)] },
     );
+    $self->_add_requirements_to_meta(\%meta);
 
-    # The author key is required and it takes a list.
-    $meta{author}   = defined $self->{AUTHOR}    ? $self->{AUTHOR} : [];
+    if (!eval { require JSON::PP; require CPAN::Meta::Converter; CPAN::Meta::Converter->VERSION(2.141170) }) {
+      return \%meta;
+    }
 
-    {
-      my $vers = _metaspec_version( $meta_add, $meta_merge );
-      my $method = $vers =~ m!^2!
-               ? '_add_requirements_to_meta_v2'
-               : '_add_requirements_to_meta_v1_4';
-      %meta = $self->$method( %meta );
+    # needs to be based on the original version
+    my $v1_add = _metaspec_version($meta_add) !~ /^2/;
+
+    for my $frag ($meta_add, $meta_merge) {
+        $frag = CPAN::Meta::Converter->new($frag, default_version => "1.4")->upgrade_fragment;
     }
 
+    # if we upgraded a 1.x _ADD fragment, we gave it a prereqs key that
+    # will override all prereqs, which is more than the user asked for;
+    # instead, we'll go inside the prereqs and override all those
     while( my($key, $val) = each %$meta_add ) {
-        $meta{$key} = $val;
+        if ($v1_add and $key eq 'prereqs') {
+            $meta{$key}{$_} = $val->{$_} for keys %$val;
+        } elsif ($key ne 'meta-spec') {
+            $meta{$key} = $val;
+        }
     }
 
     while( my($key, $val) = each %$meta_merge ) {
+        next if $key eq 'meta-spec';
         $self->_hash_merge(\%meta, $key, $val);
     }
 
-    return %meta;
+    return \%meta;
 }
 
 
@@ -1167,84 +1346,61 @@ sub metafile_data {
 
 =cut
 
+sub _add_requirements_to_meta {
+    my ( $self, $meta ) = @_;
+    # Check the original args so we can tell between the user setting it
+    # to an empty hash and it just being initialized.
+    $meta->{prereqs}{configure}{requires} = $self->{ARGS}{CONFIGURE_REQUIRES}
+        ? $self->{CONFIGURE_REQUIRES}
+        : { 'ExtUtils::MakeMaker' => 0, };
+    $meta->{prereqs}{build}{requires} = $self->{ARGS}{BUILD_REQUIRES}
+        ? $self->{BUILD_REQUIRES}
+        : { 'ExtUtils::MakeMaker' => 0, };
+    $meta->{prereqs}{test}{requires} = $self->{TEST_REQUIRES}
+        if $self->{ARGS}{TEST_REQUIRES};
+    $meta->{prereqs}{runtime}{requires} = $self->{PREREQ_PM}
+        if $self->{ARGS}{PREREQ_PM};
+    $meta->{prereqs}{runtime}{requires}{perl} = _normalize_version($self->{MIN_PERL_VERSION})
+        if $self->{MIN_PERL_VERSION};
+}
+
+# spec version of given fragment - if not given, assume 1.4
 sub _metaspec_version {
-  my ( $meta_add, $meta_merge ) = @_;
-  return $meta_add->{'meta-spec'}->{version}
-    if defined $meta_add->{'meta-spec'}
-       and defined $meta_add->{'meta-spec'}->{version};
-  return $meta_merge->{'meta-spec'}->{version}
-    if defined $meta_merge->{'meta-spec'}
-       and  defined $meta_merge->{'meta-spec'}->{version};
+  my ( $meta ) = @_;
+  return $meta->{'meta-spec'}->{version}
+    if defined $meta->{'meta-spec'}
+       and defined $meta->{'meta-spec'}->{version};
   return '1.4';
 }
 
 sub _add_requirements_to_meta_v1_4 {
-    my ( $self, %meta ) = @_;
-
+    my ( $self, $meta ) = @_;
     # Check the original args so we can tell between the user setting it
     # to an empty hash and it just being initialized.
     if( $self->{ARGS}{CONFIGURE_REQUIRES} ) {
-        $meta{configure_requires} = $self->{CONFIGURE_REQUIRES};
+        $meta->{configure_requires} = $self->{CONFIGURE_REQUIRES};
     } else {
-        $meta{configure_requires} = {
+        $meta->{configure_requires} = {
             'ExtUtils::MakeMaker'       => 0,
         };
     }
-
     if( $self->{ARGS}{BUILD_REQUIRES} ) {
-        $meta{build_requires} = $self->{BUILD_REQUIRES};
+        $meta->{build_requires} = $self->{BUILD_REQUIRES};
     } else {
-        $meta{build_requires} = {
+        $meta->{build_requires} = {
             'ExtUtils::MakeMaker'       => 0,
         };
     }
-
     if( $self->{ARGS}{TEST_REQUIRES} ) {
-        $meta{build_requires} = {
-          %{ $meta{build_requires} },
+        $meta->{build_requires} = {
+          %{ $meta->{build_requires} },
           %{ $self->{TEST_REQUIRES} },
         };
     }
-
-    $meta{requires} = $self->{PREREQ_PM}
+    $meta->{requires} = $self->{PREREQ_PM}
         if defined $self->{PREREQ_PM};
-    $meta{requires}{perl} = _normalize_version($self->{MIN_PERL_VERSION})
+    $meta->{requires}{perl} = _normalize_version($self->{MIN_PERL_VERSION})
         if $self->{MIN_PERL_VERSION};
-
-    return %meta;
-}
-
-sub _add_requirements_to_meta_v2 {
-    my ( $self, %meta ) = @_;
-
-    # Check the original args so we can tell between the user setting it
-    # to an empty hash and it just being initialized.
-    if( $self->{ARGS}{CONFIGURE_REQUIRES} ) {
-        $meta{prereqs}{configure}{requires} = $self->{CONFIGURE_REQUIRES};
-    } else {
-        $meta{prereqs}{configure}{requires} = {
-            'ExtUtils::MakeMaker'       => 0,
-        };
-    }
-
-    if( $self->{ARGS}{BUILD_REQUIRES} ) {
-        $meta{prereqs}{build}{requires} = $self->{BUILD_REQUIRES};
-    } else {
-        $meta{prereqs}{build}{requires} = {
-            'ExtUtils::MakeMaker'       => 0,
-        };
-    }
-
-    if( $self->{ARGS}{TEST_REQUIRES} ) {
-        $meta{prereqs}{test}{requires} = $self->{TEST_REQUIRES};
-    }
-
-    $meta{prereqs}{runtime}{requires} = $self->{PREREQ_PM}
-        if $self->{ARGS}{PREREQ_PM};
-    $meta{prereqs}{runtime}{requires}{perl} = _normalize_version($self->{MIN_PERL_VERSION})
-        if $self->{MIN_PERL_VERSION};
-
-    return %meta;
 }
 
 # Adapted from Module::Build::Base
@@ -1253,7 +1409,7 @@ sub _normalize_version {
   $version = 0 unless defined $version;
 
   if ( ref $version eq 'version' ) { # version objects
-    $version = $version->is_qv ? $version->normal : $version->stringify;
+    $version = $version->stringify;
   }
   elsif ( $version =~ /^[^v][^.]*\.[^.]+\./ ) { # no leading v, multiple dots
     # normalize string tuples without "v": "1.2.3" -> "v1.2.3"
@@ -1426,12 +1582,12 @@ sub distmeta_target {
       $self->oneliner(<<'CODE', ['-MExtUtils::Manifest=maniadd']),
 exit unless -e q{META.yml};
 eval { maniadd({q{META.yml} => q{Module YAML meta-data (added by MakeMaker)}}) }
-    or print "Could not add META.yml to MANIFEST: $${'@'}\n"
+    or die "Could not add META.yml to MANIFEST: ${'@'}"
 CODE
       $self->oneliner(<<'CODE', ['-MExtUtils::Manifest=maniadd'])
 exit unless -f q{META.json};
 eval { maniadd({q{META.json} => q{Module JSON meta-data (added by MakeMaker)}}) }
-    or print "Could not add META.json to MANIFEST: $${'@'}\n"
+    or die "Could not add META.json to MANIFEST: ${'@'}"
 CODE
     );
 
@@ -1464,21 +1620,15 @@ sub mymeta {
     my $v2 = 1;
 
     unless ( $mymeta ) {
-        my @metadata = $self->metafile_data(
+        $mymeta = $self->metafile_data(
             $self->{META_ADD}   || {},
             $self->{META_MERGE} || {},
         );
-        $mymeta = {@metadata};
         $v2 = 0;
     }
 
     # Overwrite the non-configure dependency hashes
-
-    my $method = $v2
-               ? '_add_requirements_to_meta_v2'
-               : '_add_requirements_to_meta_v1_4';
-
-    $mymeta = { $self->$method( %$mymeta ) };
+    $self->_add_requirements_to_meta($mymeta);
 
     $mymeta->{dynamic_config} = 0;
 
@@ -1530,13 +1680,9 @@ sub write_mymeta {
 
     return unless _has_cpan_meta();
 
-    _fix_metadata_before_conversion( $mymeta );
+    my $meta_obj = $self->_fix_metadata_before_conversion( $mymeta );
 
-    # this can still blow up
-    # not sure if i should just eval this and skip file creation if it
-    # blows up
-    my $meta_obj = CPAN::Meta->new( $mymeta, { lazy_validation => 1 } );
-    $meta_obj->save( 'MYMETA.json' );
+    $meta_obj->save( 'MYMETA.json', { version => "2.0" } );
     $meta_obj->save( 'MYMETA.yml', { version => "1.4" } );
     return 1;
 }
@@ -1574,8 +1720,8 @@ sub realclean {
     }
 
     # Occasionally files are repeated several times from different sources
-    { my(%f) = map { ($_ => 1) } @files;  @files = keys %f; }
-    { my(%d) = map { ($_ => 1) } @dirs;   @dirs  = keys %d; }
+    { my(%f) = map { ($_ => 1) } @files;  @files = sort keys %f; }
+    { my(%d) = map { ($_ => 1) } @dirs;   @dirs  = sort keys %d; }
 
     my $rm_cmd  = join "\n\t", map { "$_" }
                     $self->split_command('- $(RM_F)',  @files);
@@ -1584,7 +1730,7 @@ sub realclean {
 
     my $m = sprintf <<'MAKE', $rm_cmd, $rmf_cmd;
 # Delete temporary files (via clean) and also delete dist files
-realclean purge ::  clean realclean_subdirs
+realclean purge :: realclean_subdirs
        %s
        %s
 MAKE
@@ -1606,28 +1752,20 @@ target to call realclean on any subdirectories which contain Makefiles.
 
 sub realclean_subdirs_target {
     my $self = shift;
-
-    return <<'NOOP_FRAG' unless @{$self->{DIR}};
-realclean_subdirs :
-       $(NOECHO) $(NOOP)
-NOOP_FRAG
-
-    my $rclean = "realclean_subdirs :\n";
-
+    my @m = <<'EOF';
+# so clean is forced to complete before realclean_subdirs runs
+realclean_subdirs : clean
+EOF
+    return join '', @m, "\t\$(NOECHO) \$(NOOP)\n" unless @{$self->{DIR}};
     foreach my $dir (@{$self->{DIR}}) {
         foreach my $makefile ('$(MAKEFILE_OLD)', '$(FIRST_MAKEFILE)' ) {
-            my $subrclean .= $self->oneliner(sprintf <<'CODE', $dir, ($makefile) x 2);
-chdir '%s';  system '$(MAKE) $(USEMAKEFILE) %s realclean' if -f '%s';
+            my $subrclean .= $self->oneliner(_sprintf562 <<'CODE', $dir, $makefile);
+chdir '%1$s';  system '$(MAKE) $(USEMAKEFILE) %2$s realclean' if -f '%2$s';
 CODE
-
-            $rclean .= sprintf <<'RCLEAN', $subrclean;
-       - %s
-RCLEAN
-
+            push @m, "\t- $subrclean\n";
         }
     }
-
-    return $rclean;
+    return join '', @m;
 }
 
 
@@ -1666,7 +1804,7 @@ sub distsignature_target {
 
     my $add_sign = $self->oneliner(<<'CODE', ['-MExtUtils::Manifest=maniadd']);
 eval { maniadd({q{SIGNATURE} => q{Public-key signature (added by MakeMaker)}}) }
-    or print "Could not add SIGNATURE to MANIFEST: $${'@'}\n"
+    or die "Could not add SIGNATURE to MANIFEST: ${'@'}"
 CODE
 
     my $sign_dist        = $self->cd('$(DISTVNAME)' => 'cpansign -s');
@@ -1700,7 +1838,7 @@ sub special_targets {
     my $make_frag = <<'MAKE_FRAG';
 .SUFFIXES : .xs .c .C .cpp .i .s .cxx .cc $(OBJ_EXT)
 
-.PHONY: all config static dynamic test linkext manifest blibdirs clean realclean disttest distdir
+.PHONY: all config static dynamic test linkext manifest blibdirs clean realclean disttest distdir pure_all subdirs clean_subdirs makemakerdflt manifypods realclean_subdirs subdirs_dynamic subdirs_pure_nolink subdirs_static subdirs-test_dynamic subdirs-test_static test_dynamic test_static
 
 MAKE_FRAG
 
@@ -2291,7 +2429,7 @@ sub init_others {
     if ( $self->{OBJECT} ) {
         $self->{OBJECT} = join(" ", @{$self->{OBJECT}}) if ref $self->{OBJECT};
         $self->{OBJECT} =~ s!\.o(bj)?\b!\$(OBJ_EXT)!g;
-    } elsif ( $self->{MAGICXS} && @{$self->{O_FILES}||[]} ) {
+    } elsif ( ($self->{MAGICXS} || $self->{XSMULTI}) && @{$self->{O_FILES}||[]} ) {
         $self->{OBJECT} = join(" ", @{$self->{O_FILES}});
         $self->{OBJECT} =~ s!\.o(bj)?\b!\$(OBJ_EXT)!g;
     } else {
@@ -2659,38 +2797,50 @@ sub find_tests {
   my $tests = $mm->find_tests_recursive;
 
 Returns a string suitable for feeding to the shell to return all
-tests in t/ but recursively.
+tests in t/ but recursively. Equivalent to
+
+  my $tests = $mm->find_tests_recursive_in('t');
 
 =cut
 
 sub find_tests_recursive {
-    my($self) = shift;
-    return '' unless -d 't';
+    my $self = shift;
+    return $self->find_tests_recursive_in('t');
+}
+
+=head3 find_tests_recursive_in
+
+  my $tests = $mm->find_tests_recursive_in($dir);
+
+Returns a string suitable for feeding to the shell to return all
+tests in $dir recursively.
+
+=cut
+
+sub find_tests_recursive_in {
+    my($self, $dir) = @_;
+    return '' unless -d $dir;
 
     require File::Find;
 
-    my %testfiles;
+    my $base_depth = grep { $_ ne '' } File::Spec->splitdir( (File::Spec->splitpath($dir))[1] );
+    my %depths;
 
     my $wanted = sub {
         return unless m!\.t$!;
         my ($volume,$directories,$file) =
             File::Spec->splitpath( $File::Find::name  );
-        my @dirs = File::Spec->splitdir( $directories );
-        for ( @dirs ) {
-          next if $_ eq 't';
-          unless ( $_ ) {
-            $_ = '*.t';
-            next;
-          }
-          $_ = '*';
-        }
-        my $testfile = join '/', @dirs;
-        $testfiles{ $testfile } = 1;
+        my $depth = grep { $_ ne '' } File::Spec->splitdir( $directories );
+        $depth -= $base_depth;
+        $depths{ $depth } = 1;
     };
 
-    File::Find::find( $wanted, 't' );
+    File::Find::find( $wanted, $dir );
 
-    return join ' ', sort keys %testfiles;
+    return join ' ',
+        map { $dir . '/*' x $_ . '.t' }
+        sort { $a <=> $b }
+        keys %depths;
 }
 
 =head3 extra_clean_files
@@ -2764,6 +2914,39 @@ sub platform_constants {
     return '';
 }
 
+=head3 post_constants (o)
+
+Returns an empty string per default. Dedicated to overrides from
+within Makefile.PL after all constants have been defined.
+
+=cut
+
+sub post_constants {
+    "";
+}
+
+=head3 post_initialize (o)
+
+Returns an empty string per default. Used in Makefile.PLs to add some
+chunk of text to the Makefile after the object is initialized.
+
+=cut
+
+sub post_initialize {
+    "";
+}
+
+=head3 postamble (o)
+
+Returns an empty string. Can be used in Makefile.PLs to write some
+text to the Makefile at the end.
+
+=cut
+
+sub postamble {
+    "";
+}
+
 =begin private
 
 =head3 _PREREQ_PRINT
@@ -2799,7 +2982,7 @@ sub _PREREQ_PRINT {
 Implements PRINT_PREREQ, a slightly different version of PREREQ_PRINT
 added by Redhat to, I think, support generating RPMs from Perl modules.
 
-Should not include BUILD_REQUIRES as RPMs do not incluide them.
+Should not include BUILD_REQUIRES as RPMs do not include them.
 
 Refactored out of MakeMaker->new().
 
@@ -2823,24 +3006,6 @@ sub _PRINT_PREREQ {
 }
 
 
-=begin private
-
-=head3 _all_prereqs
-
-  my $prereqs = $self->_all_prereqs;
-
-Returns a hash ref of both PREREQ_PM and BUILD_REQUIRES.
-
-=end private
-
-=cut
-
-sub _all_prereqs {
-    my $self = shift;
-
-    return { %{$self->{PREREQ_PM}}, %{$self->{BUILD_REQUIRES}} };
-}
-
 =begin private
 
 =head3 _perl_header_files
index 801b035..1a910d9 100644 (file)
@@ -26,7 +26,8 @@ require ExtUtils::MM_Any;
 require ExtUtils::MM_Unix;
 
 our @ISA = qw( ExtUtils::MM_Any ExtUtils::MM_Unix );
-our $VERSION = '7.10_01';
+our $VERSION = '7.18';
+$VERSION = eval $VERSION;
 
 
 =item os_flavor
index a9331ff..e8e9d3d 100644 (file)
@@ -9,7 +9,8 @@ require ExtUtils::MM_Unix;
 require ExtUtils::MM_Win32;
 our @ISA = qw( ExtUtils::MM_Unix );
 
-our $VERSION = '7.10_01';
+our $VERSION = '7.18';
+$VERSION = eval $VERSION;
 
 
 =head1 NAME
@@ -129,16 +130,31 @@ But for new archdir dll's use the same rebase address if the old exists.
 sub dynamic_lib {
     my($self, %attribs) = @_;
     my $s = ExtUtils::MM_Unix::dynamic_lib($self, %attribs);
-    my $ori = "$self->{INSTALLARCHLIB}/auto/$self->{FULLEXT}/$self->{BASEEXT}.$self->{DLEXT}";
-    if (-e $ori) {
-        my $imagebase = `/bin/objdump -p $ori | /bin/grep ImageBase | /bin/cut -c12-`;
-        chomp $imagebase;
-        if ($imagebase gt "40000000") {
-            my $LDDLFLAGS = $self->{LDDLFLAGS};
-            $LDDLFLAGS =~ s/-Wl,--enable-auto-image-base/-Wl,--image-base=0x$imagebase/;
-            $s =~ s/ \$\(LDDLFLAGS\) / $LDDLFLAGS /m;
-        }
-    }
+    return '' unless $s;
+    return $s unless %{$self->{XS}};
+
+    # do an ephemeral rebase so the new DLL fits to the current rebase map
+    $s .= "\t/bin/find \$\(INST_ARCHLIB\)/auto -xdev -name \\*.$self->{DLEXT} | /bin/rebase -sOT -" if (( $Config{myarchname} eq 'i686-cygwin' ) and not ( exists $ENV{CYGPORT_PACKAGE_VERSION} ));
+    $s;
+}
+
+=item install
+
+Rebase dll's with the global rebase database after installation.
+
+=cut
+
+sub install {
+    my($self, %attribs) = @_;
+    my $s = ExtUtils::MM_Unix::install($self, %attribs);
+    return '' unless $s;
+    return $s unless %{$self->{XS}};
+
+    my $INSTALLDIRS = $self->{INSTALLDIRS};
+    my $INSTALLLIB = $self->{"INSTALL". ($INSTALLDIRS eq 'perl' ? 'ARCHLIB' : uc($INSTALLDIRS)."ARCH")};
+    my $dop = "\$\(DESTDIR\)$INSTALLLIB/auto/";
+    my $dll = "$dop/$self->{FULLEXT}/$self->{BASEEXT}.$self->{DLEXT}";
+    $s =~ s|^(pure_install :: pure_\$\(INSTALLDIRS\)_install\n\t)\$\(NOECHO\) \$\(NOOP\)\n|$1\$(CHMOD) \$(PERM_RWX) $dll\n\t/bin/find $dop -xdev -name \\*.$self->{DLEXT} \| /bin/rebase -sOT -\n|m if (( $Config{myarchname} eq 'i686-cygwin') and not ( exists $ENV{CYGPORT_PACKAGE_VERSION} ));
     $s;
 }
 
index c6ffc59..6bbd02e 100644 (file)
@@ -2,7 +2,8 @@ package ExtUtils::MM_DOS;
 
 use strict;
 
-our $VERSION = '7.10_01';
+our $VERSION = '7.18';
+$VERSION = eval $VERSION;
 
 require ExtUtils::MM_Any;
 require ExtUtils::MM_Unix;
index cc52f1d..a6490db 100644 (file)
@@ -7,7 +7,8 @@ BEGIN {
     our @ISA = qw( ExtUtils::MM_Unix );
 }
 
-our $VERSION = '7.10_01';
+our $VERSION = '7.18';
+$VERSION = eval $VERSION;
 
 
 =head1 NAME
index 820ffd1..5cee011 100644 (file)
@@ -2,7 +2,8 @@ package ExtUtils::MM_MacOS;
 
 use strict;
 
-our $VERSION = '7.10_01';
+our $VERSION = '7.18';
+$VERSION = eval $VERSION;
 
 sub new {
     die 'MacOS Classic (MacPerl) is no longer supported by MakeMaker';
index 0b89a15..48b0b46 100644 (file)
@@ -22,17 +22,18 @@ use strict;
 use ExtUtils::MakeMaker::Config;
 use File::Basename;
 
-our $VERSION = '7.10_01';
+our $VERSION = '7.18';
+$VERSION = eval $VERSION;
 
 require ExtUtils::MM_Win32;
 our @ISA = qw(ExtUtils::MM_Win32);
 
-use ExtUtils::MakeMaker qw( &neatvalue );
+use ExtUtils::MakeMaker qw(&neatvalue &_sprintf562);
 
 $ENV{EMXSHELL} = 'sh'; # to run `commands`
 
-my $BORLAND  = $Config{'cc'} =~ /^bcc/i;
-my $GCC      = $Config{'cc'} =~ /^gcc/i;
+my $BORLAND  = $Config{'cc'} =~ /\bbcc/i;
+my $GCC      = $Config{'cc'} =~ /\bgcc/i;
 
 
 =item os_flavor
@@ -122,148 +123,78 @@ sub platform_constants {
     return $make_frag;
 }
 
+=item static_lib_pure_cmd
 
-=item const_cccmd
+Defines how to run the archive utility
 
 =cut
 
-sub const_cccmd {
-    my($self,$libperl)=@_;
-    return $self->{CONST_CCCMD} if $self->{CONST_CCCMD};
-    return '' unless $self->needs_linking();
-    return $self->{CONST_CCCMD} = <<'MAKE_FRAG';
-CCCMD = $(CC) $(CCFLAGS) $(INC) $(OPTIMIZE) \
-       $(PERLTYPE) $(MPOLLUTE) -o $@ \
-       -DVERSION=\"$(VERSION)\" -DXS_VERSION=\"$(XS_VERSION)\"
-MAKE_FRAG
-
-}
-
-
-=item static_lib
-
-=cut
-
-sub static_lib {
-    my($self) = @_;
-
-    return '' unless $self->has_link_code;
-
-    my $m = <<'END';
-$(INST_STATIC): $(OBJECT) $(MYEXTLIB) $(INST_ARCHAUTODIR)$(DFSEP).exists
-       $(RM_RF) $@
-END
-
-    # If this extension has it's own library (eg SDBM_File)
-    # then copy that to $(INST_STATIC) and add $(OBJECT) into it.
-    $m .= <<'END'  if $self->{MYEXTLIB};
-       $self->{CP} $(MYEXTLIB) $@
-END
-
-    my $ar_arg;
-    if( $BORLAND ) {
-        $ar_arg = '$@ $(OBJECT:^"+")';
-    }
-    elsif( $GCC ) {
-        $ar_arg = '-ru $@ $(OBJECT)';
-    }
-    else {
-        $ar_arg = '-type library -o $@ $(OBJECT)';
-    }
-
-    $m .= sprintf <<'END', $ar_arg;
-       $(AR) %s
-       $(NOECHO) $(ECHO) "$(EXTRALIBS)" > $(INST_ARCHAUTODIR)\extralibs.ld
-       $(CHMOD) 755 $@
-END
-
-    $m .= <<'END' if $self->{PERL_SRC};
-       $(NOECHO) $(ECHO) "$(EXTRALIBS)" >> $(PERL_SRC)\ext.libs
-
-
-END
-    return $m;
+sub static_lib_pure_cmd {
+    my ($self, $src) = @_;
+    $src =~ s/(\$\(\w+)(\))/$1:^"+"$2/g if $BORLAND;
+    sprintf qq{\t\$(AR) %s\n}, ($BORLAND ? '$@ ' . $src
+                          : ($GCC ? '-ru $@ ' . $src
+                                  : '-type library -o $@ ' . $src));
 }
 
 =item dynamic_lib
 
-Defines how to produce the *.so (or equivalent) files.
+Override of utility methods for OS-specific work.
 
 =cut
 
-sub dynamic_lib {
-    my($self, %attribs) = @_;
-    return '' unless $self->needs_linking(); #might be because of a subdir
-
-    return '' unless $self->has_link_code;
-
-    my($otherldflags) = $attribs{OTHERLDFLAGS} || ($BORLAND ? 'c0d32.obj': '');
-    my($inst_dynamic_dep) = $attribs{INST_DYNAMIC_DEP} || "";
-    my($ldfrom) = '$(LDFROM)';
-
-    (my $boot = $self->{NAME}) =~ s/:/_/g;
-
-    my $m = <<'MAKE_FRAG';
-# This section creates the dynamically loadable $(INST_DYNAMIC)
-# from $(OBJECT) and possibly $(MYEXTLIB).
-OTHERLDFLAGS = '.$otherldflags.'
-INST_DYNAMIC_DEP = '.$inst_dynamic_dep.'
-
+sub xs_make_dynamic_lib {
+    my ($self, $attribs, $from, $to, $todir, $ldfrom, $exportlist) = @_;
+    my @m;
+    # Taking care of long names like FileHandle, ByteLoader, SDBM_File etc
+    if ($to =~ /^\$/) {
+        if ($self->{NLM_SHORT_NAME}) {
+            # deal with shortnames
+            my $newto = q{$(INST_AUTODIR)\\$(NLM_SHORT_NAME).$(DLEXT)};
+            push @m, "$to: $newto\n\n";
+            $to = $newto;
+        }
+    } else {
+        my ($v, $d, $f) = File::Spec->splitpath($to);
+        # relies on $f having a literal "." in it, unlike for $(OBJ_EXT)
+        if ($f =~ /[^\.]{9}\./) {
+            # 9+ chars before '.', need to shorten
+            $f = substr $f, 0, 8;
+        }
+        my $newto = File::Spec->catpath($v, $d, $f);
+        push @m, "$to: $newto\n\n";
+        $to = $newto;
+    }
+    # bits below should be in dlsyms, not here
+    #                                   1    2      3       4
+    push @m, _sprintf562 <<'MAKE_FRAG', $to, $from, $todir, $exportlist;
 # Create xdc data for an MT safe NLM in case of mpk build
-$(INST_DYNAMIC): $(OBJECT) $(MYEXTLIB) $(BOOTSTRAP) $(INST_ARCHAUTODIR)$(DFSEP).exists
-       $(NOECHO) $(ECHO) Export boot_$(BOOT_SYMBOL) > $(BASEEXT).def
-       $(NOECHO) $(ECHO) $(BASE_IMPORT) >> $(BASEEXT).def
-       $(NOECHO) $(ECHO) Import @$(PERL_INC)\perl.imp >> $(BASEEXT).def
+%1$s: %2$s $(MYEXTLIB) $(BOOTSTRAP) %3$s$(DFSEP).exists
+       $(NOECHO) $(ECHO) Export boot_$(BOOT_SYMBOL) > %4$s
+       $(NOECHO) $(ECHO) $(BASE_IMPORT) >> %4$s
+       $(NOECHO) $(ECHO) Import @$(PERL_INC)\perl.imp >> %4$s
 MAKE_FRAG
-
-
     if ( $self->{CCFLAGS} =~ m/ -DMPK_ON /) {
-        $m .= <<'MAKE_FRAG';
-       $(MPKTOOL) $(XDCFLAGS) $(BASEEXT).xdc
-       $(NOECHO) $(ECHO) xdcdata $(BASEEXT).xdc >> $(BASEEXT).def
+        (my $xdc = $exportlist) =~ s#def\z#xdc#;
+        $xdc = '$(BASEEXT).xdc';
+        push @m, sprintf <<'MAKE_FRAG', $xdc, $exportlist;
+       $(MPKTOOL) $(XDCFLAGS) %s
+       $(NOECHO) $(ECHO) xdcdata $(BASEEXT).xdc >> %s
 MAKE_FRAG
     }
-
     # Reconstruct the X.Y.Z version.
     my $version = join '.', map { sprintf "%d", $_ }
                               $] =~ /(\d)\.(\d{3})(\d{2})/;
-    $m .= sprintf '    $(LD) $(LDFLAGS) $(OBJECT:.obj=.obj) -desc "Perl %s Extension ($(BASEEXT))  XS_VERSION: $(XS_VERSION)" -nlmversion $(NLM_VERSION)', $version;
-
-    # Taking care of long names like FileHandle, ByteLoader, SDBM_File etc
-    if($self->{NLM_SHORT_NAME}) {
-        # In case of nlms with names exceeding 8 chars, build nlm in the
-        # current dir, rename and move to auto\lib.
-        $m .= q{ -o $(NLM_SHORT_NAME).$(DLEXT)}
-    } else {
-        $m .= q{ -o $(INST_AUTODIR)\\$(BASEEXT).$(DLEXT)}
-    }
-
-    # Add additional lib files if any (SDBM_File)
-    $m .= q{ $(MYEXTLIB) } if $self->{MYEXTLIB};
-
-    $m .= q{ $(PERL_INC)\Main.lib -commandfile $(BASEEXT).def}."\n";
-
-    if($self->{NLM_SHORT_NAME}) {
-        $m .= <<'MAKE_FRAG';
-       if exist $(INST_AUTODIR)\$(NLM_SHORT_NAME).$(DLEXT) del $(INST_AUTODIR)\$(NLM_SHORT_NAME).$(DLEXT)
-       move $(NLM_SHORT_NAME).$(DLEXT) $(INST_AUTODIR)
-MAKE_FRAG
-    }
-
-    $m .= <<'MAKE_FRAG';
-
+    push @m, sprintf <<'EOF', $from, $version, $to, $exportlist;
+       $(LD) $(LDFLAGS) %s -desc "Perl %s Extension ($(BASEEXT))  XS_VERSION: $(XS_VERSION)" -nlmversion $(NLM_VERSION) -o %s $(MYEXTLIB) $(PERL_INC)\Main.lib -commandfile %s
        $(CHMOD) 755 $@
-MAKE_FRAG
-
-    return $m;
+EOF
+    join '', @m;
 }
 
-
 1;
 __END__
 
 =back
 
 =cut
-
-
index 2c64ac4..4dc8bcc 100644 (file)
@@ -5,7 +5,8 @@ use strict;
 use ExtUtils::MakeMaker qw(neatvalue);
 use File::Spec;
 
-our $VERSION = '7.10_01';
+our $VERSION = '7.18';
+$VERSION = eval $VERSION;
 
 require ExtUtils::MM_Any;
 require ExtUtils::MM_Unix;
@@ -49,33 +50,12 @@ MAKE_TEXT
 
 sub dlsyms {
     my($self,%attribs) = @_;
-
-    my($funcs) = $attribs{DL_FUNCS} || $self->{DL_FUNCS} || {};
-    my($vars)  = $attribs{DL_VARS} || $self->{DL_VARS} || [];
-    my($funclist) = $attribs{FUNCLIST} || $self->{FUNCLIST} || [];
-    my($imports)  = $attribs{IMPORTS} || $self->{IMPORTS} || {};
-    my(@m);
-    (my $boot = $self->{NAME}) =~ s/:/_/g;
-
-    if (not $self->{SKIPHASH}{'dynamic'}) {
-       push(@m,"
-$self->{BASEEXT}.def: Makefile.PL
-",
-     ' $(PERL) "-I$(PERL_ARCHLIB)" "-I$(PERL_LIB)" -e \'use ExtUtils::Mksymlists; \\
-     Mksymlists("NAME" => "$(NAME)", "DLBASE" => "$(DLBASE)", ',
-     '"VERSION" => "$(VERSION)", "DISTNAME" => "$(DISTNAME)", ',
-     '"INSTALLDIRS" => "$(INSTALLDIRS)", ',
-     '"DL_FUNCS" => ',neatvalue($funcs),
-     ', "FUNCLIST" => ',neatvalue($funclist),
-     ', "IMPORTS" => ',neatvalue($imports),
-     ', "DL_VARS" => ', neatvalue($vars), ');\'
-');
-    }
     if ($self->{IMPORTS} && %{$self->{IMPORTS}}) {
        # Make import files (needed for static build)
        -d 'tmp_imp' or mkdir 'tmp_imp', 0777 or die "Can't mkdir tmp_imp";
        open my $imp, '>', 'tmpimp.imp' or die "Can't open tmpimp.imp";
-       while (my($name, $exp) = each %{$self->{IMPORTS}}) {
+       foreach my $name (sort keys %{$self->{IMPORTS}}) {
+           my $exp = $self->{IMPORTS}->{$name};
            my ($lib, $id) = ($exp =~ /(.*)\.(.*)/) or die "Malformed IMPORT `$exp'";
            print $imp "$name $lib $id ?\n";
        }
@@ -88,21 +68,26 @@ $self->{BASEEXT}.def: Makefile.PL
        system "cd tmp_imp; $Config::Config{ar} x ../tmpimp$Config::Config{lib_ext}"
            and die "Cannot extract import objects: $!, \$?=$?";
     }
-    join('',@m);
+    return '' if $self->{SKIPHASH}{'dynamic'};
+    $self->xs_dlsyms_iterator(\%attribs);
 }
 
-sub static_lib {
-    my($self) = @_;
-    my $old = $self->ExtUtils::MM_Unix::static_lib();
-    return $old unless $self->{IMPORTS} && %{$self->{IMPORTS}};
+sub xs_dlsyms_ext {
+    '.def';
+}
 
-    my @chunks = split /\n{2,}/, $old;
-    shift @chunks unless length $chunks[0]; # Empty lines at the start
-    $chunks[0] .= <<'EOC';
+sub xs_dlsyms_extra {
+    join '', map { qq{, "$_" => "\$($_)"} } qw(VERSION DISTNAME INSTALLDIRS);
+}
 
-       $(AR) $(AR_STATIC_ARGS) $@ tmp_imp/* && $(RANLIB) $@
+sub static_lib_pure_cmd {
+    my($self) = @_;
+    my $old = $self->SUPER::static_lib_pure_cmd;
+    return $old unless $self->{IMPORTS} && %{$self->{IMPORTS}};
+    $old . <<'EOC';
+       $(AR) $(AR_STATIC_ARGS) "$@" tmp_imp/*
+       $(RANLIB) "$@"
 EOC
-    return join "\n\n". '', @chunks;
 }
 
 sub replace_manpage_separator {
index 71c4bd5..9a604a1 100644 (file)
@@ -1,7 +1,8 @@
 package ExtUtils::MM_QNX;
 
 use strict;
-our $VERSION = '7.10_01';
+our $VERSION = '7.18';
+$VERSION = eval $VERSION;
 
 require ExtUtils::MM_Unix;
 our @ISA = qw(ExtUtils::MM_Unix);
index 2350482..38c1042 100644 (file)
@@ -1,7 +1,8 @@
 package ExtUtils::MM_UWIN;
 
 use strict;
-our $VERSION = '7.10_01';
+our $VERSION = '7.18';
+$VERSION = eval $VERSION;
 
 require ExtUtils::MM_Unix;
 our @ISA = qw(ExtUtils::MM_Unix);
index e24a61b..fe0ff54 100644 (file)
@@ -7,15 +7,14 @@ use strict;
 use Carp;
 use ExtUtils::MakeMaker::Config;
 use File::Basename qw(basename dirname);
-use DirHandle;
 
 our %Config_Override;
 
-use ExtUtils::MakeMaker qw($Verbose neatvalue);
+use ExtUtils::MakeMaker qw($Verbose neatvalue _sprintf562);
 
 # If we make $VERSION an our variable parse_version() breaks
 use vars qw($VERSION);
-$VERSION = '7.10_01';
+$VERSION = '7.18';
 $VERSION = eval $VERSION;  ## no critic [BuiltinFunctions::ProhibitStringyEval]
 
 require ExtUtils::MM_Any;
@@ -98,7 +97,6 @@ something that used to be in here, look in MM_Any.
 # So we don't have to keep calling the methods over and over again,
 # we have these globals to cache the values.  Faster and shrtr.
 my $Curdir  = __PACKAGE__->curdir;
-my $Rootdir = __PACKAGE__->rootdir;
 my $Updir   = __PACKAGE__->updir;
 
 
@@ -143,31 +141,36 @@ sub c_o {
 };
     }
 
-    push @m, qq{
-.c.s:
-       $command -S $flags \$*.c
+    my $m_o = $self->{XSMULTI} ? $self->xs_obj_opt('$*.s') : '';
+    push @m, sprintf <<'EOF', $command, $flags, $m_o;
 
-.c\$(OBJ_EXT):
-       $command $flags \$*.c
+.c.s :
+       %s -S %s $*.c %s
+EOF
 
-.cpp\$(OBJ_EXT):
-       $command $flags \$*.cpp
+    my @exts = qw(c cpp cxx cc);
+    push @exts, 'C' if !$Is{OS2} and !$Is{Win32} and !$Is{Dos}; #Case-specific
+    $m_o = $self->{XSMULTI} ? $self->xs_obj_opt('$*$(OBJ_EXT)') : '';
+    for my $ext (@exts) {
+       push @m, "\n.$ext\$(OBJ_EXT) :\n\t$command $flags \$*.$ext" . ( $m_o ? " $m_o" : '' ) . "\n";
+    }
+    return join "", @m;
+}
 
-.cxx\$(OBJ_EXT):
-       $command $flags \$*.cxx
 
-.cc\$(OBJ_EXT):
-       $command $flags \$*.cc
-};
+=item xs_obj_opt
 
-    push @m, qq{
-.C\$(OBJ_EXT):
-       $command $flags \$*.C
-} if !$Is{OS2} and !$Is{Win32} and !$Is{Dos}; #Case-specific
+Takes the object file as an argument, and returns the portion of compile
+command-line that will output to the specified object file.
 
-    return join "", @m;
+=cut
+
+sub xs_obj_opt {
+    my ($self, $output_file) = @_;
+    "-o $output_file";
 }
 
+
 =item cflags (o)
 
 Does very much the same as the cflags script in the perl
@@ -284,9 +287,6 @@ sub cflags {
        $pollute = '$(PERL_MALLOC_DEF)';
     }
 
-    $self->{CCFLAGS}  = quote_paren($self->{CCFLAGS});
-    $self->{OPTIMIZE} = quote_paren($self->{OPTIMIZE});
-
     return $self->{CFLAGS} = qq{
 CCFLAGS = $self->{CCFLAGS}
 OPTIMIZE = $self->{OPTIMIZE}
@@ -337,7 +337,6 @@ END
     foreach my $key (@{$self->{CONFIG}}){
         # SITE*EXP macros are defined in &constants; avoid duplicates here
         next if $once_only{$key};
-        $self->{uc $key} = quote_paren($self->{uc $key});
         push @m, uc($key) , ' = ' , $self->{uc $key}, "\n";
         $once_only{$key} = 1;
     }
@@ -455,9 +454,9 @@ MM_REVISION = $self->{MM_REVISION}
     push @m, "
 # Handy lists of source code files:
 XS_FILES = ".$self->wraplist(sort keys %{$self->{XS}})."
-C_FILES  = ".$self->wraplist(@{$self->{C}})."
-O_FILES  = ".$self->wraplist(@{$self->{O_FILES}})."
-H_FILES  = ".$self->wraplist(@{$self->{H}})."
+C_FILES  = ".$self->wraplist(sort @{$self->{C}})."
+O_FILES  = ".$self->wraplist(sort @{$self->{O_FILES}})."
+H_FILES  = ".$self->wraplist(sort @{$self->{H}})."
 MAN1PODS = ".$self->wraplist(sort keys %{$self->{MAN1PODS}})."
 MAN3PODS = ".$self->wraplist(sort keys %{$self->{MAN3PODS}})."
 ";
@@ -466,7 +465,7 @@ MAN3PODS = ".$self->wraplist(sort keys %{$self->{MAN3PODS}})."
     push @m, q{
 # Where is the Config information that we are using/depend on
 CONFIGDEP = $(PERL_ARCHLIBDEP)$(DFSEP)Config.pm $(PERL_INCDEP)$(DFSEP)config.h
-} if -e File::Spec->catfile( $self->{PERL_INC}, 'config.h' );
+} if -e $self->catfile( $self->{PERL_INC}, 'config.h' );
 
 
     push @m, qq{
@@ -492,10 +491,7 @@ PERL_ARCHIVE_AFTER = $self->{PERL_ARCHIVE_AFTER}
 
     push @m, "
 
-TO_INST_PM = ".$self->wraplist(sort keys %{$self->{PM}})."
-
-PM_TO_BLIB = ".$self->wraplist(map { ($_ => $self->{PM}->{$_}) } sort keys %{$self->{PM}})."
-";
+TO_INST_PM = ".$self->wraplist(map $self->quote_dep($_), sort keys %{$self->{PM}})."\n";
 
     join('',@m);
 }
@@ -510,8 +506,9 @@ Same as macro for the depend attribute.
 sub depend {
     my($self,%attribs) = @_;
     my(@m,$key,$val);
-    while (($key,$val) = each %attribs){
-       last unless defined $key;
+    for my $key (sort keys %attribs){
+       my $val = $attribs{$key};
+       next unless defined $key and defined $val;
        push @m, "$key : $val\n";
     }
     join "", @m;
@@ -883,25 +880,43 @@ Defines targets for bootstrap files.
 
 sub dynamic_bs {
     my($self, %attribs) = @_;
-    return '
-BOOTSTRAP =
-' unless $self->has_link_code();
-
-    my $target = $Is{VMS} ? '$(MMS$TARGET)' : '$@';
-
-    return sprintf <<'MAKE_FRAG', ($target) x 2;
-BOOTSTRAP = $(BASEEXT).bs
-
+    return "\nBOOTSTRAP =\n" unless $self->has_link_code();
+    my @exts;
+    if ($self->{XSMULTI}) {
+       @exts = $self->_xs_list_basenames;
+    } else {
+       @exts = '$(BASEEXT)';
+    }
+    return join "\n",
+        "BOOTSTRAP = @{[map { qq{$_.bs} } @exts]}\n",
+        map { $self->_xs_make_bs($_) } @exts;
+}
+
+sub _xs_make_bs {
+    my ($self, $basename) = @_;
+    my ($v, $d, $f) = File::Spec->splitpath($basename);
+    my @d = File::Spec->splitdir($d);
+    shift @d if $self->{XSMULTI} and $d[0] eq 'lib';
+    my $instdir = $self->catdir('$(INST_ARCHLIB)', 'auto', @d, $f);
+    $instdir = '$(INST_ARCHAUTODIR)' if $basename eq '$(BASEEXT)';
+    my $instfile = $self->catfile($instdir, "$f.bs");
+    my $exists = "$instdir\$(DFSEP).exists"; # match blibdirs_target
+    #                                 1          2          3
+    return _sprintf562 <<'MAKE_FRAG', $basename, $instfile, $exists;
 # As Mkbootstrap might not write a file (if none is required)
 # we use touch to prevent make continually trying to remake it.
 # The DynaLoader only reads a non-empty file.
-$(BOOTSTRAP) : $(FIRST_MAKEFILE) $(BOOTDEP) $(INST_ARCHAUTODIR)$(DFSEP).exists
-       $(NOECHO) $(ECHO) "Running Mkbootstrap for $(NAME) ($(BSLOADLIBS))"
+%1$s.bs : $(FIRST_MAKEFILE) $(BOOTDEP)
+       $(NOECHO) $(ECHO) "Running Mkbootstrap for %1$s ($(BSLOADLIBS))"
        $(NOECHO) $(PERLRUN) \
                "-MExtUtils::Mkbootstrap" \
-               -e "Mkbootstrap('$(BASEEXT)','$(BSLOADLIBS)');"
-       $(NOECHO) $(TOUCH) "%s"
-       $(CHMOD) $(PERM_RW) "%s"
+               -e "Mkbootstrap('%1$s','$(BSLOADLIBS)');"
+       $(NOECHO) $(TOUCH) "%1$s.bs"
+       $(CHMOD) $(PERM_RW) "%1$s.bs"
+
+%2$s : %1$s.bs %3$s
+       $(NOECHO) $(RM_RF) %2$s
+       - $(CP_NONEMPTY) %1$s.bs %2$s $(PERM_RW)
 MAKE_FRAG
 }
 
@@ -914,31 +929,84 @@ Defines how to produce the *.so (or equivalent) files.
 sub dynamic_lib {
     my($self, %attribs) = @_;
     return '' unless $self->needs_linking(); #might be because of a subdir
-
     return '' unless $self->has_link_code;
+    my @m = $self->xs_dynamic_lib_macros(\%attribs);
+    my @libs;
+    if ($self->{XSMULTI}) {
+        my @exts = $self->_xs_list_basenames;
+        for my $ext (@exts) {
+            my ($v, $d, $f) = File::Spec->splitpath($ext);
+            my @d = File::Spec->splitdir($d);
+            shift @d if $d[0] eq 'lib';
+            my $instdir = $self->catdir('$(INST_ARCHLIB)', 'auto', @d, $f);
+
+            # Dynamic library names may need special handling.
+            eval { require DynaLoader };
+            if (defined &DynaLoader::mod2fname) {
+                $f = &DynaLoader::mod2fname([@d, $f]);
+            }
 
-    my($otherldflags) = $attribs{OTHERLDFLAGS} || "";
-    my($inst_dynamic_dep) = $attribs{INST_DYNAMIC_DEP} || "";
-    my($armaybe) = $attribs{ARMAYBE} || $self->{ARMAYBE} || ":";
-    my($ldfrom) = '$(LDFROM)';
-    $armaybe = 'ar' if ($Is{OSF} and $armaybe eq ':');
-    my(@m);
-    my $ld_opt = $Is{OS2} ? '$(OPTIMIZE) ' : '';       # Useful on other systems too?
+            my $instfile = $self->catfile($instdir, "$f.\$(DLEXT)");
+            my $objfile = $self->_xsbuild_value('xs', $ext, 'OBJECT');
+            $objfile = "$ext\$(OBJ_EXT)" unless defined $objfile;
+            my $ldfrom = $self->_xsbuild_value('xs', $ext, 'LDFROM');
+            $ldfrom = $objfile unless defined $ldfrom;
+            my $exportlist = "$ext.def";
+            push @libs, [ $objfile, $instfile, $instdir, $ldfrom, $exportlist ];
+        }
+    } else {
+        @libs = ([ qw($(OBJECT) $(INST_DYNAMIC) $(INST_ARCHAUTODIR) $(LDFROM) $(EXPORT_LIST)) ]);
+    }
+    push @m, map { $self->xs_make_dynamic_lib(\%attribs, @$_); } @libs;
+
+    return join("\n",@m);
+}
+
+=item xs_dynamic_lib_macros
+
+Defines the macros for the C<dynamic_lib> section.
+
+=cut
+
+sub xs_dynamic_lib_macros {
+    my ($self, $attribs) = @_;
+    my $otherldflags = $attribs->{OTHERLDFLAGS} || "";
+    my $inst_dynamic_dep = $attribs->{INST_DYNAMIC_DEP} || "";
+    my $armaybe = $self->_xs_armaybe($attribs);
+    my $ld_opt = $Is{OS2} ? '$(OPTIMIZE) ' : ''; # Useful on other systems too?
     my $ld_fix = $Is{OS2} ? '|| ( $(RM_F) $@ && sh -c false )' : '';
-    push(@m,'
-# This section creates the dynamically loadable $(INST_DYNAMIC)
-# from $(OBJECT) and possibly $(MYEXTLIB).
-ARMAYBE = '.$armaybe.'
-OTHERLDFLAGS = '.$ld_opt.$otherldflags.'
-INST_DYNAMIC_DEP = '.$inst_dynamic_dep.'
-INST_DYNAMIC_FIX = '.$ld_fix.'
-
-$(INST_DYNAMIC): $(OBJECT) $(MYEXTLIB) $(INST_ARCHAUTODIR)$(DFSEP).exists $(EXPORT_LIST) $(PERL_ARCHIVEDEP) $(PERL_ARCHIVE_AFTER) $(INST_DYNAMIC_DEP)
-');
+    sprintf <<'EOF', $armaybe, $ld_opt.$otherldflags, $inst_dynamic_dep, $ld_fix;
+# This section creates the dynamically loadable objects from relevant
+# objects and possibly $(MYEXTLIB).
+ARMAYBE = %s
+OTHERLDFLAGS = %s
+INST_DYNAMIC_DEP = %s
+INST_DYNAMIC_FIX = %s
+EOF
+}
+
+sub _xs_armaybe {
+    my ($self, $attribs) = @_;
+    my $armaybe = $attribs->{ARMAYBE} || $self->{ARMAYBE} || ":";
+    $armaybe = 'ar' if ($Is{OSF} and $armaybe eq ':');
+    $armaybe;
+}
+
+=item xs_make_dynamic_lib
+
+Defines the recipes for the C<dynamic_lib> section.
+
+=cut
+
+sub xs_make_dynamic_lib {
+    my ($self, $attribs, $object, $to, $todir, $ldfrom, $exportlist) = @_;
+    $exportlist = '' if $exportlist ne '$(EXPORT_LIST)';
+    my $armaybe = $self->_xs_armaybe($attribs);
+    my @m = sprintf '%s : %s $(MYEXTLIB) %s$(DFSEP).exists %s $(PERL_ARCHIVEDEP) $(PERL_ARCHIVE_AFTER) $(INST_DYNAMIC_DEP)'."\n", $to, $object, $todir, $exportlist;
     if ($armaybe ne ':'){
-       $ldfrom = 'tmp$(LIB_EXT)';
-       push(@m,'       $(ARMAYBE) cr '.$ldfrom.' $(OBJECT)'."\n");
-       push(@m,'       $(RANLIB) '."$ldfrom\n");
+        $ldfrom = 'tmp$(LIB_EXT)';
+        push(@m,"      \$(ARMAYBE) cr $ldfrom $object\n");
+        push(@m,"      \$(RANLIB) $ldfrom\n");
     }
     $ldfrom = "-all $ldfrom -none" if $Is{OSF};
 
@@ -951,16 +1019,14 @@ $(INST_DYNAMIC): $(OBJECT) $(MYEXTLIB) $(INST_ARCHAUTODIR)$(DFSEP).exists $(EXPO
     # is using them.  This is painful if one for instance tries to restart
     # a failed build because the link command will fail unnecessarily 'cos
     # the shared object/library is 'busy'.
-    push(@m,'  $(RM_F) $@
-');
+    push(@m,"  \$(RM_F) \$\@\n");
 
     my $libs = '$(LDLOADLIBS)';
-
     if (($Is{NetBSD} || $Is{Interix} || $Is{Android}) && $Config{'useshrplib'} eq 'true') {
-       # Use nothing on static perl platforms, and to the flags needed
-       # to link against the shared libperl library on shared perl
-       # platforms.  We peek at lddlflags to see if we need -Wl,-R
-       # or -R to add paths to the run-time library search path.
+        # Use nothing on static perl platforms, and to the flags needed
+        # to link against the shared libperl library on shared perl
+        # platforms.  We peek at lddlflags to see if we need -Wl,-R
+        # or -R to add paths to the run-time library search path.
         if ($Config{'lddlflags'} =~ /-Wl,-R/) {
             $libs .= ' "-L$(PERL_INC)" "-Wl,-R$(INSTALLARCHLIB)/CORE" "-Wl,-R$(PERL_ARCHLIB)/CORE" -lperl';
         } elsif ($Config{'lddlflags'} =~ /-R/) {
@@ -974,22 +1040,16 @@ $(INST_DYNAMIC): $(OBJECT) $(MYEXTLIB) $(INST_ARCHAUTODIR)$(DFSEP).exists $(EXPO
 
     my $ld_run_path_shell = "";
     if ($self->{LD_RUN_PATH} ne "") {
-       $ld_run_path_shell = 'LD_RUN_PATH="$(LD_RUN_PATH)" ';
+        $ld_run_path_shell = 'LD_RUN_PATH="$(LD_RUN_PATH)" ';
     }
 
-    push @m, sprintf <<'MAKE', $ld_run_path_shell, $ldrun, $ldfrom, $libs;
-       %s$(LD) %s $(LDDLFLAGS) %s $(OTHERLDFLAGS) -o $@ $(MYEXTLIB)    \
-         $(PERL_ARCHIVE) %s $(PERL_ARCHIVE_AFTER) $(EXPORT_LIST)       \
+    push @m, sprintf <<'MAKE', $ld_run_path_shell, $ldrun, $self->xs_obj_opt('$@'), $ldfrom, $libs, $exportlist;
+       %s$(LD) %s $(LDDLFLAGS) %s $(OTHERLDFLAGS) %s $(MYEXTLIB) \
+         $(PERL_ARCHIVE) %s $(PERL_ARCHIVE_AFTER) %s \
          $(INST_DYNAMIC_FIX)
-MAKE
-
-    push @m, <<'MAKE';
        $(CHMOD) $(PERM_RWX) $@
-       $(NOECHO) $(RM_RF) $(BOOTSTRAP)
-       - $(CP_NONEMPTY) $(BOOTSTRAP) $(INST_BOOT) $(PERM_RW)
 MAKE
-
-    return join('',@m);
+    join '', @m;
 }
 
 =item exescan
@@ -1050,21 +1110,26 @@ WARNING
     }
 
     foreach my $name (@$names){
-        foreach my $dir (@$dirs){
+        my ($abs, $use_dir);
+        if ($self->file_name_is_absolute($name)) {     # /foo/bar
+            $abs = $name;
+        } elsif ($self->canonpath($name) eq
+                 $self->canonpath(basename($name))) {  # foo
+            $use_dir = 1;
+        } else {                                            # foo/bar
+            $abs = $self->catfile($Curdir, $name);
+        }
+        foreach my $dir ($use_dir ? @$dirs : 1){
             next unless defined $dir; # $self->{PERL_SRC} may be undefined
-            my ($abs, $val);
-            if ($self->file_name_is_absolute($name)) {     # /foo/bar
-                $abs = $name;
-            } elsif ($self->canonpath($name) eq
-                     $self->canonpath(basename($name))) {  # foo
-                $abs = $self->catfile($dir, $name);
-            } else {                                            # foo/bar
-                $abs = $self->catfile($Curdir, $name);
-            }
+
+            $abs = $self->catfile($dir, $name)
+                if $use_dir;
+
             print "Checking $abs\n" if ($trace >= 2);
             next unless $self->maybe_command($abs);
             print "Executing $abs\n" if ($trace >= 2);
 
+            my $val;
             my $version_check = qq{"$abs" -le "require $ver; print qq{VER_OK}"};
 
             # To avoid using the unportable 2>&1 to suppress STDERR,
@@ -1191,11 +1256,12 @@ sub _fixin_replace_shebang {
             = reverse grep { $self->file_name_is_absolute($_) } $self->path;
         $interpreter = '';
 
-         foreach my $dir (@absdirs) {
-            if ( $self->maybe_command($cmd) ) {
+        foreach my $dir (@absdirs) {
+            my $maybefile = $self->catfile($dir,$cmd);
+            if ( $self->maybe_command($maybefile) ) {
                 warn "Ignoring $interpreter in $file\n"
                     if $Verbose && $interpreter;
-                $interpreter = $self->catfile( $dir, $cmd );
+                $interpreter = $maybefile;
             }
         }
     }
@@ -1451,7 +1517,10 @@ sub init_MAN3PODS {
     # To force inclusion, just name it "Configure.pod", or override
     # MAN3PODS
     foreach my $name (keys %manifypods) {
-       if ($self->{PERL_CORE} and $name =~ /(config|setup).*\.pm/is) {
+       if (
+            ($self->{PERL_CORE} and $name =~ /(config|setup).*\.pm/is) or
+            ( $name =~ m/^README\.pod$/i ) # don't manify top-level README.pod
+        ) {
            delete $manifypods{$name};
            next;
        }
@@ -1562,7 +1631,14 @@ sub init_PM {
            $inst = $self->libscan($inst);
            print "libscan($path) => '$inst'\n" if ($Verbose >= 2);
            return unless $inst;
-           $self->{PM}{$path} = $inst;
+           if ($self->{XSMULTI} and $inst =~ /\.xs\z/) {
+               my($base); ($base = $path) =~ s/\.xs\z//;
+               $self->{XS}{$path} = "$base.c";
+               push @{$self->{C}}, "$base.c";
+               push @{$self->{O_FILES}}, "$base$self->{OBJ_EXT}";
+           } else {
+               $self->{PM}{$path} = $inst;
+           }
        }, @{$self->{PMLIBDIRS}});
     }
 }
@@ -1987,19 +2063,22 @@ sub init_PERL {
     $self->{PERL_CORE} = $ENV{PERL_CORE} unless exists $self->{PERL_CORE};
     $self->{PERL_CORE} = 0               unless defined $self->{PERL_CORE};
 
+    # Make sure perl can find itself before it's installed.
+    my $lib_paths = $self->{UNINSTALLED_PERL} || $self->{PERL_CORE}
+        ? $self->{PERL_ARCHLIB} ne $self->{PERL_LIB} ?
+            q{ "-I$(PERL_LIB)" "-I$(PERL_ARCHLIB)"} : q{ "-I$(PERL_LIB)"}
+        : undef;
+    my $inst_lib_paths = $self->{INST_ARCHLIB} ne $self->{INST_LIB}
+        ? 'RUN)'.$perlflags.' "-I$(INST_ARCHLIB)" "-I$(INST_LIB)"'
+        : 'RUN)'.$perlflags.' "-I$(INST_LIB)"';
     # How do we run perl?
     foreach my $perl (qw(PERL FULLPERL ABSPERL)) {
         my $run  = $perl.'RUN';
 
         $self->{$run}  = qq{\$($perl)};
+        $self->{$run} .= $lib_paths if $lib_paths;
 
-        # Make sure perl can find itself before it's installed.
-        $self->{$run} .= q{ "-I$(PERL_LIB)" "-I$(PERL_ARCHLIB)"}
-          if $self->{UNINSTALLED_PERL} || $self->{PERL_CORE};
-
-        $self->{$perl.'RUNINST'} =
-          sprintf q{$(%sRUN)%s "-I$(INST_ARCHLIB)" "-I$(INST_LIB)"},
-           $perl, $perlflags;
+        $self->{$perl.'RUNINST'} = '$('.$perl.$inst_lib_paths;
     }
 
     return 1;
@@ -2076,6 +2155,31 @@ sub init_xs {
           $self->catfile('$(INST_ARCHAUTODIR)', '$(DLBASE).$(DLEXT)');
         $self->{INST_BOOT}    =
           $self->catfile('$(INST_ARCHAUTODIR)', '$(BASEEXT).bs');
+       if ($self->{XSMULTI}) {
+           my @exts = $self->_xs_list_basenames;
+           my (@statics, @dynamics, @boots);
+           for my $ext (@exts) {
+               my ($v, $d, $f) = File::Spec->splitpath($ext);
+               my @d = File::Spec->splitdir($d);
+               shift @d if defined $d[0] and $d[0] eq 'lib';
+               my $instdir = $self->catdir('$(INST_ARCHLIB)', 'auto', @d, $f);
+               my $instfile = $self->catfile($instdir, $f);
+               push @statics, "$instfile\$(LIB_EXT)";
+
+                # Dynamic library names may need special handling.
+                my $dynfile = $instfile;
+                eval { require DynaLoader };
+                if (defined &DynaLoader::mod2fname) {
+                    $dynfile = $self->catfile($instdir, &DynaLoader::mod2fname([@d, $f]));
+                }
+
+               push @dynamics, "$dynfile.\$(DLEXT)";
+               push @boots, "$instfile.bs";
+           }
+           $self->{INST_STATIC} = join ' ', @statics;
+           $self->{INST_DYNAMIC} = join ' ', @dynamics;
+           $self->{INST_BOOT} = join ' ', @boots;
+       }
     } else {
         $self->{INST_STATIC}  = '';
         $self->{INST_DYNAMIC} = '';
@@ -2192,7 +2296,7 @@ doc_perl_install :: all
        -$(NOECHO) $(MKPATH) "$(DESTINSTALLARCHLIB)"
        -$(NOECHO) $(DOC_INSTALL) \
                "Module" "$(NAME)" \
-               "installed into" $(INSTALLPRIVLIB) \
+               "installed into" "$(INSTALLPRIVLIB)" \
                LINKTYPE "$(LINKTYPE)" \
                VERSION "$(VERSION)" \
                EXE_FILES "$(EXE_FILES)" \
@@ -2203,7 +2307,7 @@ doc_site_install :: all
        -$(NOECHO) $(MKPATH) "$(DESTINSTALLARCHLIB)"
        -$(NOECHO) $(DOC_INSTALL) \
                "Module" "$(NAME)" \
-               "installed into" $(INSTALLSITELIB) \
+               "installed into" "$(INSTALLSITELIB)" \
                LINKTYPE "$(LINKTYPE)" \
                VERSION "$(VERSION)" \
                EXE_FILES "$(EXE_FILES)" \
@@ -2214,7 +2318,7 @@ doc_vendor_install :: all
        -$(NOECHO) $(MKPATH) "$(DESTINSTALLARCHLIB)"
        -$(NOECHO) $(DOC_INSTALL) \
                "Module" "$(NAME)" \
-               "installed into" $(INSTALLVENDORLIB) \
+               "installed into" "$(INSTALLVENDORLIB)" \
                LINKTYPE "$(LINKTYPE)" \
                VERSION "$(VERSION)" \
                EXE_FILES "$(EXE_FILES)" \
@@ -2249,7 +2353,7 @@ sub installbin {
     my($self) = shift;
 
     return "" unless $self->{EXE_FILES} && ref $self->{EXE_FILES} eq "ARRAY";
-    my @exefiles = @{$self->{EXE_FILES}};
+    my @exefiles = sort @{$self->{EXE_FILES}};
     return "" unless @exefiles;
 
     @exefiles = map vmsify($_), @exefiles if $Is{VMS};
@@ -2265,7 +2369,7 @@ sub installbin {
         $to = vmsify($to) if $Is{VMS};
        $fromto{$from} = $to;
     }
-    my @to   = values %fromto;
+    my @to   = sort values %fromto;
 
     my @m;
     push(@m, qq{
@@ -2281,17 +2385,16 @@ realclean ::
     push @m, map "\t$_\n", $self->split_command('$(RM_F)', @to);
     push @m, "\n";
 
-
     # A target for each exe file.
-    while (my($from,$to) = each %fromto) {
-       last unless defined $from;
-
-       push @m, sprintf <<'MAKE', $to, $from, $to, $from, $to, $to, $to;
-%s : %s $(FIRST_MAKEFILE) $(INST_SCRIPT)$(DFSEP).exists $(INST_BIN)$(DFSEP).exists
-       $(NOECHO) $(RM_F) %s
-       $(CP) %s %s
-       $(FIXIN) %s
-       -$(NOECHO) $(CHMOD) $(PERM_RWX) %s
+    my @froms = sort keys %fromto;
+    for my $from (@froms) {
+        #                              1      2
+        push @m, _sprintf562 <<'MAKE', $from, $fromto{$from};
+%2$s : %1$s $(FIRST_MAKEFILE) $(INST_SCRIPT)$(DFSEP).exists $(INST_BIN)$(DFSEP).exists
+       $(NOECHO) $(RM_F) %2$s
+       $(CP) %1$s %2$s
+       $(FIXIN) %2$s
+       -$(NOECHO) $(CHMOD) $(PERM_RWX) %2$s
 
 MAKE
 
@@ -2300,18 +2403,21 @@ MAKE
     join "", @m;
 }
 
-
 =item linkext (o)
 
 Defines the linkext target which in turn defines the LINKTYPE.
 
 =cut
 
+# LINKTYPE => static or dynamic or ''
 sub linkext {
     my($self, %attribs) = @_;
-    # LINKTYPE => static or dynamic or ''
-    my($linktype) = defined $attribs{LINKTYPE} ?
-      $attribs{LINKTYPE} : '$(LINKTYPE)';
+    my $linktype = $attribs{LINKTYPE};
+    $linktype = $self->{LINKTYPE} unless defined $linktype;
+    if (defined $linktype and $linktype eq '') {
+        warn "Warning: LINKTYPE set to '', no longer necessary\n";
+    }
+    $linktype = '$(LINKTYPE)' unless defined $linktype;
     "
 linkext :: $linktype
        \$(NOECHO) \$(NOOP)
@@ -2326,14 +2432,13 @@ all entries in the directory that match the regular expression.
 =cut
 
 sub lsdir {
-    my($self) = shift;
-    my($dir, $regex) = @_;
-    my(@ls);
-    my $dh = new DirHandle;
-    $dh->open($dir || ".") or return ();
-    @ls = $dh->read;
-    $dh->close;
-    @ls = grep(/$regex/, @ls) if $regex;
+    #  $self
+    my(undef, $dir, $regex) = @_;
+    opendir(my $dh, defined($dir) ? $dir : ".")
+        or return;
+    my @ls = readdir $dh;
+    closedir $dh;
+    @ls = grep(/$regex/, @ls) if defined $regex;
     @ls;
 }
 
@@ -2346,9 +2451,9 @@ into the Makefile.
 
 sub macro {
     my($self,%attribs) = @_;
-    my(@m,$key,$val);
-    while (($key,$val) = each %attribs){
-       last unless defined $key;
+    my @m;
+    foreach my $key (sort keys %attribs) {
+       my $val = $attribs{$key};
        push @m, "$key = $val\n";
     }
     join "", @m;
@@ -2369,11 +2474,13 @@ sub makeaperl {
     my($self, %attribs) = @_;
     my($makefilename, $searchdirs, $static, $extra, $perlinc, $target, $tmp, $libperl) =
        @attribs{qw(MAKE DIRS STAT EXTRA INCL TARGET TMP LIBPERL)};
+    s/^(.*)/"-I$1"/ for @{$perlinc || []};
     my(@m);
     push @m, "
 # --- MakeMaker makeaperl section ---
 MAP_TARGET    = $target
 FULLPERL      = $self->{FULLPERL}
+MAP_PERLINC   = @{$perlinc || []}
 ";
     return join '', @m if $self->{PARENT};
 
@@ -2381,10 +2488,10 @@ FULLPERL      = $self->{FULLPERL}
 
     unless ($self->{MAKEAPERL}) {
        push @m, q{
-$(MAP_TARGET) :: static $(MAKE_APERL_FILE)
+$(MAP_TARGET) :: $(MAKE_APERL_FILE)
        $(MAKE) $(USEMAKEFILE) $(MAKE_APERL_FILE) $@
 
-$(MAKE_APERL_FILE) : $(FIRST_MAKEFILE) pm_to_blib
+$(MAKE_APERL_FILE) : static $(FIRST_MAKEFILE) pm_to_blib
        $(NOECHO) $(ECHO) Writing \"$(MAKE_APERL_FILE)\" for this $(MAP_TARGET)
        $(NOECHO) $(PERLRUNINST) \
                Makefile.PL DIR="}, $dir, q{" \
@@ -2392,23 +2499,18 @@ $(MAKE_APERL_FILE) : $(FIRST_MAKEFILE) pm_to_blib
                MAKEAPERL=1 NORECURS=1 CCCDLFLAGS=};
 
        foreach (@ARGV){
-               if( /\s/ ){
-                       s/=(.*)/='$1'/;
+               my $arg = $_; # avoid lvalue aliasing
+               if ( $arg =~ /(^.*?=)(.*['\s].*)/ ) {
+                       $arg = $1 . $self->quote_literal($2);
                }
-               push @m, " \\\n\t\t$_";
+               push @m, " \\\n\t\t$arg";
        }
-#      push @m, map( " \\\n\t\t$_", @ARGV );
        push @m, "\n";
 
        return join '', @m;
     }
 
-
-
-    my($cccmd, $linkcmd, $lperl);
-
-
-    $cccmd = $self->const_cccmd($libperl);
+    my $cccmd = $self->const_cccmd($libperl);
     $cccmd =~ s/^CCCMD\s*=\s*//;
     $cccmd =~ s/\$\(INC\)/ "-I$self->{PERL_INC}" /;
     $cccmd .= " $Config{cccdlflags}"
@@ -2416,7 +2518,7 @@ $(MAKE_APERL_FILE) : $(FIRST_MAKEFILE) pm_to_blib
     $cccmd =~ s/\(CC\)/\(PERLMAINCC\)/;
 
     # The front matter of the linkcommand...
-    $linkcmd = join ' ', "\$(CC)",
+    my $linkcmd = join ' ', "\$(CC)",
            grep($_, @Config{qw(ldflags ccdlflags)});
     $linkcmd =~ s/\s+/ /g;
     $linkcmd =~ s,(perl\.exp),\$(PERL_INC)/$1,;
@@ -2424,6 +2526,10 @@ $(MAKE_APERL_FILE) : $(FIRST_MAKEFILE) pm_to_blib
     # Which *.a files could we make use of...
     my %static;
     require File::Find;
+    # don't use File::Spec here because on Win32 F::F still uses "/"
+    my $installed_version = join('/',
+       'auto', $self->{FULLEXT}, "$self->{BASEEXT}$self->{LIB_EXT}"
+    );
     File::Find::find(sub {
        return unless m/\Q$self->{LIB_EXT}\E$/;
 
@@ -2469,7 +2575,7 @@ $(MAKE_APERL_FILE) : $(FIRST_MAKEFILE) pm_to_blib
 
        # Once the patch to minimod.PL is in the distribution, I can
        # drop it
-       return if $File::Find::name =~ m:auto/$self->{FULLEXT}/$self->{BASEEXT}$self->{LIB_EXT}\z:;
+       return if $File::Find::name =~ m:\Q$installed_version\E\z:;
        use Cwd 'cwd';
        $static{cwd() . "/" . $_}++;
     }, grep( -d $_, @{$searchdirs || []}) );
@@ -2493,15 +2599,16 @@ $(MAKE_APERL_FILE) : $(FIRST_MAKEFILE) pm_to_blib
 # MAP_STATIC doesn't look into subdirs yet. Once "all" is made and we
 # regenerate the Makefiles, MAP_STATIC and the dependencies for
 # extralibs.all are computed correctly
+    my @map_static = reverse sort keys %static;
     push @m, "
 MAP_LINKCMD   = $linkcmd
-MAP_PERLINC   = @{$perlinc || []}
-MAP_STATIC    = ",
-join(" \\\n\t", reverse sort keys %static), "
+MAP_STATIC    = ", join(" \\\n\t", map { qq{"$_"} } @map_static), "
+MAP_STATICDEP = ", join(' ', map { $self->quote_dep($_) } @map_static), "
 
 MAP_PRELIBS   = $Config{perllibs} $Config{cryptlib}
 ";
 
+    my $lperl;
     if (defined $libperl) {
        ($lperl = $libperl) =~ s/\$\(A\)/$self->{LIB_EXT}/;
     }
@@ -2522,17 +2629,20 @@ MAP_PRELIBS   = $Config{perllibs} $Config{cryptlib}
           }
         }
 
-       print "Warning: $libperl not found
-    If you're going to build a static perl binary, make sure perl is installed
-    otherwise ignore this warning\n"
-               unless (-f $lperl || defined($self->{PERL_SRC}));
+       print <<EOF unless -f $lperl || defined($self->{PERL_SRC});
+Warning: $libperl not found
+If you're going to build a static perl binary, make sure perl is installed
+otherwise ignore this warning
+EOF
     }
 
     # SUNOS ld does not take the full path to a shared library
     my $llibperl = $libperl ? '$(MAP_LIBPERL)' : '-lperl';
+    my $libperl_dep = $self->quote_dep($libperl);
 
     push @m, "
 MAP_LIBPERL = $libperl
+MAP_LIBPERLDEP = $libperl_dep
 LLIBPERL    = $llibperl
 ";
 
@@ -2546,25 +2656,29 @@ $(INST_ARCHAUTODIR)/extralibs.all : $(INST_ARCHAUTODIR)$(DFSEP).exists '.join("
        push @m, "\tcat $catfile >> \$\@\n";
     }
 
-push @m, "
-\$(MAP_TARGET) :: $tmp/perlmain\$(OBJ_EXT) \$(MAP_LIBPERL) \$(MAP_STATIC) \$(INST_ARCHAUTODIR)/extralibs.all
-       \$(MAP_LINKCMD) -o \$\@ \$(OPTIMIZE) $tmp/perlmain\$(OBJ_EXT) \$(LDFROM) \$(MAP_STATIC) \$(LLIBPERL) `cat \$(INST_ARCHAUTODIR)/extralibs.all` \$(MAP_PRELIBS)
-       \$(NOECHO) \$(ECHO) 'To install the new \"\$(MAP_TARGET)\" binary, call'
-       \$(NOECHO) \$(ECHO) '    \$(MAKE) \$(USEMAKEFILE) $makefilename inst_perl MAP_TARGET=\$(MAP_TARGET)'
-       \$(NOECHO) \$(ECHO) 'To remove the intermediate files say'
-       \$(NOECHO) \$(ECHO) '    \$(MAKE) \$(USEMAKEFILE) $makefilename map_clean'
+    my $ldfrom = $self->{XSMULTI} ? '' : '$(LDFROM)';
+    #                             1     2                        3        4
+    push @m, _sprintf562 <<'EOF', $tmp, $self->xs_obj_opt('$@'), $ldfrom, $makefilename;
+$(MAP_TARGET) :: %1$s/perlmain$(OBJ_EXT) $(MAP_LIBPERLDEP) $(MAP_STATICDEP) $(INST_ARCHAUTODIR)/extralibs.all
+       $(MAP_LINKCMD) %2$s $(OPTIMIZE) %1$s/perlmain$(OBJ_EXT) %3$s $(MAP_STATIC) "$(LLIBPERL)" `cat $(INST_ARCHAUTODIR)/extralibs.all` $(MAP_PRELIBS)
+       $(NOECHO) $(ECHO) "To install the new '$(MAP_TARGET)' binary, call"
+       $(NOECHO) $(ECHO) "    $(MAKE) $(USEMAKEFILE) %4$s inst_perl MAP_TARGET=$(MAP_TARGET)"
+       $(NOECHO) $(ECHO) "    $(MAKE) $(USEMAKEFILE) %4$s map_clean"
 
-$tmp/perlmain\$(OBJ_EXT): $tmp/perlmain.c
-";
+%1$s/perlmain\$(OBJ_EXT): %1$s/perlmain.c
+EOF
     push @m, "\t".$self->cd($tmp, qq[$cccmd "-I\$(PERL_INC)" perlmain.c])."\n";
 
-    push @m, qq{
-$tmp/perlmain.c: $makefilename}, q{
+    my $maybe_DynaLoader = $Config{usedl} ? 'q(DynaLoader)' : '';
+    push @m, _sprintf562 <<'EOF', $tmp, $makefilename, $maybe_DynaLoader;
+
+%1$s/perlmain.c: %2$s
        $(NOECHO) $(ECHO) Writing $@
-       $(NOECHO) $(PERL) $(MAP_PERLINC) "-MExtUtils::Miniperl" \\
-               -e "writemain(grep s#.*/auto/##s, split(q| |, q|$(MAP_STATIC)|))" > $@t && $(MV) $@t $@
+       $(NOECHO) $(PERL) $(MAP_PERLINC) "-MExtUtils::Miniperl" \
+               -e "writemain(grep(s#.*/auto/##s, @ARGV), %3$s)" $(MAP_STATIC) > $@t
+       $(MV) $@t $@
 
-};
+EOF
     push @m, "\t", q{$(NOECHO) $(PERL) "$(INSTALLSCRIPT)/fixpmain"
 } if (defined (&Dos::UseLFN) && Dos::UseLFN()==0);
 
@@ -2694,6 +2808,7 @@ sub parse_abstract {
 
     local $/ = "\n";
     open(my $fh, '<', $parsefile) or die "Could not open '$parsefile': $!";
+    binmode $fh;
     my $inpod = 0;
     my $pod_encoding;
     my $package = $self->{DISTNAME};
@@ -2701,7 +2816,7 @@ sub parse_abstract {
     while (<$fh>) {
         $inpod = /^=(?!cut)/ ? 1 : /^=cut/ ? 0 : $inpod;
         next if !$inpod;
-        chop;
+        s#\r*\n\z##; # handle CRLF input
 
         if ( /^=encoding\s*(.*)$/i ) {
             $pod_encoding = $1;
@@ -2766,7 +2881,7 @@ sub parse_version {
         next if $inpod || /^\s*#/;
         chop;
         next if /^\s*(if|unless|elsif)/;
-        if ( m{^ \s* package \s+ \w[\w\:\']* \s+ (v?[0-9._]+) \s* ;  }x ) {
+        if ( m{^ \s* package \s+ \w[\w\:\']* \s+ (v?[0-9._]+) \s* (;|\{)  }x ) {
             local $^W = 0;
             $result = $1;
         }
@@ -2811,7 +2926,16 @@ sub get_version {
 =item pasthru (o)
 
 Defines the string that is passed to recursive make calls in
-subdirectories.
+subdirectories. The variables like C<PASTHRU_DEFINE> are used in each
+level, and passed downwards on the command-line with e.g. the value of
+that level's DEFINE. Example:
+
+    # Level 0 has DEFINE = -Dfunky
+    # This code will define level 0's PASTHRU=PASTHRU_DEFINE="$(DEFINE)
+    #     $(PASTHRU_DEFINE)"
+    # Level 0's $(CCCMD) will include macros $(DEFINE) and $(PASTHRU_DEFINE)
+    # So will level 1's, so when level 1 compiles, it will get right values
+    # And so ad infinitum
 
 =cut
 
@@ -2832,8 +2956,14 @@ sub pasthru {
     }
 
     foreach my $key (qw(DEFINE INC)) {
-        next unless defined $self->{$key};
-       push @pasthru, "PASTHRU_$key=\"\$(PASTHRU_$key)\"";
+        # default to the make var
+        my $val = qq{\$($key)};
+        # expand within perl if given since need to use quote_literal
+        # since INC might include space-protecting ""!
+        chomp($val = $self->{$key}) if defined $self->{$key};
+        $val .= " \$(PASTHRU_$key)";
+        my $quoted = $self->quote_literal($val);
+        push @pasthru, qq{PASTHRU_$key=$quoted};
     }
 
     push @m, "\nPASTHRU = ", join ($sep, @pasthru), "\n";
@@ -2913,7 +3043,7 @@ pm_to_blib({\@ARGV}, '$autodir', q[\$(PM_FILTER)], '\$(PERM_DIR)')
 CODE
 
     my @cmds = $self->split_command($pm_to_blib,
-                  map { ($_, $self->{PM}->{$_}) } sort keys %{$self->{PM}});
+                  map { ($self->quote_literal($_) => $self->quote_literal($self->{PM}->{$_})) } sort keys %{$self->{PM}});
 
     $r .= join '', map { "\t\$(NOECHO) $_\n" } @cmds;
     $r .= qq{\t\$(NOECHO) \$(TOUCH) pm_to_blib\n};
@@ -2921,39 +3051,6 @@ CODE
     return $r;
 }
 
-=item post_constants (o)
-
-Returns an empty string per default. Dedicated to overrides from
-within Makefile.PL after all constants have been defined.
-
-=cut
-
-sub post_constants{
-    "";
-}
-
-=item post_initialize (o)
-
-Returns an empty string per default. Used in Makefile.PLs to add some
-chunk of text to the Makefile after the object is initialized.
-
-=cut
-
-sub post_initialize {
-    "";
-}
-
-=item postamble (o)
-
-Returns an empty string. Can be used in Makefile.PLs to write some
-text to the Makefile at the end.
-
-=cut
-
-sub postamble {
-    "";
-}
-
 # transform dot-separated version string into comma-separated quadruple
 # examples:  '1.2.3.4.5' => '1,2,3,4'
 #            '1.2.3'     => '1,2,3,0'
@@ -2977,25 +3074,23 @@ sub ppd {
     $abstract =~ s/</&lt;/g;
     $abstract =~ s/>/&gt;/g;
 
-    my $author = join(', ',@{$self->{AUTHOR} || []});
+    my $author = join(', ',@{ ref $self->{AUTHOR} eq 'ARRAY' ? $self->{AUTHOR} : [ $self->{AUTHOR} || '']});
     $author =~ s/</&lt;/g;
     $author =~ s/>/&gt;/g;
 
-    my $ppd_file = '$(DISTNAME).ppd';
+    my $ppd_file = "$self->{DISTNAME}.ppd";
 
-    my @ppd_cmds = $self->echo(<<'PPD_HTML', $ppd_file, { append => 0, allow_variables => 1 });
-<SOFTPKG NAME="$(DISTNAME)" VERSION="$(VERSION)">
-PPD_HTML
+    my @ppd_chunks = qq(<SOFTPKG NAME="$self->{DISTNAME}" VERSION="$self->{VERSION}">\n);
 
-    my $ppd_xml = sprintf <<'PPD_HTML', $abstract, $author;
+    push @ppd_chunks, sprintf <<'PPD_HTML', $abstract, $author;
     <ABSTRACT>%s</ABSTRACT>
     <AUTHOR>%s</AUTHOR>
 PPD_HTML
 
-    $ppd_xml .= "    <IMPLEMENTATION>\n";
+    push @ppd_chunks, "    <IMPLEMENTATION>\n";
     if ( $self->{MIN_PERL_VERSION} ) {
         my $min_perl_version = $self->_ppd_version($self->{MIN_PERL_VERSION});
-        $ppd_xml .= sprintf <<'PPD_PERLVERS', $min_perl_version;
+        push @ppd_chunks, sprintf <<'PPD_PERLVERS', $min_perl_version;
         <PERLCORE VERSION="%s" />
 PPD_PERLVERS
 
@@ -3015,7 +3110,7 @@ PPD_PERLVERS
         my %attrs = ( NAME => $name );
         $attrs{VERSION} = $version if $version;
         my $attrs = join " ", map { qq[$_="$attrs{$_}"] } sort keys %attrs;
-        $ppd_xml .= qq(        <REQUIRE $attrs />\n);
+        push @ppd_chunks, qq(        <REQUIRE $attrs />\n);
     }
 
     my $archname = $Config{archname};
@@ -3025,28 +3120,28 @@ PPD_PERLVERS
         # version that changes when binary compatibility may change
         $archname .= "-$Config{PERL_REVISION}.$Config{PERL_VERSION}";
     }
-    $ppd_xml .= sprintf <<'PPD_OUT', $archname;
+    push @ppd_chunks, sprintf <<'PPD_OUT', $archname;
         <ARCHITECTURE NAME="%s" />
 PPD_OUT
 
     if ($self->{PPM_INSTALL_SCRIPT}) {
         if ($self->{PPM_INSTALL_EXEC}) {
-            $ppd_xml .= sprintf qq{        <INSTALL EXEC="%s">%s</INSTALL>\n},
+            push @ppd_chunks, sprintf qq{        <INSTALL EXEC="%s">%s</INSTALL>\n},
                   $self->{PPM_INSTALL_EXEC}, $self->{PPM_INSTALL_SCRIPT};
         }
         else {
-            $ppd_xml .= sprintf qq{        <INSTALL>%s</INSTALL>\n},
+            push @ppd_chunks, sprintf qq{        <INSTALL>%s</INSTALL>\n},
                   $self->{PPM_INSTALL_SCRIPT};
         }
     }
 
     if ($self->{PPM_UNINSTALL_SCRIPT}) {
         if ($self->{PPM_UNINSTALL_EXEC}) {
-            $ppd_xml .= sprintf qq{        <UNINSTALL EXEC="%s">%s</UNINSTALL>\n},
+            push @ppd_chunks, sprintf qq{        <UNINSTALL EXEC="%s">%s</UNINSTALL>\n},
                   $self->{PPM_UNINSTALL_EXEC}, $self->{PPM_UNINSTALL_SCRIPT};
         }
         else {
-            $ppd_xml .= sprintf qq{        <UNINSTALL>%s</UNINSTALL>\n},
+            push @ppd_chunks, sprintf qq{        <UNINSTALL>%s</UNINSTALL>\n},
                   $self->{PPM_UNINSTALL_SCRIPT};
         }
     }
@@ -3054,13 +3149,13 @@ PPD_OUT
     my ($bin_location) = $self->{BINARY_LOCATION} || '';
     $bin_location =~ s/\\/\\\\/g;
 
-    $ppd_xml .= sprintf <<'PPD_XML', $bin_location;
+    push @ppd_chunks, sprintf <<'PPD_XML', $bin_location;
         <CODEBASE HREF="%s" />
     </IMPLEMENTATION>
 </SOFTPKG>
 PPD_XML
 
-    push @ppd_cmds, $self->echo($ppd_xml, $ppd_file, { append => 1 });
+    my @ppd_cmds = $self->stashmeta(join('', @ppd_chunks), $ppd_file);
 
     return sprintf <<'PPD_OUT', join "\n\t", @ppd_cmds;
 # Creates a PPD (Perl Package Description) for a binary distribution.
@@ -3138,29 +3233,29 @@ sub processPL {
     foreach my $plfile (sort keys %$pl_files) {
         my $list = ref($pl_files->{$plfile})
                      ?  $pl_files->{$plfile}
-                    : [$pl_files->{$plfile}];
+                     : [$pl_files->{$plfile}];
 
-       foreach my $target (@$list) {
+        foreach my $target (@$list) {
             if( $Is{VMS} ) {
                 $plfile = vmsify($self->eliminate_macros($plfile));
                 $target = vmsify($self->eliminate_macros($target));
             }
 
-           # Normally a .PL file runs AFTER pm_to_blib so it can have
-           # blib in its @INC and load the just built modules.  BUT if
-           # the generated module is something in $(TO_INST_PM) which
-           # pm_to_blib depends on then it can't depend on pm_to_blib
-           # else we have a dependency loop.
-           my $pm_dep;
-           my $perlrun;
-           if( defined $self->{PM}{$target} ) {
-               $pm_dep  = '';
-               $perlrun = 'PERLRUN';
-           }
-           else {
-               $pm_dep  = 'pm_to_blib';
-               $perlrun = 'PERLRUNINST';
-           }
+            # Normally a .PL file runs AFTER pm_to_blib so it can have
+            # blib in its @INC and load the just built modules.  BUT if
+            # the generated module is something in $(TO_INST_PM) which
+            # pm_to_blib depends on then it can't depend on pm_to_blib
+            # else we have a dependency loop.
+            my $pm_dep;
+            my $perlrun;
+            if( defined $self->{PM}{$target} ) {
+                $pm_dep  = '';
+                $perlrun = 'PERLRUN';
+            }
+            else {
+                $pm_dep  = 'pm_to_blib';
+                $perlrun = 'PERLRUNINST';
+            }
 
             $m .= <<MAKE_FRAG;
 
@@ -3171,7 +3266,7 @@ $target :: $plfile $pm_dep
        \$($perlrun) $plfile $target
 MAKE_FRAG
 
-       }
+        }
     }
 
     return $m;
@@ -3338,29 +3433,86 @@ static :: $(FIRST_MAKEFILE) $(INST_STATIC)
 ';
 }
 
-=item static_lib (o)
+sub static_lib {
+    my($self) = @_;
+    return '' unless $self->has_link_code;
+    my(@m);
+    my @libs;
+    if ($self->{XSMULTI}) {
+       for my $ext ($self->_xs_list_basenames) {
+           my ($v, $d, $f) = File::Spec->splitpath($ext);
+           my @d = File::Spec->splitdir($d);
+           shift @d if $d[0] eq 'lib';
+           my $instdir = $self->catdir('$(INST_ARCHLIB)', 'auto', @d, $f);
+           my $instfile = $self->catfile($instdir, "$f\$(LIB_EXT)");
+           my $objfile = "$ext\$(OBJ_EXT)";
+           push @libs, [ $objfile, $instfile, $instdir ];
+       }
+    } else {
+       @libs = ([ qw($(OBJECT) $(INST_STATIC) $(INST_ARCHAUTODIR)) ]);
+    }
+    push @m, map { $self->xs_make_static_lib(@$_); } @libs;
+    join "\n", @m;
+}
+
+=item xs_make_static_lib
 
-Defines how to produce the *.a (or equivalent) files.
+Defines the recipes for the C<static_lib> section.
 
 =cut
 
-sub static_lib {
-    my($self) = @_;
-    return '' unless $self->has_link_code;
+sub xs_make_static_lib {
+    my ($self, $from, $to, $todir) = @_;
+    my @m = sprintf '%s: %s $(MYEXTLIB) %s$(DFSEP).exists'."\n", $to, $from, $todir;
+    push @m, "\t\$(RM_F) \"\$\@\"\n";
+    push @m, $self->static_lib_fixtures;
+    push @m, $self->static_lib_pure_cmd($from);
+    push @m, "\t\$(CHMOD) \$(PERM_RWX) \$\@\n";
+    push @m, $self->static_lib_closures($todir);
+    join '', @m;
+}
 
-    my(@m);
-    push(@m, <<'END');
+=item static_lib_closures
 
-$(INST_STATIC) : $(OBJECT) $(MYEXTLIB) $(INST_ARCHAUTODIR)$(DFSEP).exists
-       $(RM_RF) $@
-END
+Records C<$(EXTRALIBS)> in F<extralibs.ld> and F<$(PERL_SRC)/ext.libs>.
+
+=cut
 
+sub static_lib_closures {
+    my ($self, $todir) = @_;
+    my @m = sprintf <<'MAKE_FRAG', $todir;
+       $(NOECHO) $(ECHO) "$(EXTRALIBS)" > %s$(DFSEP)extralibs.ld
+MAKE_FRAG
+    # Old mechanism - still available:
+    push @m, <<'MAKE_FRAG' if $self->{PERL_SRC} && $self->{EXTRALIBS};
+       $(NOECHO) $(ECHO) "$(EXTRALIBS)" >> $(PERL_SRC)$(DFSEP)ext.libs
+MAKE_FRAG
+    @m;
+}
+
+=item static_lib_fixtures
+
+Handles copying C<$(MYEXTLIB)> as starter for final static library that
+then gets added to.
+
+=cut
+
+sub static_lib_fixtures {
+    my ($self) = @_;
     # If this extension has its own library (eg SDBM_File)
     # then copy that to $(INST_STATIC) and add $(OBJECT) into it.
-    push(@m, <<'MAKE_FRAG') if $self->{MYEXTLIB};
-       $(CP) $(MYEXTLIB) "$@"
-MAKE_FRAG
+    return unless $self->{MYEXTLIB};
+    "\t\$(CP) \$(MYEXTLIB) \"\$\@\"\n";
+}
+
+=item static_lib_pure_cmd
+
+Defines how to run the archive utility.
 
+=cut
+
+sub static_lib_pure_cmd {
+    my ($self, $from) = @_;
     my $ar;
     if (exists $self->{FULL_AR} && -x $self->{FULL_AR}) {
         # Prefer the absolute pathed ar if available so that PATH
@@ -3369,18 +3521,10 @@ MAKE_FRAG
     } else {
         $ar = 'AR';
     }
-    push @m, sprintf <<'MAKE_FRAG', $ar;
-       $(%s) $(AR_STATIC_ARGS) $@ $(OBJECT) && $(RANLIB) $@
-       $(CHMOD) $(PERM_RWX) $@
-       $(NOECHO) $(ECHO) "$(EXTRALIBS)" > "$(INST_ARCHAUTODIR)/extralibs.ld"
+    sprintf <<'MAKE_FRAG', $ar, $from;
+       $(%s) $(AR_STATIC_ARGS) "$@" %s
+       $(RANLIB) "$@"
 MAKE_FRAG
-
-    # Old mechanism - still available:
-    push @m, <<'MAKE_FRAG' if $self->{PERL_SRC} && $self->{EXTRALIBS};
-       $(NOECHO) $(ECHO) "$(EXTRALIBS)" >> "$(PERL_SRC)/ext.libs"
-MAKE_FRAG
-
-    join('', @m);
 }
 
 =item staticmake (o)
@@ -3459,15 +3603,16 @@ sub subdirs {
     # subdirectories containing further Makefile.PL scripts.
     # It calls the subdir_x() method for each subdirectory.
     foreach my $dir (@{$self->{DIR}}){
-       push(@m, $self->subdir_x($dir));
+       push @m, $self->subdir_x($dir);
 ####   print "Including $dir subdirectory\n";
     }
     if (@m){
-       unshift(@m, "
+       unshift @m, <<'EOF';
+
 # The default clean, realclean and test targets in this Makefile
 # have automatically been given entries for each subdir.
 
-");
+EOF
     } else {
        push(@m, "\n# none")
     }
@@ -3481,8 +3626,6 @@ Defines the test targets.
 =cut
 
 sub test {
-# --- Test and Installation Sections ---
-
     my($self, %attribs) = @_;
     my $tests = $attribs{TESTS} || '';
     if (!$tests && -d 't' && defined $attribs{RECURSIVE_TEST_FILES}) {
@@ -3494,8 +3637,9 @@ sub test {
     # have to do this because nmake is broken
     $tests =~ s!/!\\!g if $self->is_make_type('nmake');
     # note: 'test.pl' name is also hardcoded in init_dirscan()
-    my(@m);
-    push(@m,"
+    my @m;
+    my $default_testtype = $Config{usedl} ? 'dynamic' : 'static';
+    push @m, <<EOF;
 TEST_VERBOSE=0
 TEST_TYPE=test_\$(LINKTYPE)
 TEST_FILE = test.pl
@@ -3503,56 +3647,59 @@ TEST_FILES = $tests
 TESTDB_SW = -d
 
 testdb :: testdb_\$(LINKTYPE)
+       \$(NOECHO) \$(NOOP)
 
-test :: \$(TEST_TYPE) subdirs-test
-
-subdirs-test ::
+test :: \$(TEST_TYPE)
        \$(NOECHO) \$(NOOP)
 
-");
+# Occasionally we may face this degenerate target:
+test_ : test_$default_testtype
+       \$(NOECHO) \$(NOOP)
 
-    foreach my $dir (@{ $self->{DIR} }) {
-        my $test = $self->cd($dir, '$(MAKE) test $(PASTHRU)');
+EOF
 
-        push @m, <<END
-subdirs-test ::
-       \$(NOECHO) $test
+    for my $linktype (qw(dynamic static)) {
+        my $directdeps = "$linktype pure_all";
+        push @m, "subdirs-test_$linktype :: $directdeps\n";
+        foreach my $dir (@{ $self->{DIR} }) {
+            my $test = $self->cd($dir, "\$(MAKE) test_$linktype \$(PASTHRU)");
+            push @m, "\t\$(NOECHO) $test\n";
+        }
+        push @m, "\n";
+        if ($tests or -f "test.pl") {
+            for my $testspec ([ '', '' ], [ 'db', ' $(TESTDB_SW)' ]) {
+                my ($db, $switch) = @$testspec;
+                my ($command, $deps);
+                # if testdb, build all but don't test all
+                $deps = $db eq 'db' ? $directdeps : "subdirs-test_$linktype";
+                if ($linktype eq 'static' and $self->needs_linking) {
+                    my $target = File::Spec->rel2abs('$(MAP_TARGET)');
+                    $command = qq{"$target" \$(MAP_PERLINC)};
+                    $deps .= ' $(MAP_TARGET)';
+                } else {
+                    $command = '$(FULLPERLRUN)' . $switch;
+                }
+                push @m, "test${db}_$linktype :: $deps\n";
+                if ($db eq 'db') {
+                    push @m, $self->test_via_script($command, '$(TEST_FILE)')
+                } else {
+                    push @m, $self->test_via_script($command, '$(TEST_FILE)')
+                        if -f "test.pl";
+                    push @m, $self->test_via_harness($command, '$(TEST_FILES)')
+                        if $tests;
+                }
+                push @m, "\n";
+            }
+        } else {
+            push @m, _sprintf562 <<'EOF', $linktype;
+testdb_%1$s test_%1$s :: subdirs-test_%1$s
+       $(NOECHO) $(ECHO) 'No tests defined for $(NAME) extension.'
 
-END
+EOF
+        }
     }
 
-    push(@m, "\t\$(NOECHO) \$(ECHO) 'No tests defined for \$(NAME) extension.'\n")
-       unless $tests or -f "test.pl" or @{$self->{DIR}};
-    push(@m, "\n");
-
-    push(@m, "test_dynamic :: pure_all\n");
-    push(@m, $self->test_via_harness('$(FULLPERLRUN)', '$(TEST_FILES)'))
-      if $tests;
-    push(@m, $self->test_via_script('$(FULLPERLRUN)', '$(TEST_FILE)'))
-      if -f "test.pl";
-    push(@m, "\n");
-
-    push(@m, "testdb_dynamic :: pure_all\n");
-    push(@m, $self->test_via_script('$(FULLPERLRUN) $(TESTDB_SW)',
-                                    '$(TEST_FILE)'));
-    push(@m, "\n");
-
-    # Occasionally we may face this degenerate target:
-    push @m, "test_ : test_dynamic\n\n";
-
-    if ($self->needs_linking()) {
-       push(@m, "test_static :: pure_all \$(MAP_TARGET)\n");
-       push(@m, $self->test_via_harness('./$(MAP_TARGET)', '$(TEST_FILES)')) if $tests;
-       push(@m, $self->test_via_script('./$(MAP_TARGET)', '$(TEST_FILE)')) if -f "test.pl";
-       push(@m, "\n");
-       push(@m, "testdb_static :: pure_all \$(MAP_TARGET)\n");
-       push(@m, $self->test_via_script('./$(MAP_TARGET) $(TESTDB_SW)', '$(TEST_FILE)'));
-       push(@m, "\n");
-    } else {
-       push @m, "test_static :: test_dynamic\n";
-       push @m, "testdb_static :: testdb_dynamic\n";
-    }
-    join("", @m);
+    join "", @m;
 }
 
 =item test_via_harness (override)
@@ -3605,7 +3752,7 @@ sub tool_xsubpp {
     }
     die "ExtUtils::MM_Unix::tool_xsubpp : Can't find xsubpp" if !$foundxsubpp;
 
-    my $tmdir   = File::Spec->catdir($self->{PERL_LIB},"ExtUtils");
+    my $tmdir   = $self->catdir($self->{PERL_LIB},"ExtUtils");
     my(@tmdeps) = $self->catfile($tmdir,'typemap');
     if( $self->{TYPEMAPS} ){
         foreach my $typemap (@{$self->{TYPEMAPS}}){
@@ -3613,12 +3760,21 @@ sub tool_xsubpp {
                 warn "Typemap $typemap not found.\n";
             }
             else {
-                push(@tmdeps,  $typemap);
+                $typemap = vmsify($typemap) if $Is{VMS};
+                push(@tmdeps, $typemap);
             }
         }
     }
     push(@tmdeps, "typemap") if -f "typemap";
-    my @tmargs = map(qq{-typemap "$_"}, @tmdeps);
+    # absolutised because with deep-located typemaps, eg "lib/XS/typemap",
+    # if xsubpp is called from top level with
+    #     $(XSUBPP) ... -typemap "lib/XS/typemap" "lib/XS/Test.xs"
+    # it says:
+    #     Can't find lib/XS/type map in (fulldir)/lib/XS
+    # because ExtUtils::ParseXS::process_file chdir's to .xs file's
+    # location. This is the only way to get all specified typemaps used,
+    # wherever located.
+    my @tmargs = map { '-typemap '.$self->quote_literal(File::Spec->rel2abs($_)) } @tmdeps;
     $_ = $self->quote_dep($_) for @tmdeps;
     if( exists $self->{XSOPT} ){
         unshift( @tmargs, $self->{XSOPT} );
@@ -3679,19 +3835,21 @@ sub top_targets {
 
     push @m, $self->all_target, "\n" unless $self->{SKIPHASH}{'all'};
 
-    push @m, '
+    push @m, sprintf <<'EOF';
 pure_all :: config pm_to_blib subdirs linkext
        $(NOECHO) $(NOOP)
 
+       $(NOECHO) $(NOOP)
+
 subdirs :: $(MYEXTLIB)
        $(NOECHO) $(NOOP)
 
 config :: $(FIRST_MAKEFILE) blibdirs
        $(NOECHO) $(NOOP)
-';
+EOF
 
     push @m, '
-$(O_FILES): $(H_FILES)
+$(O_FILES) : $(H_FILES)
 ' if @{$self->{O_FILES} || []} && @{$self->{H} || []};
 
     push @m, q{
@@ -3728,7 +3886,8 @@ sub xs_c {
     return '' unless $self->needs_linking();
     '
 .xs.c:
-       $(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $(XSUBPP_EXTRA_ARGS) $*.xs > $*.xsc && $(MV) $*.xsc $*.c
+       $(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $(XSUBPP_EXTRA_ARGS) $*.xs > $*.xsc
+       $(MV) $*.xsc $*.c
 ';
 }
 
@@ -3743,27 +3902,73 @@ sub xs_cpp {
     return '' unless $self->needs_linking();
     '
 .xs.cpp:
-       $(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $*.xs > $*.xsc && $(MV) $*.xsc $*.cpp
+       $(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $*.xs > $*.xsc
+       $(MV) $*.xsc $*.cpp
 ';
 }
 
 =item xs_o (o)
 
-Defines suffix rules to go from XS to object files directly. This is
-only intended for broken make implementations.
+Defines suffix rules to go from XS to object files directly. This was
+originally only intended for broken make implementations, but is now
+necessary for per-XS file under C<XSMULTI>, since each XS file might
+have an individual C<$(VERSION)>.
 
 =cut
 
-sub xs_o {     # many makes are too dumb to use xs_c then c_o
-    my($self) = shift;
+sub xs_o {
+    my ($self) = @_;
     return '' unless $self->needs_linking();
-    '
-.xs$(OBJ_EXT):
-       $(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $*.xs > $*.xsc && $(MV) $*.xsc $*.c
-       $(CCCMD) $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) $(DEFINE) $*.c
-';
+    my $m_o = $self->{XSMULTI} ? $self->xs_obj_opt('$*$(OBJ_EXT)') : '';
+    my $frag = '';
+    # dmake makes noise about ambiguous rule
+    $frag .= sprintf <<'EOF', $m_o unless $self->is_make_type('dmake');
+.xs$(OBJ_EXT) :
+       $(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $*.xs > $*.xsc
+       $(MV) $*.xsc $*.c
+       $(CCCMD) $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) $(DEFINE) $*.c %s
+EOF
+    if ($self->{XSMULTI}) {
+       for my $ext ($self->_xs_list_basenames) {
+           my $pmfile = "$ext.pm";
+           croak "$ext.xs has no matching $pmfile: $!" unless -f $pmfile;
+           my $version = $self->parse_version($pmfile);
+           my $cccmd = $self->{CONST_CCCMD};
+           $cccmd =~ s/^\s*CCCMD\s*=\s*//;
+           $cccmd =~ s/\$\(DEFINE_VERSION\)/-DVERSION=\\"$version\\"/;
+           $cccmd =~ s/\$\(XS_DEFINE_VERSION\)/-DXS_VERSION=\\"$version\\"/;
+            $self->_xsbuild_replace_macro($cccmd, 'xs', $ext, 'INC');
+            my $define = '$(DEFINE)';
+            $self->_xsbuild_replace_macro($define, 'xs', $ext, 'DEFINE');
+            #                             1     2       3     4
+            $frag .= _sprintf562 <<'EOF', $ext, $cccmd, $m_o, $define;
+
+%1$s$(OBJ_EXT): %1$s.xs
+       $(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $*.xs > $*.xsc
+       $(MV) $*.xsc $*.c
+       %2$s $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) %4$s $*.c %3$s
+EOF
+       }
+    }
+    $frag;
 }
 
+# param gets modified
+sub _xsbuild_replace_macro {
+    my ($self, undef, $xstype, $ext, $varname) = @_;
+    my $value = $self->_xsbuild_value($xstype, $ext, $varname);
+    return unless defined $value;
+    $_[1] =~ s/\$\($varname\)/$value/;
+}
+
+sub _xsbuild_value {
+    my ($self, $xstype, $ext, $varname) = @_;
+    return $self->{XSBUILD}{$xstype}{$ext}{$varname}
+        if $self->{XSBUILD}{$xstype}{$ext}{$varname};
+    return $self->{XSBUILD}{$xstype}{all}{$varname}
+        if $self->{XSBUILD}{$xstype}{all}{$varname};
+    ();
+}
 
 1;
 
index fab18df..8565dc2 100644 (file)
@@ -15,13 +15,14 @@ BEGIN {
 
 use File::Basename;
 
-our $VERSION = '7.10_01';
+our $VERSION = '7.18';
+$VERSION = eval $VERSION;
 
 require ExtUtils::MM_Any;
 require ExtUtils::MM_Unix;
 our @ISA = qw( ExtUtils::MM_Any ExtUtils::MM_Unix );
 
-use ExtUtils::MakeMaker qw($Verbose neatvalue);
+use ExtUtils::MakeMaker qw($Verbose neatvalue _sprintf562);
 our $Revision = $ExtUtils::MakeMaker::Revision;
 
 
@@ -302,15 +303,22 @@ sub maybe_command {
 
 =item pasthru (override)
 
-VMS has $(MMSQUALIFIERS) which is a listing of all the original command line
-options.  This is used in every invocation of make in the VMS Makefile so
-PASTHRU should not be necessary.  Using PASTHRU tends to blow commands past
-the 256 character limit.
+The list of macro definitions to be passed through must be specified using
+the /MACRO qualifier and must not add another /DEFINE qualifier.  We prepend
+our own comma here to the contents of $(PASTHRU_DEFINE) because it is often
+empty and a comma always present in CCFLAGS would generate a missing
+qualifier value error.
 
 =cut
 
 sub pasthru {
-    return "PASTHRU=\n";
+    my($self) = shift;
+    my $pasthru = $self->SUPER::pasthru;
+    $pasthru =~ s|(PASTHRU\s*=\s*)|$1/MACRO=(|;
+    $pasthru =~ s|\n\z|)\n|m;
+    $pasthru =~ s|/defi?n?e?=\(?([^\),]+)\)?|,$1|ig;
+
+    return $pasthru;
 }
 
 
@@ -725,13 +733,14 @@ sub cflags {
                my $term = $1;
                $term =~ s:^\((.+)\)$:$1:;
                push @terms, $term;
-           }
+       }
        if ($type eq 'Def') {
            push @terms, qw[ $(DEFINE_VERSION) $(XS_DEFINE_VERSION) ];
        }
        if (@terms) {
            $quals =~ s:/${type}i?n?e?=[^/]+::ig;
-           $quals .= "/${type}ine=(" . join(',',@terms) . ')';
+            # PASTHRU_DEFINE will have its own comma
+           $quals .= "/${type}ine=(" . join(',',@terms) . ($type eq 'Def' ? '$(PASTHRU_DEFINE)' : '') . ')';
        }
     }
 
@@ -884,13 +893,13 @@ sub c_o {
     return '' unless $self->needs_linking();
     '
 .c$(OBJ_EXT) :
-       $(CCCMD) $(CCCDLFLAGS) $(MMS$TARGET_NAME).c
+       $(CCCMD) $(CCCDLFLAGS) $(MMS$TARGET_NAME).c /OBJECT=$(MMS$TARGET_NAME)$(OBJ_EXT)
 
 .cpp$(OBJ_EXT) :
-       $(CCCMD) $(CCCDLFLAGS) $(MMS$TARGET_NAME).cpp
+       $(CCCMD) $(CCCDLFLAGS) $(MMS$TARGET_NAME).cpp /OBJECT=$(MMS$TARGET_NAME)$(OBJ_EXT)
 
 .cxx$(OBJ_EXT) :
-       $(CCCMD) $(CCCDLFLAGS) $(MMS$TARGET_NAME).cxx
+       $(CCCMD) $(CCCDLFLAGS) $(MMS$TARGET_NAME).cxx /OBJECT=$(MMS$TARGET_NAME)$(OBJ_EXT)
 
 ';
 }
@@ -906,7 +915,8 @@ sub xs_c {
     return '' unless $self->needs_linking();
     '
 .xs.c :
-       $(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $(MMS$TARGET_NAME).xs >$(MMS$TARGET)
+       $(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $(MMS$TARGET_NAME).xs >$(MMS$TARGET_NAME).xsc
+       $(MV) $(MMS$TARGET_NAME).xsc $(MMS$TARGET_NAME).c
 ';
 }
 
@@ -916,85 +926,211 @@ Use MM[SK] macros, and VMS command line for C compiler.
 
 =cut
 
-sub xs_o {     # many makes are too dumb to use xs_c then c_o
-    my($self) = @_;
+sub xs_o {
+    my ($self) = @_;
     return '' unless $self->needs_linking();
-    '
+    my $frag = '
 .xs$(OBJ_EXT) :
-       $(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $(MMS$TARGET_NAME).xs >$(MMS$TARGET_NAME).c
-       $(CCCMD) $(CCCDLFLAGS) $(MMS$TARGET_NAME).c
+       $(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $(MMS$TARGET_NAME).xs >$(MMS$TARGET_NAME).xsc
+       $(MV) $(MMS$TARGET_NAME).xsc $(MMS$TARGET_NAME).c
+       $(CCCMD) $(CCCDLFLAGS) $(MMS$TARGET_NAME).c /OBJECT=$(MMS$TARGET_NAME)$(OBJ_EXT)
 ';
+    if ($self->{XSMULTI}) {
+       for my $ext ($self->_xs_list_basenames) {
+           my $version = $self->parse_version("$ext.pm");
+           my $ccflags = $self->{CCFLAGS};
+           $ccflags =~ s/\$\(DEFINE_VERSION\)/\"VERSION_MACRO=\\"\"$version\\"\"/;
+           $ccflags =~ s/\$\(XS_DEFINE_VERSION\)/\"XS_VERSION_MACRO=\\"\"$version\\"\"/;
+           $self->_xsbuild_replace_macro($ccflags, 'xs', $ext, 'INC');
+           $self->_xsbuild_replace_macro($ccflags, 'xs', $ext, 'DEFINE');
+
+           $frag .= _sprintf562 <<'EOF', $ext, $ccflags;
+
+%1$s$(OBJ_EXT) : %1$s.xs
+       $(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $(MMS$TARGET_NAME).xs > $(MMS$TARGET_NAME).xsc
+       $(MV) $(MMS$TARGET_NAME).xsc $(MMS$TARGET_NAME).c
+       $(CC)%2$s$(OPTIMIZE) $(CCCDLFLAGS) $(MMS$TARGET_NAME).c /OBJECT=$(MMS$TARGET_NAME)$(OBJ_EXT)
+EOF
+       }
+    }
+    $frag;
 }
 
+=item _xsbuild_replace_macro (override)
 
-=item dlsyms (override)
+There is no simple replacement possible since a qualifier and all its
+subqualifiers must be considered together, so we use our own utility
+routine for the replacement.
 
-Create VMS linker options files specifying universal symbols for this
-extension's shareable image, and listing other shareable images or
-libraries to which it should be linked.
+=cut
+
+sub _xsbuild_replace_macro {
+    my ($self, undef, $xstype, $ext, $varname) = @_;
+    my $value = $self->_xsbuild_value($xstype, $ext, $varname);
+    return unless defined $value;
+    $_[1] = _vms_replace_qualifier($self, $_[1], $value, $varname);
+}
+
+=item _xsbuild_value (override)
+
+Convert the extension spec to Unix format, as that's what will
+match what's in the XSBUILD data structure.
 
 =cut
 
-sub dlsyms {
-    my($self,%attribs) = @_;
+sub _xsbuild_value {
+    my ($self, $xstype, $ext, $varname) = @_;
+    $ext = unixify($ext);
+    return $self->SUPER::_xsbuild_value($xstype, $ext, $varname);
+}
 
-    return '' unless $self->needs_linking();
+sub _vms_replace_qualifier {
+    my ($self, $flags, $newflag, $macro) = @_;
+    my $qual_type;
+    my $type_suffix;
+    my $quote_subquals = 0;
+    my @subquals_new = split /\s+/, $newflag;
+
+    if ($macro eq 'DEFINE') {
+        $qual_type = 'Def';
+        $type_suffix = 'ine';
+        map { $_ =~ s/^-D// } @subquals_new;
+        $quote_subquals = 1;
+    }
+    elsif ($macro eq 'INC') {
+        $qual_type = 'Inc';
+        $type_suffix = 'lude';
+        map { $_ =~ s/^-I//; $_ = $self->fixpath($_) } @subquals_new;
+    }
 
-    my($funcs) = $attribs{DL_FUNCS} || $self->{DL_FUNCS} || {};
-    my($vars)  = $attribs{DL_VARS}  || $self->{DL_VARS}  || [];
-    my($funclist)  = $attribs{FUNCLIST}  || $self->{FUNCLIST}  || [];
-    my(@m);
+    my @subquals = ();
+    while ($flags =~ m:/${qual_type}\S{0,4}=([^/]+):ig) {
+        my $term = $1;
+        $term =~ s/\"//g;
+        $term =~ s:^\((.+)\)$:$1:;
+        push @subquals, split /,/, $term;
+    }
+    for my $new (@subquals_new) {
+        my ($sq_new, $sqval_new) = split /=/, $new;
+        my $replaced_old = 0;
+        for my $old (@subquals) {
+            my ($sq, $sqval) = split /=/, $old;
+            if ($sq_new eq $sq) {
+                $old = $sq_new;
+                $old .= '=' . $sqval_new if defined($sqval_new) and length($sqval_new);
+                $replaced_old = 1;
+                last;
+            }
+        }
+        push @subquals, $new unless $replaced_old;
+    }
 
-    unless ($self->{SKIPHASH}{'dynamic'}) {
-       push(@m,'
-dynamic :: $(INST_ARCHAUTODIR)$(BASEEXT).opt
-       $(NOECHO) $(NOOP)
-');
+    if (@subquals) {
+        $flags =~ s:/${qual_type}\S{0,4}=[^/]+::ig;
+        # add quotes if requested but not for unexpanded macros
+        map { $_ = qq/"$_"/ if $_ !~ m/^\$\(/ } @subquals if $quote_subquals;
+        $flags .= "/${qual_type}$type_suffix=(" . join(',',@subquals) . ')';
     }
 
-    push(@m,'
-static :: $(INST_ARCHAUTODIR)$(BASEEXT).opt
-       $(NOECHO) $(NOOP)
-') unless $self->{SKIPHASH}{'static'};
+    return $flags;
+}
 
-    push @m,'
-$(INST_ARCHAUTODIR)$(BASEEXT).opt : $(BASEEXT).opt
-       $(CP) $(MMS$SOURCE) $(MMS$TARGET)
 
-$(BASEEXT).opt : Makefile.PL
-       $(PERLRUN) -e "use ExtUtils::Mksymlists;" -
-       ',qq[-e "Mksymlists('NAME' => '$self->{NAME}', 'DL_FUNCS' => ],
-       neatvalue($funcs),q[, 'DL_VARS' => ],neatvalue($vars),
-       q[, 'FUNCLIST' => ],neatvalue($funclist),qq[)"\n];
-
-    push @m, ' $(PERL) -e "print ""$(INST_STATIC)/Include=';
-    if ($self->{OBJECT} =~ /\bBASEEXT\b/ or
-        $self->{OBJECT} =~ /\b$self->{BASEEXT}\b/i) {
-        push @m, ($Config{d_vms_case_sensitive_symbols}
-                  ? uc($self->{BASEEXT}) :'$(BASEEXT)');
-    }
-    else {  # We don't have a "main" object file, so pull 'em all in
-        # Upcase module names if linker is being case-sensitive
-        my($upcase) = $Config{d_vms_case_sensitive_symbols};
-        my(@omods) = split ' ', $self->eliminate_macros($self->{OBJECT});
-        for (@omods) {
-            s/\.[^.]*$//;         # Trim off file type
-            s[\$\(\w+_EXT\)][];   # even as a macro
-            s/.*[:>\/\]]//;       # Trim off dir spec
-            $_ = uc if $upcase;
-        };
-
-        my(@lines);
-        my $tmp = shift @omods;
-        foreach my $elt (@omods) {
-            $tmp .= ",$elt";
-            if (length($tmp) > 80) { push @lines, $tmp;  $tmp = ''; }
+sub xs_dlsyms_ext {
+    '.opt';
+}
+
+=item dlsyms (override)
+
+Create VMS linker options files specifying universal symbols for this
+extension's shareable image(s), and listing other shareable images or
+libraries to which it should be linked.
+
+=cut
+
+sub dlsyms {
+    my ($self, %attribs) = @_;
+    return '' unless $self->needs_linking;
+    $self->xs_dlsyms_iterator;
+}
+
+sub xs_make_dlsyms {
+    my ($self, $attribs, $target, $dep, $name, $dlbase, $funcs, $funclist, $imports, $vars, $extra) = @_;
+    my @m;
+    my $instloc;
+    if ($self->{XSMULTI}) {
+       my ($v, $d, $f) = File::Spec->splitpath($target);
+       my @d = File::Spec->splitdir($d);
+       shift @d if $d[0] eq 'lib';
+       $instloc = $self->catfile('$(INST_ARCHLIB)', 'auto', @d, $f);
+       push @m,"\ndynamic :: $instloc\n\t\$(NOECHO) \$(NOOP)\n"
+         unless $self->{SKIPHASH}{'dynamic'};
+       push @m,"\nstatic :: $instloc\n\t\$(NOECHO) \$(NOOP)\n"
+         unless $self->{SKIPHASH}{'static'};
+       push @m, "\n", sprintf <<'EOF', $instloc, $target;
+%s : %s
+       $(CP) $(MMS$SOURCE) $(MMS$TARGET)
+EOF
+    }
+    else {
+       push @m,"\ndynamic :: \$(INST_ARCHAUTODIR)$self->{BASEEXT}.opt\n\t\$(NOECHO) \$(NOOP)\n"
+         unless $self->{SKIPHASH}{'dynamic'};
+       push @m,"\nstatic :: \$(INST_ARCHAUTODIR)$self->{BASEEXT}.opt\n\t\$(NOECHO) \$(NOOP)\n"
+         unless $self->{SKIPHASH}{'static'};
+       push @m, "\n", sprintf <<'EOF', $target;
+$(INST_ARCHAUTODIR)$(BASEEXT).opt : %s
+       $(CP) $(MMS$SOURCE) $(MMS$TARGET)
+EOF
+    }
+    push @m,
+     "\n$target : $dep\n\t",
+     q!$(PERLRUN) -MExtUtils::Mksymlists -e "Mksymlists('NAME'=>'!, $name,
+     q!', 'DLBASE' => '!,$dlbase,
+     q!', 'DL_FUNCS' => !,neatvalue($funcs),
+     q!, 'FUNCLIST' => !,neatvalue($funclist),
+     q!, 'IMPORTS' => !,neatvalue($imports),
+     q!, 'DL_VARS' => !, neatvalue($vars);
+    push @m, $extra if defined $extra;
+    push @m, qq!);"\n\t!;
+    # Can't use dlbase as it's been through mod2fname.
+    my $olb_base = basename($target, '.opt');
+    if ($self->{XSMULTI}) {
+        # We've been passed everything but the kitchen sink -- and the location of the
+        # static library we're using to build the dynamic library -- so concoct that
+        # location from what we do have.
+        my $olb_dir = $self->catdir(dirname($instloc), $olb_base);
+        push @m, qq!\$(PERL) -e "print ""${olb_dir}${olb_base}\$(LIB_EXT)/Include=!;
+        push @m, ($Config{d_vms_case_sensitive_symbols} ? uc($olb_base) : $olb_base);
+        push @m, '\n' . $olb_dir . $olb_base . '$(LIB_EXT)/Library\n"";" >>$(MMS$TARGET)',"\n";
+    }
+    else {
+        push @m, qq!\$(PERL) -e "print ""\$(INST_ARCHAUTODIR)${olb_base}\$(LIB_EXT)/Include=!;
+        if ($self->{OBJECT} =~ /\bBASEEXT\b/ or
+            $self->{OBJECT} =~ /\b$self->{BASEEXT}\b/i) {
+            push @m, ($Config{d_vms_case_sensitive_symbols}
+                     ? uc($self->{BASEEXT}) :'$(BASEEXT)');
+        }
+        else {  # We don't have a "main" object file, so pull 'em all in
+            # Upcase module names if linker is being case-sensitive
+            my($upcase) = $Config{d_vms_case_sensitive_symbols};
+            my(@omods) = split ' ', $self->eliminate_macros($self->{OBJECT});
+            for (@omods) {
+                s/\.[^.]*$//;         # Trim off file type
+                s[\$\(\w+_EXT\)][];   # even as a macro
+                s/.*[:>\/\]]//;       # Trim off dir spec
+                $_ = uc if $upcase;
+            };
+            my(@lines);
+            my $tmp = shift @omods;
+            foreach my $elt (@omods) {
+                $tmp .= ",$elt";
+                if (length($tmp) > 80) { push @lines, $tmp;  $tmp = ''; }
+            }
+            push @lines, $tmp;
+            push @m, '(', join( qq[, -\\n\\t"";" >>\$(MMS\$TARGET)\n\t\$(PERL) -e "print ""], @lines),')';
         }
-        push @lines, $tmp;
-        push @m, '(', join( qq[, -\\n\\t"";" >>\$(MMS\$TARGET)\n\t\$(PERL) -e "print ""], @lines),')';
+        push @m, '\n$(INST_ARCHAUTODIR)' . $olb_base . '$(LIB_EXT)/Library\n"";" >>$(MMS$TARGET)',"\n";
     }
-    push @m, '\n$(INST_STATIC)/Library\n"";" >>$(MMS$TARGET)',"\n";
-
     if (length $self->{LDLOADLIBS}) {
         my($line) = '';
         foreach my $lib (split ' ', $self->{LDLOADLIBS}) {
@@ -1007,9 +1143,19 @@ $(BASEEXT).opt : Makefile.PL
         }
         push @m, "\t\$(PERL) -e \"print qq{$line}\" >>\$(MMS\$TARGET)\n" if $line;
     }
+    join '', @m;
+}
 
-    join('',@m);
 
+=item xs_obj_opt
+
+Override to fixup -o flags.
+
+=cut
+
+sub xs_obj_opt {
+    my ($self, $output_file) = @_;
+    "/OBJECT=$output_file";
 }
 
 =item dynamic_lib (override)
@@ -1018,54 +1164,58 @@ Use VMS Link command.
 
 =cut
 
-sub dynamic_lib {
-    my($self, %attribs) = @_;
-    return '' unless $self->needs_linking(); #might be because of a subdir
-
-    return '' unless $self->has_link_code();
+sub xs_dynamic_lib_macros {
+    my ($self, $attribs) = @_;
+    my $otherldflags = $attribs->{OTHERLDFLAGS} || "";
+    my $inst_dynamic_dep = $attribs->{INST_DYNAMIC_DEP} || "";
+    sprintf <<'EOF', $otherldflags, $inst_dynamic_dep;
+# This section creates the dynamically loadable objects from relevant
+# objects and possibly $(MYEXTLIB).
+OTHERLDFLAGS = %s
+INST_DYNAMIC_DEP = %s
+EOF
+}
 
-    my($otherldflags) = $attribs{OTHERLDFLAGS} || "";
-    my($inst_dynamic_dep) = $attribs{INST_DYNAMIC_DEP} || "";
+sub xs_make_dynamic_lib {
+    my ($self, $attribs, $from, $to, $todir, $ldfrom, $exportlist) = @_;
     my $shr = $Config{'dbgprefix'} . 'PerlShr';
-    my(@m);
-    push @m,"
-
-OTHERLDFLAGS = $otherldflags
-INST_DYNAMIC_DEP = $inst_dynamic_dep
-
-";
-    push @m, '
-$(INST_DYNAMIC) : $(INST_STATIC) $(PERL_INC)perlshr_attr.opt $(INST_ARCHAUTODIR)$(DFSEP).exists $(EXPORT_LIST) $(PERL_ARCHIVE) $(INST_DYNAMIC_DEP)
-       If F$TrnLNm("',$shr,'").eqs."" Then Define/NoLog/User ',"$shr Sys\$Share:$shr.$Config{'dlext'}",'
-       Link $(LDFLAGS) /Shareable=$(MMS$TARGET)$(OTHERLDFLAGS) $(BASEEXT).opt/Option,$(PERL_INC)perlshr_attr.opt/Option
-';
-
-    join('',@m);
+    $exportlist =~ s/.def$/.opt/;  # it's a linker options file
+    #                    1    2       3            4     5
+    _sprintf562 <<'EOF', $to, $todir, $exportlist, $shr, "$shr Sys\$Share:$shr.$Config{'dlext'}";
+%1$s : $(INST_STATIC) $(PERL_INC)perlshr_attr.opt %2$s$(DFSEP).exists %3$s $(PERL_ARCHIVE) $(INST_DYNAMIC_DEP)
+       If F$TrnLNm("%4$s").eqs."" Then Define/NoLog/User %5$s
+       Link $(LDFLAGS) /Shareable=$(MMS$TARGET)$(OTHERLDFLAGS) %3$s/Option,$(PERL_INC)perlshr_attr.opt/Option
+EOF
 }
 
-
-=item static_lib (override)
+=item xs_make_static_lib (override)
 
 Use VMS commands to manipulate object library.
 
 =cut
 
-sub static_lib {
-    my($self) = @_;
-    return '' unless $self->needs_linking();
-
-    return '
-$(INST_STATIC) :
-       $(NOECHO) $(NOOP)
-' unless ($self->{OBJECT} or @{$self->{C} || []} or $self->{MYEXTLIB});
+sub xs_make_static_lib {
+    my ($self, $object, $to, $todir) = @_;
+
+    my @objects;
+    if ($self->{XSMULTI}) {
+        # The extension name should be the main object file name minus file type.
+        my $lib = $object;
+        $lib =~ s/\$\(OBJ_EXT\)\z//;
+        my $override = $self->_xsbuild_value('xs', $lib, 'OBJECT');
+        $object = $override if defined $override;
+        @objects = map { $self->fixpath($_,0) } split /(?<!\^)\s+/, $object;
+    }
+    else {
+        push @objects, $object;
+    }
 
-    my(@m);
-    push @m,'
-# Rely on suffix rule for update action
-$(OBJECT) : $(INST_ARCHAUTODIR)$(DFSEP).exists
+    my @m;
+    for my $obj (@objects) {
+        push(@m, sprintf "\n%s : %s\$(DFSEP).exists", $obj, $todir);
+    }
+    push(@m, sprintf "\n\n%s : %s \$(MYEXTLIB)\n", $to, (join ' ', @objects));
 
-$(INST_STATIC) : $(OBJECT) $(MYEXTLIB)
-';
     # If this extension has its own library (eg SDBM_File)
     # then copy that to $(INST_STATIC) and add $(OBJECT) into it.
     push(@m, "\t",'$(CP) $(MYEXTLIB) $(MMS$TARGET)',"\n") if $self->{MYEXTLIB};
@@ -1076,8 +1226,11 @@ $(INST_STATIC) : $(OBJECT) $(MYEXTLIB)
     # 'cause it's a library and you can't stick them in other libraries.
     # In that case, we use $OBJECT instead and hope for the best
     if ($self->{MYEXTLIB}) {
-      push(@m,"\t",'Library/Object/Replace $(MMS$TARGET) $(OBJECT)',"\n");
-    } else {
+        for my $obj (@objects) {
+            push(@m,"\t",'Library/Object/Replace $(MMS$TARGET) ' . $obj,"\n");
+        }
+    }
+    else {
       push(@m,"\t",'Library/Object/Replace $(MMS$TARGET) $(MMS$SOURCE_LIST)',"\n");
     }
 
@@ -1359,7 +1512,7 @@ $(PERL_ARCHLIB)Config.pm : $(PERL_SRC)config.sh
 ]);
     }
 
-    push(@m, join(" ", map($self->fixpath($_,0),values %{$self->{XS}}))." : \$(XSUBPPDEPS)\n")
+    push(@m, join(" ", map($self->fixpath($_,0),sort values %{$self->{XS}}))." : \$(XSUBPPDEPS)\n")
       if %{$self->{XS}};
 
     join('',@m);
@@ -1469,7 +1622,7 @@ $(MAP_TARGET) :: $(MAKE_APERL_FILE)
     # (e.g. Intuit::DWIM will precede Intuit, so unresolved
     # references from [.intuit.dwim]dwim.obj can be found
     # in [.intuit]intuit.olb).
-    for (sort { length($a) <=> length($b) } keys %olbs) {
+    for (sort { length($a) <=> length($b) || $a cmp $b } keys %olbs) {
        next unless $olbs{$_} =~ /\Q$self->{LIB_EXT}\E$/;
        my($dir) = $self->fixpath($_,1);
        my($extralibs) = $dir . "extralibs.ld";
@@ -1615,7 +1768,7 @@ map_clean :
 
 =item maketext_filter (override)
 
-Insure that colons marking targets are preceded by space, in order
+Ensure that colons marking targets are preceded by space, in order
 to distinguish the target delimiter from a colon appearing as
 part of a filespec.
 
@@ -1778,7 +1931,7 @@ sub oneliner {
 =item B<echo>
 
 perl trips up on "<foo>" thinking it's an input redirect.  So we use the
-native Write command instead.  Besides, its faster.
+native Write command instead.  Besides, it's faster.
 
 =cut
 
@@ -1975,7 +2128,12 @@ sub eliminate_macros {
                     $complex = 1;
                 }
             }
-            else { ($macro = unixify($self->{$macro})) =~ s#/\Z(?!\n)##; }
+            else {
+                $macro = $self->{$macro};
+                # Don't unixify if there is unescaped whitespace
+                $macro = unixify($macro) unless ($macro =~ /(?<!\^)\s/);
+                $macro =~ s#/\Z(?!\n)##;
+            }
             $npath = "$head$macro$tail";
         }
     }
@@ -2072,6 +2230,15 @@ sub is_make_type {
 }
 
 
+=item make_type (override)
+
+Returns a suitable string describing the type of makefile being written.
+
+=cut
+
+sub make_type { "$Config{make}-style"; }
+
+
 =back
 
 
index 57d5e32..dde1902 100644 (file)
@@ -1,7 +1,8 @@
 package ExtUtils::MM_VOS;
 
 use strict;
-our $VERSION = '7.10_01';
+our $VERSION = '7.18';
+$VERSION = eval $VERSION;
 
 require ExtUtils::MM_Unix;
 our @ISA = qw(ExtUtils::MM_Unix);
index 1c6921c..d8efc66 100644 (file)
@@ -22,25 +22,26 @@ the semantics.
 use ExtUtils::MakeMaker::Config;
 use File::Basename;
 use File::Spec;
-use ExtUtils::MakeMaker qw( neatvalue );
+use ExtUtils::MakeMaker qw(neatvalue _sprintf562);
 
 require ExtUtils::MM_Any;
 require ExtUtils::MM_Unix;
 our @ISA = qw( ExtUtils::MM_Any ExtUtils::MM_Unix );
-our $VERSION = '7.10_01';
+our $VERSION = '7.18';
+$VERSION = eval $VERSION;
 
 $ENV{EMXSHELL} = 'sh'; # to run `commands`
 
-my ( $BORLAND, $GCC, $DLLTOOL ) = _identify_compiler_environment( \%Config );
+my ( $BORLAND, $GCC, $MSVC ) = _identify_compiler_environment( \%Config );
 
 sub _identify_compiler_environment {
        my ( $config ) = @_;
 
-       my $BORLAND = $config->{cc} =~ /^bcc/i ? 1 : 0;
+       my $BORLAND = $config->{cc} =~ /\bbcc/i ? 1 : 0;
        my $GCC     = $config->{cc} =~ /\bgcc\b/i ? 1 : 0;
-       my $DLLTOOL = $config->{dlltool} || 'dlltool';
+       my $MSVC    = $config->{cc} =~ /\b(?:cl|icl)/i ? 1 : 0; # MSVC can come as clarm.exe, icl=Intel C
 
-       return ( $BORLAND, $GCC, $DLLTOOL );
+       return ( $BORLAND, $GCC, $MSVC );
 }
 
 
@@ -54,31 +55,18 @@ sub _identify_compiler_environment {
 
 sub dlsyms {
     my($self,%attribs) = @_;
+    return '' if $self->{SKIPHASH}{'dynamic'};
+    $self->xs_dlsyms_iterator(\%attribs);
+}
 
-    my($funcs) = $attribs{DL_FUNCS} || $self->{DL_FUNCS} || {};
-    my($vars)  = $attribs{DL_VARS} || $self->{DL_VARS} || [];
-    my($funclist) = $attribs{FUNCLIST} || $self->{FUNCLIST} || [];
-    my($imports)  = $attribs{IMPORTS} || $self->{IMPORTS} || {};
-    my(@m);
-
-    if (not $self->{SKIPHASH}{'dynamic'}) {
-       push(@m,"
-$self->{BASEEXT}.def: Makefile.PL
-",
-     q!        $(PERLRUN) -MExtUtils::Mksymlists \\
-     -e "Mksymlists('NAME'=>\"!, $self->{NAME},
-     q!\", 'DLBASE' => '!,$self->{DLBASE},
-     # The above two lines quoted differently to work around
-     # a bug in the 4DOS/4NT command line interpreter.  The visible
-     # result of the bug was files named q('extension_name',) *with the
-     # single quotes and the comma* in the extension build directories.
-     q!', 'DL_FUNCS' => !,neatvalue($funcs),
-     q!, 'FUNCLIST' => !,neatvalue($funclist),
-     q!, 'IMPORTS' => !,neatvalue($imports),
-     q!, 'DL_VARS' => !, neatvalue($vars), q!);"
-!);
-    }
-    join('',@m);
+=item xs_dlsyms_ext
+
+On Win32, is C<.def>.
+
+=cut
+
+sub xs_dlsyms_ext {
+    '.def';
 }
 
 =item replace_manpage_separator
@@ -292,104 +280,76 @@ MAKE_FRAG
     return $make_frag;
 }
 
+=item static_lib_pure_cmd
 
-=item static_lib
-
-Changes how to run the linker.
-
-The rest is duplicate code from MM_Unix.  Should move the linker code
-to its own method.
+Defines how to run the archive utility
 
 =cut
 
-sub static_lib {
-    my($self) = @_;
-    return '' unless $self->has_link_code;
-
-    my(@m);
-    push(@m, <<'END');
-$(INST_STATIC): $(OBJECT) $(MYEXTLIB) $(INST_ARCHAUTODIR)$(DFSEP).exists
-       $(RM_RF) $@
-END
-
-    # If this extension has its own library (eg SDBM_File)
-    # then copy that to $(INST_STATIC) and add $(OBJECT) into it.
-    push @m, <<'MAKE_FRAG' if $self->{MYEXTLIB};
-       $(CP) $(MYEXTLIB) $@
-MAKE_FRAG
-
-    push @m,
-q{     $(AR) }.($BORLAND ? '$@ $(OBJECT:^"+")'
-                         : ($GCC ? '-ru $@ $(OBJECT)'
-                                 : '-out:$@ $(OBJECT)')).q{
-       $(CHMOD) $(PERM_RWX) $@
-       $(NOECHO) $(ECHO) "$(EXTRALIBS)" > $(INST_ARCHAUTODIR)\extralibs.ld
-};
-
-    # Old mechanism - still available:
-    push @m, <<'MAKE_FRAG' if $self->{PERL_SRC} && $self->{EXTRALIBS};
-       $(NOECHO) $(ECHO) "$(EXTRALIBS)" >> $(PERL_SRC)\ext.libs
-MAKE_FRAG
-
-    join('', @m);
+sub static_lib_pure_cmd {
+    my ($self, $from) = @_;
+    $from =~ s/(\$\(\w+)(\))/$1:^"+"$2/g if $BORLAND;
+    sprintf qq{\t\$(AR) %s\n}, ($BORLAND ? '$@ ' . $from
+                          : ($GCC ? '-ru $@ ' . $from
+                                  : '-out:$@ ' . $from));
 }
 
-
 =item dynamic_lib
 
-Complicated stuff for Win32 that I don't understand. :(
+Methods are overridden here: not dynamic_lib itself, but the utility
+ones that do the OS-specific work.
 
 =cut
 
-sub dynamic_lib {
-    my($self, %attribs) = @_;
-    return '' unless $self->needs_linking(); #might be because of a subdir
-
-    return '' unless $self->has_link_code;
-
-    my($otherldflags) = $attribs{OTHERLDFLAGS} || ($BORLAND ? 'c0d32.obj': '');
-    my($inst_dynamic_dep) = $attribs{INST_DYNAMIC_DEP} || "";
-    my($ldfrom) = '$(LDFROM)';
-    my(@m);
-
-    push(@m,'
-# This section creates the dynamically loadable $(INST_DYNAMIC)
-# from $(OBJECT) and possibly $(MYEXTLIB).
-OTHERLDFLAGS = '.$otherldflags.'
-INST_DYNAMIC_DEP = '.$inst_dynamic_dep.'
-
-$(INST_DYNAMIC): $(OBJECT) $(MYEXTLIB) $(BOOTSTRAP) $(INST_ARCHAUTODIR)$(DFSEP).exists $(EXPORT_LIST) $(PERL_ARCHIVEDEP) $(INST_DYNAMIC_DEP)
-');
+sub xs_make_dynamic_lib {
+    my ($self, $attribs, $from, $to, $todir, $ldfrom, $exportlist) = @_;
+    my @m = sprintf '%s : %s $(MYEXTLIB) %s$(DFSEP).exists %s $(PERL_ARCHIVEDEP) $(INST_DYNAMIC_DEP)'."\n", $to, $from, $todir, $exportlist;
     if ($GCC) {
-      push(@m,
-       q{      }.$DLLTOOL.q{ --def $(EXPORT_LIST) --output-exp dll.exp
-       $(LD) -o $@ -Wl,--base-file -Wl,dll.base $(LDDLFLAGS) }.$ldfrom.q{ $(OTHERLDFLAGS) $(MYEXTLIB) "$(PERL_ARCHIVE)" $(LDLOADLIBS) dll.exp
-       }.$DLLTOOL.q{ --def $(EXPORT_LIST) --base-file dll.base --output-exp dll.exp
-       $(LD) -o $@ $(LDDLFLAGS) }.$ldfrom.q{ $(OTHERLDFLAGS) $(MYEXTLIB) "$(PERL_ARCHIVE)" $(LDLOADLIBS) dll.exp });
+      # per https://rt.cpan.org/Ticket/Display.html?id=78395 no longer
+      # uses dlltool - relies on post 2002 MinGW
+      #                             1            2
+      push @m, _sprintf562 <<'EOF', $exportlist, $ldfrom;
+       $(LD) %1$s -o $@ $(LDDLFLAGS) %2$s $(OTHERLDFLAGS) $(MYEXTLIB) "$(PERL_ARCHIVE)" $(LDLOADLIBS) -Wl,--enable-auto-image-base
+EOF
     } elsif ($BORLAND) {
-      push(@m,
-       q{      $(LD) $(LDDLFLAGS) $(OTHERLDFLAGS) }.$ldfrom.q{,$@,,}
-       .($self->is_make_type('dmake')
-                ? q{"$(PERL_ARCHIVE:s,/,\,)" $(LDLOADLIBS:s,/,\,) }
-                .q{$(MYEXTLIB:s,/,\,),$(EXPORT_LIST:s,/,\,)}
-               : q{"$(subst /,\,$(PERL_ARCHIVE))" $(subst /,\,$(LDLOADLIBS)) }
-                .q{$(subst /,\,$(MYEXTLIB)),$(subst /,\,$(EXPORT_LIST))})
-       .q{,$(RESFILES)});
+      my $ldargs = $self->is_make_type('dmake')
+          ? q{"$(PERL_ARCHIVE:s,/,\,)" $(LDLOADLIBS:s,/,\,) $(MYEXTLIB:s,/,\,),}
+          : q{"$(subst /,\,$(PERL_ARCHIVE))" $(subst /,\,$(LDLOADLIBS)) $(subst /,\,$(MYEXTLIB)),};
+      my $subbed;
+      if ($exportlist eq '$(EXPORT_LIST)') {
+          $subbed = $self->is_make_type('dmake')
+              ? q{$(EXPORT_LIST:s,/,\,)}
+              : q{$(subst /,\,$(EXPORT_LIST))};
+      } else {
+            # in XSMULTI, exportlist is per-XS, so have to sub in perl not make
+          ($subbed = $exportlist) =~ s#/#\\#g;
+      }
+      push @m, sprintf <<'EOF', $ldfrom, $ldargs . $subbed;
+        $(LD) $(LDDLFLAGS) $(OTHERLDFLAGS) %s,$@,,%s,$(RESFILES)
+EOF
     } else {   # VC
-      push(@m,
-       q{      $(LD) -out:$@ $(LDDLFLAGS) }.$ldfrom.q{ $(OTHERLDFLAGS) }
-      .q{$(MYEXTLIB) "$(PERL_ARCHIVE)" $(LDLOADLIBS) -def:$(EXPORT_LIST)});
-
+      push @m, sprintf <<'EOF', $ldfrom, $exportlist;
+       $(LD) -out:$@ $(LDDLFLAGS) %s $(OTHERLDFLAGS) $(MYEXTLIB) "$(PERL_ARCHIVE)" $(LDLOADLIBS) -def:%s
+EOF
       # Embed the manifest file if it exists
-      push(@m, q{
-       if exist $@.manifest mt -nologo -manifest $@.manifest -outputresource:$@;2
+      push(@m, q{      if exist $@.manifest mt -nologo -manifest $@.manifest -outputresource:$@;2
        if exist $@.manifest del $@.manifest});
     }
-    push @m, '
-       $(CHMOD) $(PERM_RWX) $@
-';
+    push @m, "\n\t\$(CHMOD) \$(PERM_RWX) \$\@\n";
+
+    join '', @m;
+}
 
-    join('',@m);
+sub xs_dynamic_lib_macros {
+    my ($self, $attribs) = @_;
+    my $otherldflags = $attribs->{OTHERLDFLAGS} || ($BORLAND ? 'c0d32.obj': '');
+    my $inst_dynamic_dep = $attribs->{INST_DYNAMIC_DEP} || "";
+    sprintf <<'EOF', $otherldflags, $inst_dynamic_dep;
+# This section creates the dynamically loadable objects from relevant
+# objects and possibly $(MYEXTLIB).
+OTHERLDFLAGS = %s
+INST_DYNAMIC_DEP = %s
+EOF
 }
 
 =item extra_clean_files
@@ -458,14 +418,16 @@ EOF
     return $self->SUPER::quote_dep($arg);
 }
 
-=item xs_o
 
-This target is stubbed out.  Not sure why.
+=item xs_obj_opt
+
+Override to fixup -o flags for MSVC.
 
 =cut
 
-sub xs_o {
-    return ''
+sub xs_obj_opt {
+    my ($self, $output_file) = @_;
+    ($MSVC ? "/Fo" : "-o ") . $output_file;
 }
 
 
@@ -478,7 +440,10 @@ banner.
 
 sub pasthru {
     my($self) = shift;
-    return "PASTHRU = " . ($self->is_make_type('nmake') ? "-nologo" : "");
+    my $old = $self->SUPER::pasthru;
+    return $old unless $self->is_make_type('nmake');
+    $old =~ s/(PASTHRU\s*=\s*)/$1 -nologo /;
+    $old;
 }
 
 
@@ -658,6 +623,23 @@ PERLTYPE = $self->{PERLTYPE}
 
 }
 
+=item make_type
+
+Returns a suitable string describing the type of makefile being written.
+
+=cut
+
+sub make_type {
+    my ($self) = @_;
+    my $make = $self->make;
+    $make = +( File::Spec->splitpath( $make ) )[-1];
+    $make =~ s!\.exe$!!i;
+    if ( $make =~ m![^A-Z0-9]!i ) {
+      ($make) = grep { m!make!i } split m![^A-Z0-9]!i, $make;
+    }
+    return "$make-style";
+}
+
 1;
 __END__
 
index 2c31d7c..f9a4f9d 100644 (file)
@@ -2,7 +2,8 @@ package ExtUtils::MM_Win95;
 
 use strict;
 
-our $VERSION = '7.10_01';
+our $VERSION = '7.18';
+$VERSION = eval $VERSION;
 
 require ExtUtils::MM_Win32;
 our @ISA = qw(ExtUtils::MM_Win32);
@@ -26,59 +27,10 @@ to get MakeMaker playing nice with command.com and other Win9Xisms.
 =head2 Overridden methods
 
 Most of these make up for limitations in the Win9x/nmake command shell.
-Mostly its lack of &&.
 
 =over 4
 
 
-=item xs_c
-
-The && problem.
-
-=cut
-
-sub xs_c {
-    my($self) = shift;
-    return '' unless $self->needs_linking();
-    '
-.xs.c:
-       $(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $*.xs > $*.c
-       '
-}
-
-
-=item xs_cpp
-
-The && problem
-
-=cut
-
-sub xs_cpp {
-    my($self) = shift;
-    return '' unless $self->needs_linking();
-    '
-.xs.cpp:
-       $(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $*.xs > $*.cpp
-       ';
-}
-
-=item xs_o
-
-The && problem.
-
-=cut
-
-sub xs_o {
-    my($self) = shift;
-    return '' unless $self->needs_linking();
-    '
-.xs$(OBJ_EXT):
-       $(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $*.xs > $*.c
-       $(CCCMD) $(CCCDLFLAGS) -I$(PERL_INC) $(DEFINE) $*.c
-       ';
-}
-
-
 =item max_exec_len
 
 Win98 chokes on things like Encode if we set the max length to nmake's max
index 3973e37..be4c708 100644 (file)
@@ -3,7 +3,8 @@ package ExtUtils::MY;
 use strict;
 require ExtUtils::MM;
 
-our $VERSION = '7.10_01';
+our $VERSION = '7.18';
+$VERSION = eval $VERSION;
 our @ISA = qw(ExtUtils::MM);
 
 {
index f9fb8fe..e840410 100644 (file)
@@ -24,7 +24,7 @@ my %Recognized_Att_Keys;
 our %macro_fsentity; # whether a macro is a filesystem name
 our %macro_dep; # whether a macro is a dependency
 
-our $VERSION = '7.10_01';
+our $VERSION = '7.18';
 $VERSION = eval $VERSION;  ## no critic [BuiltinFunctions::ProhibitStringyEval]
 
 # Emulate something resembling CVS $Revision$
@@ -36,7 +36,8 @@ our $Filename = __FILE__;   # referenced outside MakeMaker
 our @ISA = qw(Exporter);
 our @EXPORT    = qw(&WriteMakefile $Verbose &prompt);
 our @EXPORT_OK = qw($VERSION &neatvalue &mkbootstrap &mksymlists
-                    &WriteEmptyMakefile);
+                    &WriteEmptyMakefile &open_for_writing &write_file_via_tmp
+                    &_sprintf562);
 
 # These will go away once the last of the Win32 & VMS specific code is
 # purged.
@@ -54,6 +55,15 @@ require ExtUtils::MY;  # XXX pre-5.8 versions of ExtUtils::Embed expect
                        # This will go when Embed is its own CPAN module.
 
 
+# 5.6.2 can't do sprintf "%1$s" - this can only do %s
+sub _sprintf562 {
+    my ($format, @args) = @_;
+    for (my $i = 1; $i <= @args; $i++) {
+        $format =~ s#%$i\$s#$args[$i-1]#g;
+    }
+    $format;
+}
+
 sub WriteMakefile {
     croak "WriteMakefile: Need even number of args" if @_ % 2;
 
@@ -106,6 +116,7 @@ my %Special_Sigs = (
  SKIP               => 'ARRAY',
  TYPEMAPS           => 'ARRAY',
  XS                 => 'HASH',
+ XSBUILD            => 'HASH',
  VERSION            => ['version',''],
  _KEEP_AFTER_FLUSH  => '',
 
@@ -141,7 +152,8 @@ sub _convert_compat_attrs { #result of running several times should be same
 sub _verify_att {
     my($att) = @_;
 
-    while( my($key, $val) = each %$att ) {
+    foreach my $key (sort keys %$att) {
+        my $val = $att->{$key};
         my $sig = $Att_Sigs{$key};
         unless( defined $sig ) {
             warn "WARNING: $key is not a known parameter.\n";
@@ -301,9 +313,9 @@ sub full_setup {
     PERM_DIR PERM_RW PERM_RWX MAGICXS
     PL_FILES PM PM_FILTER PMLIBDIRS PMLIBPARENTDIRS POLLUTE
     PREREQ_FATAL PREREQ_PM PREREQ_PRINT PRINT_PREREQ
-    SIGN SKIP TEST_REQUIRES TYPEMAPS UNINST VERSION VERSION_FROM XS XSOPT XSPROTOARG
-    XS_VERSION clean depend dist dynamic_lib linkext macro realclean
-    tool_autosplit
+    SIGN SKIP TEST_REQUIRES TYPEMAPS UNINST VERSION VERSION_FROM XS
+    XSBUILD XSMULTI XSOPT XSPROTOARG XS_VERSION
+    clean depend dist dynamic_lib linkext macro realclean tool_autosplit
 
     MAN1EXT MAN3EXT
 
@@ -405,6 +417,14 @@ sub full_setup {
     );
 }
 
+sub _has_cpan_meta_requirements {
+    return eval {
+      require CPAN::Meta::Requirements;
+      CPAN::Meta::Requirements->VERSION(2.130);
+      require B; # CMR requires this, for core we have to too.
+    };
+}
+
 sub new {
     my($class,$self) = @_;
     my($key);
@@ -423,12 +443,53 @@ sub new {
     bless $self, "MM";
 
     # Cleanup all the module requirement bits
+    my %key2cmr;
     for my $key (qw(PREREQ_PM BUILD_REQUIRES CONFIGURE_REQUIRES TEST_REQUIRES)) {
         $self->{$key}      ||= {};
-        $self->clean_versions( $key );
+        if (_has_cpan_meta_requirements) {
+            my $cmr = CPAN::Meta::Requirements->from_string_hash(
+                $self->{$key},
+                {
+                  bad_version_hook => sub {
+                    #no warnings 'numeric'; # module doesn't use warnings
+                    my $fallback;
+                    if ( $_[0] =~ m!^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$! ) {
+                      $fallback = sprintf "%f", $_[0];
+                    } else {
+                      ($fallback) = $_[0] ? ($_[0] =~ /^([0-9.]+)/) : 0;
+                      $fallback += 0;
+                      carp "Unparsable version '$_[0]' for prerequisite $_[1] treated as $fallback";
+                    }
+                    version->new($fallback);
+                  },
+                },
+            );
+            $self->{$key} = $cmr->as_string_hash;
+            $key2cmr{$key} = $cmr;
+        } else {
+            for my $module (sort keys %{ $self->{$key} }) {
+                my $version = $self->{$key}->{$module};
+                my $fallback = 0;
+                if (!defined($version) or !length($version)) {
+                    carp "Undefined requirement for $module treated as '0' (CPAN::Meta::Requirements not available)";
+                }
+                elsif ($version =~ /^\d+(?:\.\d+(?:_\d+)*)?$/) {
+                    next;
+                }
+                else {
+                    if ( $version =~ m!^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$! ) {
+                      $fallback = sprintf "%f", $version;
+                    } else {
+                      ($fallback) = $version ? ($version =~ /^([0-9.]+)/) : 0;
+                      $fallback += 0;
+                      carp "Unparsable version '$version' for prerequisite $module treated as $fallback (CPAN::Meta::Requirements not available)";
+                    }
+                }
+                $self->{$key}->{$module} = $fallback;
+            }
+        }
     }
 
-
     if ("@ARGV" =~ /\bPREREQ_PRINT\b/) {
         $self->_PREREQ_PRINT;
     }
@@ -495,9 +556,24 @@ END
     my(%initial_att) = %$self; # record initial attributes
 
     my(%unsatisfied) = ();
-    my $prereqs = $self->_all_prereqs;
-    foreach my $prereq (sort keys %$prereqs) {
-        my $required_version = $prereqs->{$prereq};
+    my %prereq2version;
+    my $cmr;
+    if (_has_cpan_meta_requirements) {
+        $cmr = CPAN::Meta::Requirements->new;
+        for my $key (qw(PREREQ_PM BUILD_REQUIRES CONFIGURE_REQUIRES TEST_REQUIRES)) {
+            $cmr->add_requirements($key2cmr{$key}) if $key2cmr{$key};
+        }
+        foreach my $prereq ($cmr->required_modules) {
+            $prereq2version{$prereq} = $cmr->requirements_for_module($prereq);
+        }
+    } else {
+        for my $key (qw(PREREQ_PM BUILD_REQUIRES CONFIGURE_REQUIRES TEST_REQUIRES)) {
+            next unless my $module2version = $self->{$key};
+            $prereq2version{$_} = $module2version->{$_} for keys %$module2version;
+        }
+    }
+    foreach my $prereq (sort keys %prereq2version) {
+        my $required_version = $prereq2version{$prereq};
 
         my $pr_version = 0;
         my $installed_file;
@@ -516,6 +592,18 @@ END
           $installed_file = MM->_installed_file_for_module($prereq);
           $pr_version = MM->parse_version($installed_file) if $installed_file;
           $pr_version = 0 if $pr_version eq 'undef';
+          if ( !eval { version->new( $pr_version ); 1 } ) {
+            #no warnings 'numeric'; # module doesn't use warnings
+            my $fallback;
+            if ( $pr_version =~ m!^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$! ) {
+              $fallback = sprintf '%f', $pr_version;
+            } else {
+              ($fallback) = $pr_version ? ($pr_version =~ /^([0-9.]+)/) : 0;
+              $fallback += 0;
+              carp "Unparsable version '$pr_version' for installed prerequisite $prereq treated as $fallback";
+            }
+            $pr_version = $fallback;
+          }
         }
 
         # convert X.Y_Z alpha version #s to X.YZ for easier comparisons
@@ -529,13 +617,17 @@ END
 
             $unsatisfied{$prereq} = 'not installed';
         }
-        elsif ($pr_version < $required_version ){
+        elsif (
+            $cmr
+                ? !$cmr->accepts_module($prereq, $pr_version)
+                : $required_version > $pr_version
+        ) {
             warn sprintf "Warning: prerequisite %s %s not found. We have %s.\n",
               $prereq, $required_version, ($pr_version || 'unknown version')
                   unless $self->{PREREQ_FATAL}
                        or $UNDER_CORE;
 
-            $unsatisfied{$prereq} = $required_version ? $required_version : 'unknown version' ;
+            $unsatisfied{$prereq} = $required_version || 'unknown version' ;
         }
     }
 
@@ -671,7 +763,9 @@ END
     $self->init_others();
     $self->init_platform();
     $self->init_PERM();
-    my($argv) = neatvalue(\@ARGV);
+    my @args = @ARGV;
+    @args = map { Encode::decode(locale => $_) } @args if $CAN_DECODE;
+    my($argv) = neatvalue(\@args);
     $argv =~ s/^\[/(/;
     $argv =~ s/\]$/)/;
 
@@ -757,6 +851,7 @@ sub WriteEmptyMakefile {
     croak "WriteEmptyMakefile: Need an even number of args" if @_ % 2;
 
     my %att = @_;
+    $att{DIR} = [] unless $att{DIR}; # don't recurse by default
     my $self = MM->new(\%att);
 
     my $new = $self->{MAKEFILE};
@@ -771,6 +866,14 @@ sub WriteEmptyMakefile {
     print $mfh <<'EOP';
 all :
 
+manifypods :
+
+subdirs :
+
+dynamic :
+
+static :
+
 clean :
 
 install :
@@ -779,6 +882,10 @@ makemakerdflt :
 
 test :
 
+test_dynamic :
+
+test_static :
+
 EOP
     close $mfh or die "close $new for write: $!";
 }
@@ -1051,7 +1158,7 @@ sub _run_hintfile {
     my($hint_file) = shift;
 
     local($@, $!);
-    warn "Processing hints file $hint_file\n";
+    print "Processing hints file $hint_file\n" if $Verbose;
 
     # Just in case the ./ isn't on the hint file, which File::Spec can
     # often strip off, we bung the curdir into @INC
@@ -1065,69 +1172,34 @@ sub _run_hintfile {
 
 sub mv_all_methods {
     my($from,$to) = @_;
-
-    # Here you see the *current* list of methods that are overridable
-    # from Makefile.PL via MY:: subroutines. As of VERSION 5.07 I'm
-    # still trying to reduce the list to some reasonable minimum --
-    # because I want to make it easier for the user. A.K.
-
     local $SIG{__WARN__} = sub {
         # can't use 'no warnings redefined', 5.6 only
         warn @_ unless $_[0] =~ /^Subroutine .* redefined/
     };
     foreach my $method (@Overridable) {
-
-        # We cannot say "next" here. Nick might call MY->makeaperl
-        # which isn't defined right now
-
-        # Above statement was written at 4.23 time when Tk-b8 was
-        # around. As Tk-b9 only builds with 5.002something and MM 5 is
-        # standard, we try to enable the next line again. It was
-        # commented out until MM 5.23
-
         next unless defined &{"${from}::$method"};
+        no strict 'refs';   ## no critic
+        *{"${to}::$method"} = \&{"${from}::$method"};
+
+        # If we delete a method, then it will be undefined and cannot
+        # be called.  But as long as we have Makefile.PLs that rely on
+        # %MY:: being intact, we have to fill the hole with an
+        # inheriting method:
 
         {
-            no strict 'refs';   ## no critic
-            *{"${to}::$method"} = \&{"${from}::$method"};
-
-            # If we delete a method, then it will be undefined and cannot
-            # be called.  But as long as we have Makefile.PLs that rely on
-            # %MY:: being intact, we have to fill the hole with an
-            # inheriting method:
-
-            {
-                package MY;
-                my $super = "SUPER::".$method;
-                *{$method} = sub {
-                    shift->$super(@_);
-                };
-            }
+            package MY;
+            my $super = "SUPER::".$method;
+            *{$method} = sub {
+                shift->$super(@_);
+            };
         }
     }
-
-    # We have to clean out %INC also, because the current directory is
-    # changed frequently and Graham Barr prefers to get his version
-    # out of a History.pl file which is "required" so wouldn't get
-    # loaded again in another extension requiring a History.pl
-
-    # With perl5.002_01 the deletion of entries in %INC caused Tk-b11
-    # to core dump in the middle of a require statement. The required
-    # file was Tk/MMutil.pm.  The consequence is, we have to be
-    # extremely careful when we try to give perl a reason to reload a
-    # library with same name.  The workaround prefers to drop nothing
-    # from %INC and teach the writers not to use such libraries.
-
-#    my $inc;
-#    foreach $inc (keys %INC) {
-#       #warn "***$inc*** deleted";
-#       delete $INC{$inc};
-#    }
 }
 
 sub skipcheck {
     my($self) = shift;
     my($section) = @_;
+    return 'skipped' if $section eq 'metafile' && $UNDER_CORE;
     if ($section eq 'dynamic') {
         print "Warning (non-fatal): Target 'dynamic' depends on targets ",
         "in skipped section 'dynamic_bs'\n"
@@ -1150,64 +1222,63 @@ sub skipcheck {
     return '';
 }
 
+# returns filehandle, dies on fail. :raw so no :crlf
+sub open_for_writing {
+    my ($file) = @_;
+    open my $fh ,">", $file or die "Unable to open $file: $!";
+    my @layers = ':raw';
+    push @layers, join ' ', ':encoding(locale)' if $CAN_DECODE;
+    binmode $fh, join ' ', @layers;
+    $fh;
+}
+
 sub flush {
     my $self = shift;
 
-    # This needs a bit more work for more wacky OSen
-    my $type = 'Unix-style';
-    if ( $self->os_flavor_is('Win32') ) {
-      my $make = $self->make;
-      $make = +( File::Spec->splitpath( $make ) )[-1];
-      $make =~ s!\.exe$!!i;
-      $type = $make . '-style';
-    }
-    elsif ( $Is_VMS ) {
-        $type = $Config{make} . '-style';
-    }
-
     my $finalname = $self->{MAKEFILE};
-    print "Generating a $type $finalname\n";
-    print "Writing $finalname for $self->{NAME}\n";
+    printf "Generating a %s %s\n", $self->make_type, $finalname if $Verbose || !$self->{PARENT};
+    print "Writing $finalname for $self->{NAME}\n" if $Verbose || !$self->{PARENT};
 
     unlink($finalname, "MakeMaker.tmp", $Is_VMS ? 'Descrip.MMS' : ());
-    open(my $fh,">", "MakeMaker.tmp")
-        or die "Unable to open MakeMaker.tmp: $!";
-    binmode $fh, ':encoding(locale)' if $CAN_DECODE;
 
-    for my $chunk (@{$self->{RESULT}}) {
+    write_file_via_tmp($finalname, $self->{RESULT});
+
+    # Write MYMETA.yml to communicate metadata up to the CPAN clients
+    print "Writing MYMETA.yml and MYMETA.json\n"
+      if !$self->{NO_MYMETA} and $self->write_mymeta( $self->mymeta );
+
+    # save memory
+    if ($self->{PARENT} && !$self->{_KEEP_AFTER_FLUSH}) {
+        my %keep = map { ($_ => 1) } qw(NEEDS_LINKING HAS_LINK_CODE);
+        delete $self->{$_} for grep !$keep{$_}, keys %$self;
+    }
+
+    system("$Config::Config{eunicefix} $finalname")
+      if $Config::Config{eunicefix} ne ":";
+
+    return;
+}
+
+sub write_file_via_tmp {
+    my ($finalname, $contents) = @_;
+    my $fh = open_for_writing("MakeMaker.tmp");
+    die "write_file_via_tmp: 2nd arg must be ref" unless ref $contents;
+    for my $chunk (@$contents) {
         my $to_write = $chunk;
         utf8::encode $to_write if !$CAN_DECODE && $] > 5.008;
         print $fh "$to_write\n" or die "Can't write to MakeMaker.tmp: $!";
     }
-
-    close $fh
-        or die "Can't write to MakeMaker.tmp: $!";
+    close $fh or die "Can't write to MakeMaker.tmp: $!";
     _rename("MakeMaker.tmp", $finalname) or
       warn "rename MakeMaker.tmp => $finalname: $!";
-    chmod 0644, $finalname unless $Is_VMS;
-
-    unless ($self->{NO_MYMETA}) {
-        # Write MYMETA.yml to communicate metadata up to the CPAN clients
-        if ( $self->write_mymeta( $self->mymeta ) ) {
-            print "Writing MYMETA.yml and MYMETA.json\n";
-        }
-
-    }
-    my %keep = map { ($_ => 1) } qw(NEEDS_LINKING HAS_LINK_CODE);
-    if ($self->{PARENT} && !$self->{_KEEP_AFTER_FLUSH}) {
-        foreach (keys %$self) { # safe memory
-            delete $self->{$_} unless $keep{$_};
-        }
-    }
-
-    system("$Config::Config{eunicefix} $finalname") unless $Config::Config{eunicefix} eq ":";
+    chmod 0644, $finalname if !$Is_VMS;
+    return;
 }
 
 # This is a rename for OS's where the target must be unlinked first.
 sub _rename {
     my($src, $dest) = @_;
-    chmod 0666, $dest;
-    unlink $dest;
+    _unlink($dest);
     return rename $src, $dest;
 }
 
@@ -1283,36 +1354,6 @@ sub _find_magic_vstring {
     return $tvalue;
 }
 
-
-# Look for weird version numbers, warn about them and set them to 0
-# before CPAN::Meta chokes.
-sub clean_versions {
-    my($self, $key) = @_;
-    my $reqs = $self->{$key};
-    for my $module (keys %$reqs) {
-        my $v = $reqs->{$module};
-        my $printable = _find_magic_vstring($v);
-        $v = $printable if length $printable;
-        my $version = eval {
-            local $SIG{__WARN__} = sub {
-              # simulate "use warnings FATAL => 'all'" for vintage perls
-              die @_;
-            };
-            version->new($v)->stringify;
-        };
-        if( $@ || $reqs->{$module} eq '' ) {
-            if ( $] < 5.008 && $v !~ /^v?[\d_\.]+$/ ) {
-               $v = sprintf "v%vd", $v unless $v eq '';
-            }
-            carp "Unparsable version '$v' for prerequisite $module";
-            $reqs->{$module} = 0;
-        }
-        else {
-            $reqs->{$module} = $version;
-        }
-    }
-}
-
 sub selfdocument {
     my($self) = @_;
     my(@m);
@@ -1326,6 +1367,16 @@ sub selfdocument {
             push @m, "# $key => $v";
         }
     }
+    # added here as selfdocument is not overridable
+    push @m, <<'EOF';
+
+# here so even if top_targets is overridden, these will still be defined
+# gmake will silently still work if any are .PHONY-ed but nmake won't
+EOF
+    push @m, join "\n", map "$_ ::\n\t\$(NOECHO) \$(NOOP)\n",
+        # config is so manifypods won't puke if no subdirs
+        grep !$self->{SKIPHASH}{$_},
+        qw(static dynamic config);
     join "\n", @m;
 }
 
@@ -2381,7 +2432,14 @@ passed to subdirectory makes.
 
 =item PERL
 
-Perl binary for tasks that can be done by miniperl.
+Perl binary for tasks that can be done by miniperl. If it contains
+spaces or other shell metacharacters, it needs to be quoted in a way
+that protects them, since this value is intended to be inserted in a
+shell command line in the Makefile. E.g.:
+
+  # Perl executable lives in "C:/Program Files/Perl/bin"
+  # Normally you don't need to set this yourself!
+  $ perl Makefile.PL PERL='"C:/Program Files/Perl/bin/perl.exe" -w'
 
 =item PERL_CORE
 
@@ -2480,7 +2538,9 @@ Desired permission for executable files. Defaults to C<755>.
 MakeMaker can run programs to generate files for you at build time.
 By default any file named *.PL (except Makefile.PL and Build.PL) in
 the top level directory will be assumed to be a Perl program and run
-passing its own basename in as an argument.  For example...
+passing its own basename in as an argument.  This basename is actually a build
+target, and there is an intention, but not a requirement, that the *.PL file
+make the file passed to to as an argument. For example...
 
     perl foo.PL foo
 
@@ -2490,6 +2550,8 @@ and the value is passed in as the first argument when the PL file is run.
 
     PL_FILES => {'bin/foobar.PL' => 'bin/foobar'}
 
+    PL_FILES => {'foo.PL' => 'foo.c'}
+
 Would run bin/foobar.PL like this:
 
     perl bin/foobar.PL bin/foobar
@@ -2508,8 +2570,14 @@ INST_ARCH in their C<@INC>, so the just built modules can be
 accessed... unless the PL file is making a module (or anything else in
 PM) in which case it is run B<before> pm_to_blib and does not include
 INST_LIB and INST_ARCH in its C<@INC>.  This apparently odd behavior
-is there for backwards compatibility (and it's somewhat DWIM).
-
+is there for backwards compatibility (and it's somewhat DWIM).  The argument
+passed to the .PL is set up as a target to build in the Makefile.  In other
+sections such as C<postamble> you can specify a dependency on the
+filename/argument that the .PL is supposed (or will have, now that that is
+is a dependency) to generate.  Note the file to be generated will still be
+generated and the .PL will still run even without an explicit dependency created
+by you, since the C<all> target still depends on running all eligible to run.PL
+files.
 
 =item PM
 
@@ -2536,24 +2604,23 @@ Defining PM in the Makefile.PL will override PMLIBDIRS.
 A filter program, in the traditional Unix sense (input from stdin, output
 to stdout) that is passed on each .pm file during the build (in the
 pm_to_blib() phase).  It is empty by default, meaning no filtering is done.
+You could use:
 
-Great care is necessary when defining the command if quoting needs to be
-done.  For instance, you would need to say:
-
-  {'PM_FILTER' => 'grep -v \\"^\\#\\"'}
+  PM_FILTER => 'perl -ne "print unless /^\\#/"',
 
-to remove all the leading comments on the fly during the build.  The
-extra \\ are necessary, unfortunately, because this variable is interpolated
-within the context of a Perl program built on the command line, and double
-quotes are what is used with the -e switch to build that command line.  The
-# is escaped for the Makefile, since what is going to be generated will then
-be:
+to remove all the leading comments on the fly during the build.  In order
+to be as portable as possible, please consider using a Perl one-liner
+rather than Unix (or other) utilities, as above.  The # is escaped for
+the Makefile, since what is going to be generated will then be:
 
-  PM_FILTER = grep -v \"^\#\"
+  PM_FILTER = perl -ne "print unless /^\#/"
 
-Without the \\ before the #, we'd have the start of a Makefile comment,
+Without the \ before the #, we'd have the start of a Makefile comment,
 and the macro would be incorrectly defined.
 
+You will almost certainly be better off using the C<PL_FILES> system,
+instead. See above, or the L<ExtUtils::MakeMaker::FAQ> entry.
+
 =item POLLUTE
 
 Release 5.005 grandfathered old global symbol names by providing preprocessor
@@ -2623,8 +2690,11 @@ doesn't.  See L<Test::More/BAIL_OUT> for more details.
 A hash of modules that are needed to run your module.  The keys are
 the module names ie. Test::More, and the minimum version is the
 value. If the required version number is 0 any version will do.
+The versions given may be a Perl v-string (see L<version>) or a range
+(see L<CPAN::Meta::Requirements>).
 
-This will go into the C<requires> field of your F<META.yml> and the C<runtime> of the C<prereqs> field of your F<META.json>.
+This will go into the C<requires> field of your F<META.yml> and the
+C<runtime> of the C<prereqs> field of your F<META.json>.
 
     PREREQ_PM => {
         # Require Test::More at least 0.47
@@ -2793,6 +2863,49 @@ Hashref of .xs files. MakeMaker will default this.  e.g.
 The .c files will automatically be included in the list of files
 deleted by a make clean.
 
+=item XSBUILD
+
+Hashref with options controlling the operation of C<XSMULTI>:
+
+  {
+    xs => {
+        all => {
+            # options applying to all .xs files for this distribution
+        },
+        'lib/Class/Name/File' => { # specifically for this file
+            DEFINE => '-Dfunktastic', # defines for only this file
+            INC => "-I$funkyliblocation", # include flags for only this file
+            # OBJECT => 'lib/Class/Name/File$(OBJ_EXT)', # default
+            LDFROM => "lib/Class/Name/File\$(OBJ_EXT) $otherfile\$(OBJ_EXT)", # what's linked
+        },
+    },
+  }
+
+Note C<xs> is the file-extension. More possibilities may arise in the
+future. Note that object names are specified without their XS extension.
+
+C<LDFROM> defaults to the same as C<OBJECT>. C<OBJECT> defaults to,
+for C<XSMULTI>, just the XS filename with the extension replaced with
+the compiler-specific object-file extension.
+
+The distinction between C<OBJECT> and C<LDFROM>: C<OBJECT> is the make
+target, so make will try to build it. However, C<LDFROM> is what will
+actually be linked together to make the shared object or static library
+(SO/SL), so if you override it, make sure it includes what you want to
+make the final SO/SL, almost certainly including the XS basename with
+C<$(OBJ_EXT)> appended.
+
+=item XSMULTI
+
+When this is set to C<1>, multiple XS files may be placed under F<lib/>
+next to their corresponding C<*.pm> files (this is essential for compiling
+with the correct C<VERSION> values). This feature should be considered
+experimental, and details of it may change.
+
+This feature was inspired by, and small portions of code copied from,
+L<ExtUtils::MakeMaker::BigHelper>. Hopefully this feature will render
+that module mainly obsolete.
+
 =item XSOPT
 
 String of options to pass to xsubpp.  This might include C<-C++> or
@@ -3112,13 +3225,13 @@ part of the 'distdir' target (and thus the 'dist' target).  This is intended to
 seamlessly and rapidly populate CPAN with module meta-data.  If you wish to
 shut this feature off, set the C<NO_META> C<WriteMakefile()> flag to true.
 
-At the 2008 QA Hackathon in Oslo, Perl module toolchain maintainers agrees
+At the 2008 QA Hackathon in Oslo, Perl module toolchain maintainers agreed
 to use the CPAN Meta format to communicate post-configuration requirements
 between toolchain components.  These files, F<MYMETA.json> and F<MYMETA.yml>,
 are generated when F<Makefile.PL> generates a F<Makefile> (if L<CPAN::Meta>
-is installed).  Clients like L<CPAN> or L<CPANPLUS> will read this
+is installed).  Clients like L<CPAN> or L<CPANPLUS> will read these
 files to see what prerequisites must be fulfilled before building or testing
-the distribution.  If you with to shut this feature off, set the C<NO_MYMETA>
+the distribution.  If you wish to shut this feature off, set the C<NO_MYMETA>
 C<WriteMakeFile()> flag to true.
 
 =head2 Disabling an extension
index 3b96836..7259f34 100644 (file)
@@ -2,7 +2,8 @@ package ExtUtils::MakeMaker::Config;
 
 use strict;
 
-our $VERSION = '7.10_01';
+our $VERSION = '7.18';
+$VERSION = eval $VERSION;
 
 use Config ();
 
index d3aa100..6f59192 100644 (file)
@@ -1,6 +1,7 @@
 package ExtUtils::MakeMaker::FAQ;
 
-our $VERSION = '7.10_01';
+our $VERSION = '7.18';
+$VERSION = eval $VERSION;
 
 1;
 __END__
@@ -21,8 +22,12 @@ FAQs, tricks and tips for C<ExtUtils::MakeMaker>.
 =item How do I install a module into my home directory?
 
 If you're not the Perl administrator you probably don't have
-permission to install a module to its default location.  Then you
-should install it for your own use into your home directory like so:
+permission to install a module to its default location. Ways of handling
+this with a B<lot> less manual effort on your part are L<perlbrew>
+and L<local::lib>.
+
+Otherwise, you can install it for your own use into your home directory
+like so:
 
     # Non-unix folks, replace ~ with /path/to/your/home/dir
     perl Makefile.PL INSTALL_BASE=~
@@ -41,7 +46,6 @@ reason, do it the long way.
 
     use lib "/path/to/your/home/dir/lib/perl5";
 
-
 =item How do I get MakeMaker and Module::Build to install to the same place?
 
 Module::Build, as of 0.28, supports two ways to install to the same
@@ -99,8 +103,10 @@ Two ways.  One is to build the module normally...
         make
         make test
 
-...and then set the PERL5LIB environment variable to point at the
-blib/lib and blib/arch directories.
+...and then use L<blib> to point Perl at the built but uninstalled module:
+
+       perl -Mblib script.pl
+       perl -Mblib -e '...'
 
 The other is to install the module in a temporary location.
 
@@ -112,20 +118,66 @@ The other is to install the module in a temporary location.
 And then set PERL5LIB to F<~/tmp/lib/perl5>.  This works well when you
 have multiple modules to work with.  It also ensures that the module
 goes through its full installation process which may modify it.
+Again, L<local::lib> may assist you here.
 
 =item PREFIX vs INSTALL_BASE from Module::Build::Cookbook
 
 The behavior of PREFIX is complicated and depends closely 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 where prefix will place your modules.
+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 where prefix
+will place your modules.
+
+In contrast, INSTALL_BASE has predictable, easy to explain installation
+locations.  Now that Module::Build and MakeMaker both have INSTALL_BASE
+there is little reason to use PREFIX other than to preserve your existing
+installation locations. If you are starting a fresh Perl installation we
+encourage you to use INSTALL_BASE. If you have an existing installation
+installed via PREFIX, consider moving it to an installation structure
+matching INSTALL_BASE and using that instead.
+
+=item Generating *.pm files with substitutions eg of $VERSION
+
+If you want to configure your module files for local conditions, or to
+automatically insert a version number, you can use EUMM's C<PL_FILES>
+capability, where it will automatically run each F<*.PL> it finds to
+generate its basename. For instance:
+
+    # Makefile.PL:
+    require 'common.pl';
+    my $version = get_version();
+    my @pms = qw(Foo.pm);
+    WriteMakefile(
+      NAME => 'Foo',
+      VERSION => $version,
+      PM => { map { ($_ => "\$(INST_LIB)/$_") } @pms },
+      clean => { FILES => join ' ', @pms },
+    );
 
-In contrast, INSTALL_BASE has predictable, easy to explain installation locations.
-Now that Module::Build and MakeMaker both have INSTALL_BASE there is little reason
-to use PREFIX other than to preserve your existing installation locations. If you
-are starting a fresh Perl installation we encourage you to use INSTALL_BASE. If
-you have an existing installation installed via PREFIX, consider moving it to an
-installation structure matching INSTALL_BASE and using that instead.
+    # common.pl:
+    sub get_version { '0.04' }
+    sub process { my $v = get_version(); s/__VERSION__/$v/g; }
+    1;
+
+    # Foo.pm.PL:
+    require 'common.pl';
+    $_ = join '', <DATA>;
+    process();
+    my $file = shift;
+    open my $fh, '>', $file or die "$file: $!";
+    print $fh $_;
+    __DATA__
+    package Foo;
+    our $VERSION = '__VERSION__';
+    1;
+
+You may notice that C<PL_FILES> is not specified above, since the default
+of mapping each .PL file to its basename works well.
+
+If the generated module were architecture-specific, you could replace
+C<$(INST_LIB)> above with C<$(INST_ARCHLIB)>, although if you locate
+modules under F<lib>, that would involve ensuring any C<lib/> in front
+of the module location were removed.
 
 =back
 
@@ -184,16 +236,16 @@ Its primary advantages are:
 
 =back
 
-Module::Build was long the official heir apparent to MakeMaker.  The rate of
-both its development and adoption has slowed in recent years, though, and it is
-unclear what the future holds for it.  That said, Module::Build set the stage
-for I<something> to become the heir to MakeMaker.  MakeMaker's maintainers have
-long said that it is a dead end and should be kept functioning, but not
-extended with new features.  It's complicated enough as it is!
+Module::Build was long the official heir apparent to MakeMaker.  The
+rate of both its development and adoption has slowed in recent years,
+though, and it is unclear what the future holds for it.  That said,
+Module::Build set the stage for I<something> to become the heir to
+MakeMaker.  MakeMaker's maintainers have long said that it is a dead
+end and should be kept functioning, while being cautious about extending
+with new features.
 
 =back
 
-
 =head2 Module Writing
 
 =over 4
@@ -207,8 +259,14 @@ modules in your dist, $VERSION is really just bookkeeping and all that's
 important is it goes up every time the module is changed.  Doing this
 by hand is a pain and you often forget.
 
-Simplest way to do it automatically is to use your version control
-system's revision number (you are using version control, right?).
+Probably the easiest way to do this is using F<perl-reversion> in
+L<Perl::Version>:
+
+  perl-reversion -bump
+
+If your version control system supports revision numbers (git doesn't
+easily), the simplest way to do it automatically is to use its revision
+number (you are using version control, right?).
 
 In CVS, RCS and SVN you use $Revision$ (see the documentation of your
 version control system for details).  Every time the file is checked
@@ -300,7 +358,7 @@ do that.  Use at your own risk.  Have fun blowing holes in your foot.
 
 We recommend ptar from Archive::Tar not older than 1.66 with '-C' option.
 
-=item Which zip should I use on Windows for '[nd]make zipdist'?
+=item Which zip should I use on Windows for '[ndg]make zipdist'?
 
 We recommend InfoZIP: L<http://www.info-zip.org/Zip.html>
 
@@ -309,9 +367,7 @@ We recommend InfoZIP: L<http://www.info-zip.org/Zip.html>
 
 =head2 XS
 
-=over 4
-
-=item How do I prevent "object version X.XX does not match bootstrap parameter Y.YY" errors?
+=head3 How do I prevent "object version X.XX does not match bootstrap parameter Y.YY" errors?
 
 XS code is very sensitive to the module version number and will
 complain if the version number in your Perl module doesn't match.  If
@@ -326,12 +382,28 @@ WriteMakefile() arguments.
     depend => { '$(FIRST_MAKEFILE)' => '$(VERSION_FROM)' }
 
 
-=item How do I make two or more XS files coexist in the same directory?
+=head3 How do I make two or more XS files coexist in the same directory?
 
 Sometimes you need to have two and more XS files in the same package.
-One way to go is to put them into separate directories, but sometimes
-this is not the most suitable solution. The following technique allows
-you to put two (and more) XS files in the same directory.
+There are three ways: C<XSMULTI>, separate directories, and bootstrapping
+one XS from another.
+
+=head4 XSMULTI
+
+Structure your modules so they are all located under F<lib>, such that
+C<Foo::Bar> is in F<lib/Foo/Bar.pm> and F<lib/Foo/Bar.xs>, etc. Have your
+top-level C<WriteMakefile> set the variable C<XSMULTI> to a true value.
+
+Er, that's it.
+
+=head4 Separate directories
+
+Put each XS files into separate directories, each with their own
+F<Makefile.PL>. Make sure each of those F<Makefile.PL>s has the correct
+C<CFLAGS>, C<INC>, C<LIBS> etc. You will need to make sure the top-level
+F<Makefile.PL> refers to each of these using C<DIR>.
+
+=head4 Bootstrapping
 
 Let's assume that we have a package C<Cool::Foo>, which includes
 C<Cool::Foo> and C<Cool::Bar> modules each having a separate XS
@@ -446,12 +518,113 @@ And of course a very basic test:
 
 This tip has been brought to you by Nick Ing-Simmons and Stas Bekman.
 
+An alternative way to achieve this can be seen in L<Gtk2::CodeGen>
+and L<Glib::CodeGen>.
+
 =back
 
+=head1 DESIGN
+
+=head2 MakeMaker object hierarchy (simplified)
+
+What most people need to know (superclasses on top.)
+
+        ExtUtils::MM_Any
+                |
+        ExtUtils::MM_Unix
+                |
+        ExtUtils::MM_{Current OS}
+                |
+        ExtUtils::MakeMaker
+                |
+               MY
+
+The object actually used is of the class MY which allows you to
+override bits of MakeMaker inside your Makefile.PL by declaring
+MY::foo() methods.
+
+=head2 MakeMaker object hierarchy (real)
+
+Here's how it really works:
+
+                                    ExtUtils::MM_Any
+                                            |
+                                    ExtUtils::MM_Unix
+                                            |
+    ExtUtils::Liblist::Kid          ExtUtils::MM_{Current OS} (if necessary)
+          |                                          |
+    ExtUtils::Liblist     ExtUtils::MakeMaker        |
+                    |     |                          |   
+                    |     |   |-----------------------
+                   ExtUtils::MM
+                   |          |
+        ExtUtils::MY         MM (created by ExtUtils::MM)
+        |                                   |
+        MY (created by ExtUtils::MY)        |
+                    .                       |
+                 (mixin)                    |
+                    .                       |
+               PACK### (created each call to ExtUtils::MakeMaker->new)
+
+NOTE: Yes, this is a mess.  See
+L<http://archive.develooper.com/makemaker@perl.org/msg00134.html>
+for some history.
+
+NOTE: When ExtUtils::MM is loaded it chooses a superclass for MM from
+amongst the ExtUtils::MM_* modules based on the current operating
+system.
+
+NOTE: ExtUtils::MM_{Current OS} represents one of the ExtUtils::MM_*
+modules except ExtUtils::MM_Any chosen based on your operating system.
+
+NOTE: The main object used by MakeMaker is a PACK### object, *not*
+ExtUtils::MakeMaker.  It is, effectively, a subclass of MY,
+ExtUtils::Makemaker, ExtUtils::Liblist and ExtUtils::MM_{Current OS}
+
+NOTE: The methods in MY are simply copied into PACK### rather than
+MY being a superclass of PACK###.  I don't remember the rationale.
+
+NOTE: ExtUtils::Liblist should be removed from the inheritence hiearchy
+and simply be called as functions.
+
+NOTE: Modules like File::Spec and Exporter have been omitted for clarity.
+
+
+=head2 The MM_* hierarchy
+
+                                MM_Win95   MM_NW5
+                                     \      /
+ MM_BeOS  MM_Cygwin  MM_OS2  MM_VMS  MM_Win32  MM_DOS  MM_UWIN
+       \        |      |         |        /      /      /
+        ------------------------------------------------
+                           |       |
+                        MM_Unix    |
+                              |    |
+                              MM_Any
+
+NOTE: Each direct MM_Unix subclass is also an MM_Any subclass.  This
+is a temporary hack because MM_Unix overrides some MM_Any methods with
+Unix specific code.  It allows the non-Unix modules to see the
+original MM_Any implementations.
+
+NOTE: Modules like File::Spec and Exporter have been omitted for clarity.
+
 =head1 PATCHING
 
 If you have a question you'd like to see added to the FAQ (whether or
-not you have the answer) please send it to makemaker@perl.org.
+not you have the answer) please either:
+
+=over 2
+
+=item * make a pull request on the MakeMaker github repository
+
+=item * raise a issue on the MakeMaker github repository
+
+=item * file an RT ticket
+
+=item * email makemaker@perl.org
+
+=back
 
 =head1 AUTHOR
 
index 68fcd4c..21f5974 100644 (file)
@@ -1,7 +1,8 @@
 package ExtUtils::MakeMaker::Locale;
 
 use strict;
-our $VERSION = "7.10";
+our $VERSION = "7.18";
+$VERSION = eval $VERSION;
 
 use base 'Exporter';
 our @EXPORT_OK = qw(
@@ -137,7 +138,7 @@ Encode::Alias::define_alias(sub {
 
 sub _flush_aliases {
     no strict 'refs';
-    for my $a (keys %Encode::Alias::Alias) {
+    for my $a (sort keys %Encode::Alias::Alias) {
        if (defined ${"ENCODING_" . uc($a)}) {
            delete $Encode::Alias::Alias{$a};
            warn "Flushed alias cache for $a" if DEBUG;
index 7e53baa..976345f 100644 (file)
@@ -1,6 +1,7 @@
 package ExtUtils::MakeMaker::Tutorial;
 
-our $VERSION = '7.10_01';
+our $VERSION = '7.18';
+$VERSION = eval $VERSION;
 
 
 =head1 NAME
index 35cd2ab..a6584c7 100644 (file)
 
 package ExtUtils::MakeMaker::version;
 
-use 5.006002;
+use 5.006001;
 use strict;
 
 use vars qw(@ISA $VERSION $CLASS $STRICT $LAX *declare *qv);
 
-$VERSION = '7.10_01';
+$VERSION = '7.18';
+$VERSION = eval $VERSION;
 $CLASS = 'version';
 
 {
index a0213b1..896998e 100644 (file)
@@ -10,7 +10,8 @@ use strict;
 
 use vars qw($VERSION $CLASS $STRICT $LAX);
 
-$VERSION = '7.10_01';
+$VERSION = '7.18';
+$VERSION = eval $VERSION;
 
 #--------------------------------------------------------------------------#
 # Version regexp components
index a393329..2a0d463 100644 (file)
@@ -3,7 +3,8 @@ package ExtUtils::Mkbootstrap;
 # There's just too much Dynaloader incest here to turn on strict vars.
 use strict 'refs';
 
-our $VERSION = '7.10_01';
+our $VERSION = '7.18';
+$VERSION = eval $VERSION;
 
 require Exporter;
 our @ISA = ('Exporter');
@@ -47,7 +48,7 @@ sub Mkbootstrap {
 
     my(@all) = (@bsloadlibs, @DynaLoader::dl_resolve_using);
     my($method) = '';
-    if (@all){
+    if (@all || (defined $DynaLoader::bscode && length $DynaLoader::bscode)){
        open my $bs, ">", "$baseext.bs"
                or die "Unable to open $baseext.bs: $!";
        print "Writing $baseext.bs\n";
@@ -56,13 +57,15 @@ sub Mkbootstrap {
        print $bs "# Do not edit this file, changes will be lost.\n";
        print $bs "# This file was automatically generated by the\n";
        print $bs "# Mkbootstrap routine in ExtUtils::Mkbootstrap (v$VERSION).\n";
-       print $bs "\@DynaLoader::dl_resolve_using = ";
-       # If @all contains names in the form -lxxx or -Lxxx then it's asking for
-       # runtime library location so we automatically add a call to dl_findfile()
-       if (" @all" =~ m/ -[lLR]/){
-           print $bs "  dl_findfile(qw(\n  @all\n  ));\n";
-       }else{
-           print $bs "  qw(@all);\n";
+       if (@all) {
+           print $bs "\@DynaLoader::dl_resolve_using = ";
+           # If @all contains names in the form -lxxx or -Lxxx then it's asking for
+           # runtime library location so we automatically add a call to dl_findfile()
+           if (" @all" =~ m/ -[lLR]/){
+               print $bs "  dl_findfile(qw(\n  @all\n  ));\n";
+           } else {
+               print $bs "  qw(@all);\n";
+           }
        }
        # write extra code if *_BS says so
        print $bs $DynaLoader::bscode if $DynaLoader::bscode;
index b80310e..582b290 100644 (file)
@@ -10,7 +10,8 @@ use Config;
 
 our @ISA = qw(Exporter);
 our @EXPORT = qw(&Mksymlists);
-our $VERSION = '7.10_01';
+our $VERSION = '7.18';
+$VERSION = eval $VERSION;
 
 sub Mksymlists {
     my(%spec) = @_;
@@ -135,7 +136,7 @@ sub _write_win32 {
     open( my $def, ">", "$data->{FILE}.def" )
         or croak("Can't create $data->{FILE}.def: $!\n");
     # put library name in quotes (it could be a keyword, like 'Alias')
-    if ($Config::Config{'cc'} !~ /^gcc/i) {
+    if ($Config::Config{'cc'} !~ /\bgcc/i) {
         print $def "LIBRARY \"$data->{DLBASE}\"\n";
     }
     print $def "EXPORTS\n  ";
index 6f5d870..3f2795b 100644 (file)
@@ -3,7 +3,8 @@ package ExtUtils::testlib;
 use strict;
 use warnings;
 
-our $VERSION = '7.10_01';
+our $VERSION = '7.18';
+$VERSION = eval $VERSION;
 
 use Cwd;
 use File::Spec;
index 618dc09..71d29b6 100644 (file)
@@ -7,7 +7,7 @@ use warnings;
 
 use lib 't/lib';
 
-use Test::More;
+use Test::More tests => 1;
 
 note "The 0.01 / Gconvert bug"; {
     my $number = 0.01;
@@ -21,5 +21,3 @@ or upgrade to a newer version of Perl.
 END
     };
 }
-
-done_testing;
diff --git a/cpan/ExtUtils-MakeMaker/t/02-xsdynamic.t b/cpan/ExtUtils-MakeMaker/t/02-xsdynamic.t
new file mode 100644 (file)
index 0000000..5ed28de
--- /dev/null
@@ -0,0 +1,23 @@
+#!/usr/bin/perl -w
+
+use strict;
+use warnings;
+use Config;
+BEGIN {
+    chdir 't' or die "chdir(t): $!\n";
+    unshift @INC, 'lib/';
+}
+use MakeMaker::Test::Utils;
+use MakeMaker::Test::Setup::XS;
+use Test::More;
+
+plan skip_all => 'Dynaloading not enabled' if !$Config{usedl} or $Config{usedl} ne 'define';
+plan skip_all => "ExtUtils::CBuilder not installed or couldn't find a compiler"
+  unless have_compiler();
+my @tests = list_dynamic();
+plan skip_all => "No tests" unless @tests;
+plan tests => 6 * @tests;
+my $perl = which_perl();
+perl_lib;
+$| = 1;
+run_tests($perl, @$_) for @tests;
diff --git a/cpan/ExtUtils-MakeMaker/t/03-xsstatic.t b/cpan/ExtUtils-MakeMaker/t/03-xsstatic.t
new file mode 100644 (file)
index 0000000..1d748eb
--- /dev/null
@@ -0,0 +1,27 @@
+#!/usr/bin/perl -w
+
+use strict;
+use warnings;
+use Config;
+BEGIN {
+    chdir 't' or die "chdir(t): $!\n";
+    unshift @INC, 'lib/';
+}
+use MakeMaker::Test::Utils;
+use MakeMaker::Test::Setup::XS;
+use Test::More;
+
+plan skip_all => "Disabled as broken perl installs give false negative"
+  # if not static perl, and not author
+  unless !$Config{usedl} or $ENV{AUTHOR_TESTING};
+plan skip_all => "ExtUtils::CBuilder not installed or couldn't find a compiler"
+  unless have_compiler();
+plan skip_all => 'Shared perl library' if $Config{useshrplib} eq 'true';
+plan skip_all => $^O if $^O =~ m!^(MSWin32|cygwin|haiku)$!;
+my @tests = list_static();
+plan skip_all => "No tests" unless @tests;
+plan tests => 6 * @tests;
+my $perl = which_perl();
+perl_lib;
+$| = 1;
+run_tests($perl, @$_) for @tests;
index 7218dd3..cb8d0db 100644 (file)
@@ -4,20 +4,22 @@ BEGIN {
     unshift @INC, 't/lib';
 }
 
-use File::Temp qw[tempdir];
-my $tmpdir = tempdir( DIR => 't', CLEANUP => 1 );
-chdir $tmpdir;
-
 use strict;
 use Test::More tests => 7;
 
 use MakeMaker::Test::Setup::BFD;
 use MakeMaker::Test::Utils;
 
+chdir 't';
+perl_lib; # sets $ENV{PERL5LIB} relative to t/
+
+use File::Temp qw[tempdir];
+my $tmpdir = tempdir( DIR => '../t', CLEANUP => 1 );
+use Cwd; my $cwd = getcwd; END { chdir $cwd } # so File::Temp can cleanup
+chdir $tmpdir;
+
 my $perl = which_perl();
 my $make = make_run();
-perl_lib();
-
 
 ok( setup_recurs(), 'setup' );
 END {
index 91058bb..3562162 100644 (file)
@@ -18,12 +18,14 @@ use File::Spec;
 use TieOut;
 use Config;
 
+chdir 't';
+perl_lib; # sets $ENV{PERL5LIB} relative to t/
+
 use File::Temp qw[tempdir];
-my $tmpdir = tempdir( DIR => 't', CLEANUP => 1 );
+my $tmpdir = tempdir( DIR => '../t', CLEANUP => 1 );
+use Cwd; my $cwd = getcwd; END { chdir $cwd } # so File::Temp can cleanup
 chdir $tmpdir;
 
-perl_lib;
-
 $| = 1;
 
 my $Makefile = makefile_name;
@@ -47,8 +49,8 @@ my $mm = WriteMakefile(
     PERL_CORE     => $ENV{PERL_CORE},
 );
 like( $stdout->read, qr{
-                        Generating\ a\ \w+?-style\ $Makefile\n
-                        Writing\ $Makefile\ for\ Big::Liar\n
+                        (?:Generating\ a\ \w+?-style\ $Makefile\n)?
+                        (?:Writing\ $Makefile\ for\ Big::Liar\n)?
                         (?:Writing\ MYMETA.yml\ and\ MYMETA.json\n)?
                         Big::Liar's\ vars\n
                         INST_LIB\ =\ \S+\n
@@ -135,8 +137,8 @@ $mm = WriteMakefile(
     INST_MAN1DIR         => 'none',
 );
 like( $stdout->read, qr{
-                        Generating\ a\ \w+?-style\ $Makefile\n
-                        Writing\ $Makefile\ for\ Big::Liar\n
+                        (?:Generating\ a\ \w+?-style\ $Makefile\n)?
+                        (?:Writing\ $Makefile\ for\ Big::Liar\n)?
                         (?:Writing\ MYMETA.yml\ and\ MYMETA.json\n)?
                         Big::Liar's\ vars\n
                         INST_LIB\ =\ \S+\n
index fc31611..6939811 100644 (file)
@@ -15,33 +15,40 @@ $CLEANUP &&= 1; # so always 1 or numerically 0
 
 use MakeMaker::Test::Utils;
 use MakeMaker::Test::Setup::BFD;
-use Test::More;
 use Config;
 use ExtUtils::MM;
-plan !MM->can_run(make()) && $ENV{PERL_CORE} && $Config{'usecrosscompile'}
+use Test::More
+    !MM->can_run(make()) && $ENV{PERL_CORE} && $Config{'usecrosscompile'}
     ? (skip_all => "cross-compiling and make not available")
-    : (tests => 3 + $CLEANUP + @INSTDIRS * (15 + $CLEANUP));
+    : ();
+plan tests => 4 + $CLEANUP + @INSTDIRS * (15 + $CLEANUP);
 
 my $Is_VMS = $^O eq 'VMS';
 
 my $perl = which_perl();
 
+chdir 't';
+perl_lib; # sets $ENV{PERL5LIB} relative to t/
+
 use File::Temp qw[tempdir];
-my $tmpdir = tempdir( DIR => 't', CLEANUP => $CLEANUP );
+my $tmpdir = tempdir( DIR => '../t', CLEANUP => $CLEANUP );
+use Cwd; my $cwd = getcwd; END { chdir $cwd } # so File::Temp can cleanup
 chdir $tmpdir;
 
-perl_lib;
-
-ok( setup_recurs(), 'setup' );
+my $SPACEDIR = 'space dir';
+ok( setup_recurs($SPACEDIR), 'setup' );
 END {
     ok( chdir File::Spec->updir, 'chdir updir' );
+    ok( chdir File::Spec->updir, 'chdir updir again' );
     ok( teardown_recurs(), 'teardown' ) if $CLEANUP;
     map { rmtree $_ } @INSTDIRS if $CLEANUP;
 }
 
-ok( chdir('Big-Dummy'), "chdir'd to Big-Dummy") || diag("chdir failed; $!");
+ok( chdir(File::Spec->catdir($SPACEDIR, 'Big-Dummy')), "chdir'd to Big-Dummy") || diag("chdir failed; $!");
 
 for my $instdir (@INSTDIRS) {
+  $instdir = File::Spec->rel2abs($instdir);
+  $instdir = VMS::Filespec::unixpath($instdir) if $Is_VMS;
   my @mpl_out = run(qq{$perl Makefile.PL "INSTALL_BASE=$instdir"});
 
   cmp_ok( $?, '==', 0, 'Makefile.PL exited with zero' ) ||
index e8de7c6..5f7d395 100644 (file)
@@ -20,12 +20,14 @@ use ExtUtils::MakeMaker::Config;
 
 my $Is_VMS = $^O eq 'VMS';
 
+chdir 't';
+perl_lib; # sets $ENV{PERL5LIB} relative to t/
+
 use File::Temp qw[tempdir];
-my $tmpdir = tempdir( DIR => 't', CLEANUP => 1 );
+my $tmpdir = tempdir( DIR => '../t', CLEANUP => 1 );
+use Cwd; my $cwd = getcwd; END { chdir $cwd } # so File::Temp can cleanup
 chdir $tmpdir;
 
-perl_lib;
-
 $| = 1;
 
 my $Makefile = makefile_name;
@@ -51,8 +53,8 @@ my $mm = WriteMakefile(
 );
 
 like( $stdout->read, qr{
-                        Generating\ a\ \w+?-style\ $Makefile\n
-                        Writing\ $Makefile\ for\ Big::Liar\n
+                        (?:Generating\ a\ \w+?-style\ $Makefile\n)?
+                        (?:Writing\ $Makefile\ for\ Big::Liar\n)?
                         (?:Writing\ MYMETA.yml\ and\ MYMETA.json\n)?
                         Big::Liar's\ vars\n
                         INST_LIB\ =\ \S+\n
@@ -83,8 +85,8 @@ $mm = WriteMakefile(
     PREFIX        => $PREFIX,
 );
 like( $stdout->read, qr{
-                        Generating\ a\ \w+?-style\ $Makefile\n
-                        Writing\ $Makefile\ for\ Big::Liar\n
+                        (?:Generating\ a\ \w+?-style\ $Makefile\n)?
+                        (?:Writing\ $Makefile\ for\ Big::Liar\n)?
                         (?:Writing\ MYMETA.yml\ and\ MYMETA.json\n)?
                         Big::Liar's\ vars\n
                         INST_LIB\ =\ \S+\n
index 0655d17..4e7336c 100644 (file)
@@ -74,7 +74,7 @@ unlike( $MM->manifypods(), qr/foo/,
 
 $MM->{MAN3PODS} = { foo => 'foo.1' };
 my $res = $MM->manifypods();
-like( $res, qr/pure_all.*foo.*foo.1/s, '... should add MAN3PODS targets' );
+like( $res, qr/manifypods.*foo.*foo.1/s, '... should add MAN3PODS targets' );
 
 
 # init_linker
index 383e6d9..447abd2 100644 (file)
@@ -131,7 +131,6 @@ delete $ENV{PATHEXT} unless $had_pathext;
         $mm_w32->{$key} = '';
     }
     my $s_PM = join( " \\\n\t", sort keys %{$mm_w32->{PM}} );
-    my $k_PM = join( " \\\n\t", %{$mm_w32->{PM}} );
 
     like( $mm_w32->constants(),
           qr|^NAME\ =\ TestMM_NW5\s+VERSION\ =\ 1\.00.+
@@ -139,7 +138,6 @@ delete $ENV{PATHEXT} unless $had_pathext;
              MM_VERSION\ =\ \Q$ExtUtils::MakeMaker::VERSION\E.+
              VERSION_FROM\ =\ TestMM_NW5.+
              TO_INST_PM\ =\ \Q$s_PM\E\s+
-             PM_TO_BLIB\ =\ \Q$k_PM\E
           |xs, 'constants()' );
 
 }
index f0a3889..3af343d 100644 (file)
@@ -268,6 +268,6 @@ is( $mm->{EXPORT_LIST}, '$(BASEEXT).def',
 
 END {
        use File::Path;
-       rmtree('tmp_imp');
+       rmtree('tmp_imp') if -e 'tmp_imp';
        unlink 'tmpimp.imp';
 }
index ed07691..9a8d18f 100644 (file)
@@ -98,7 +98,6 @@ foreach ( qw /
   ppd
   prefixify
   processPL
-  quote_paren
   realclean
   static
   static_lib
@@ -223,3 +222,10 @@ foreach (qw/ EXPORT_LIST PERL_ARCHIVE PERL_ARCHIVE_AFTER /)
     like( $t->{CCFLAGS}, qr/\-DMY_THING/,    'cflags retains CCFLAGS' );
 }
 
+{
+    my @targv = ("var=don't forget about spaces and single quotes");
+    local @ARGV = @targv;
+    my $t = bless { NAME => "Foo", FULLPERL => $0, DIR => [] }, $class;
+    $t->makeaperl( TARGET => "Tgt" );
+    is_deeply( \@ARGV, \@targv, 'ARGV is not polluted by makeaperl' );
+}
index fee1e5e..bac36bf 100644 (file)
@@ -13,6 +13,7 @@ BEGIN {
         plan skip_all => 'This is not Win32';
     }
 }
+plan 'no_plan'; # BinGOs says there are 63 but I can only see 62
 
 use Config;
 use File::Spec;
@@ -146,7 +147,6 @@ note "init_others creates expected keys"; {
     $mm_w32->init_xs;
 
     my $s_PM = join( " \\\n\t", sort keys %{$mm_w32->{PM}} );
-    my $k_PM = join( " \\\n\t", %{$mm_w32->{PM}} );
 
     my $constants = $mm_w32->constants;
 
@@ -156,7 +156,6 @@ note "init_others creates expected keys"; {
          qr|^MAKEMAKER  \s* = \s* \Q$INC{'ExtUtils/MakeMaker.pm'}\E \s* $|xms,
          qr|^MM_VERSION \s* = \s* \Q$ExtUtils::MakeMaker::VERSION\E \s* $|xms,
          qr|^TO_INST_PM \s* = \s* \Q$s_PM\E \s* $|xms,
-         qr|^PM_TO_BLIB \s* = \s* \Q$k_PM\E \s* $|xms,
         )
     {
         like( $constants, $regex, 'constants() check' );
@@ -281,7 +280,7 @@ unlink "${script_name}$script_ext" if -f "${script_name}$script_ext";
 
         my @cc_env = ExtUtils::MM_Win32::_identify_compiler_environment( $config );
 
-        my %cc_env = ( BORLAND => $cc_env[0], GCC => $cc_env[1], DLLTOOL => $cc_env[2] );
+        my %cc_env = ( BORLAND => $cc_env[0], GCC => $cc_env[1], MSVC => $cc_env[2] );
 
         return \%cc_env;
     }
@@ -300,16 +299,6 @@ unlink "${script_name}$script_ext" if -f "${script_name}$script_ext";
     }
 
     my @tests = (
-        {
-            config => {},
-            key => 'DLLTOOL', expect => 'dlltool',
-            desc => 'empty dlltool defaults to "dlltool"',
-        },
-        {
-            config => { dlltool => 'test' },
-            key => 'DLLTOOL', expect => 'test',
-            desc => 'dlltool value is taken over verbatim from %Config, if set',
-        },
         {
             config => {},
             key => 'GCC', expect => 0,
@@ -347,8 +336,8 @@ unlink "${script_name}$script_ext" if -f "${script_name}$script_ext";
         },
         {
             config => { cc => 'C:/Borland/bin/bcc.exe' },
-            key => 'BORLAND', expect => 0,
-            desc => 'fully qualified borland cc is not recognized',
+            key => 'BORLAND', expect => 1,
+            desc => 'fully qualified borland cc is recognized',
         },
         {
             config => { cc => 'bcc-1.exe' },
@@ -365,10 +354,6 @@ unlink "${script_name}$script_ext" if -f "${script_name}$script_ext";
     _check_cc_id_value($_) for @tests;
 }
 
-
-done_testing;
-
-
 package FakeOut;
 
 sub TIEHANDLE {
index 8e921bd..b0100e6 100644 (file)
@@ -11,7 +11,7 @@ use strict;
 use warnings;
 
 use ExtUtils::MakeMaker;
-use Test::More;
+use Test::More tests => 6;
 
 my $mm = bless {}, "MM";
 
@@ -62,5 +62,3 @@ process_cmp
 #     NAME => q[Foo]
 #     PREREQ_PM => { Baz=>q[0.12], Foo::Bar=>q[1.23], Long=>q[1.45], Short=>q[0] }
 EXPECT
-
-done_testing();
index db061a4..81e49c0 100644 (file)
@@ -75,7 +75,7 @@ SKIP: {
        chmod 0444, 'dasboot.bs';
 
        SKIP: {
-           skip("cannot write readonly files", 1) if -w 'dasboot.bs';
+           skip("cannot write readonly files", 1) if -w 'dasboot.bs' || $^O eq 'cygwin';
 
            eval{ Mkbootstrap('dasboot', 1) };
            like( $@, qr/Unable to open dasboot\.bs/, 'should die given bad filename' );
index f96186f..51aed5e 100644 (file)
@@ -5,33 +5,70 @@ BEGIN {
 }
 
 use strict;
+use warnings;
 
-use File::Spec;
-use File::Temp qw[tempdir];
-use MakeMaker::Test::Setup::PL_FILES;
 use MakeMaker::Test::Utils;
 use Config;
-use Test::More;
 use ExtUtils::MM;
-plan !MM->can_run(make()) && $ENV{PERL_CORE} && $Config{'usecrosscompile'}
+use Test::More
+    !MM->can_run(make()) && $ENV{PERL_CORE} && $Config{'usecrosscompile'}
     ? (skip_all => "cross-compiling and make not available")
-    : (tests => 9);
+    : (tests => 10);
+use File::Spec;
+use File::Temp qw[tempdir];
+use File::Path;
 
 my $perl = which_perl();
 my $make = make_run();
-perl_lib();
+chdir 't';
+perl_lib; # sets $ENV{PERL5LIB} relative to t/
 
-my $tmpdir = tempdir( DIR => 't', CLEANUP => 1 );
+my $tmpdir = tempdir( DIR => '../t', CLEANUP => 1 );
+use Cwd; my $cwd = getcwd; END { chdir $cwd } # so File::Temp can cleanup
 chdir $tmpdir;
 
-setup;
+my $DIRNAME = 'PL-Module';
+my %FILES = (
+    'Makefile.PL'   => <<'END',
+use ExtUtils::MakeMaker;
+# A module for testing PL_FILES
+WriteMakefile(
+    NAME     => 'PL::Module',
+    PL_FILES => { 'single.PL' => 'single.out',
+                  'multi.PL'  => [qw(1.out 2.out)],
+                  'Bar_pm.PL' => '$(INST_LIB)/PL/Bar.pm',
+                  'Bar2.pm.PL' => 'Bar2.pm',
+    },
+);
+
+package MY;
+sub init_PM {
+  my ($self) = @_;
+  $self->SUPER::init_PM;
+  $self->{PM}{'Bar2.pm'} = '$(INST_LIBDIR)/Bar2.pm'; # PDL does this in WM args
+}
+END
+
+    'single.PL'        => _gen_pl_files(),
+    'multi.PL'         => _gen_pl_files(),
+    'Bar_pm.PL'        => _gen_pm_files(),
+    'Bar2.pm.PL'       => _gen_pm_files(),
+    'lib/PL/Foo.pm' => <<'END',
+# Module to load to ensure PL_FILES have blib in @INC.
+package PL::Foo;
+sub bar { 42 }
+1;
+END
 
+);
+
+hash2files($DIRNAME, \%FILES);
 END {
     ok( chdir File::Spec->updir );
-    ok( teardown );
+    ok( rmtree($DIRNAME) );
 }
 
-ok chdir('PL_FILES-Module');
+ok chdir($DIRNAME);
 
 run(qq{$perl Makefile.PL});
 cmp_ok( $?, '==', 0 );
@@ -39,6 +76,54 @@ cmp_ok( $?, '==', 0 );
 my $make_out = run("$make");
 is( $?, 0 ) || diag $make_out;
 
-foreach my $file (qw(single.out 1.out 2.out blib/lib/PL/Bar.pm)) {
+foreach my $file (qw(single.out 1.out 2.out blib/lib/PL/Bar.pm blib/lib/PL/Bar2.pm)) {
     ok( -e $file, "$file was created" );
 }
+
+sub _gen_pl_files {
+    my $test = <<'END';
+#!/usr/bin/perl -w
+
+# Ensure we have blib in @INC
+use PL::Foo;
+die unless PL::Foo::bar() == 42;
+
+# Had a bug where PL_FILES weren't sent the file to generate
+die "argv empty\n" unless @ARGV;
+die "too many in argv: @ARGV\n" unless @ARGV == 1;
+
+my $file = $ARGV[0];
+open OUT, ">$file" or die $!;
+
+print OUT "Testing\n";
+close OUT
+END
+
+    $test =~ s/^\n//;
+
+    return $test;
+}
+
+sub _gen_pm_files {
+    my $test = <<'END';
+#!/usr/bin/perl -w
+
+# Ensure we do NOT have blib in @INC when building a module
+eval { require PL::Foo; };
+#die $@ unless $@ =~ m{^Can't locate PL/Foo.pm in \@INC };
+
+# Had a bug where PL_FILES weren't sent the file to generate
+die "argv empty\n" unless @ARGV;
+die "too many in argv: @ARGV\n" unless @ARGV == 1;
+
+my $file = $ARGV[0];
+open OUT, ">$file" or die $!;
+
+print OUT "Testing\n";
+close OUT
+END
+
+    $test =~ s/^\n//;
+
+    return $test;
+}
index 7a86fa1..662c48d 100644 (file)
@@ -8,6 +8,7 @@ BEGIN {
 
 use File::Temp qw[tempdir];
 my $tmpdir = tempdir( DIR => 't', CLEANUP => 1 );
+use Cwd; my $cwd = getcwd; END { chdir $cwd } # so File::Temp can cleanup
 chdir $tmpdir;
 
 use strict;
index f58211a..3656c88 100644 (file)
@@ -20,11 +20,11 @@ use utf8;
 use MakeMaker::Test::Utils;
 use MakeMaker::Test::Setup::BFD;
 use Config;
-use Test::More;
 use ExtUtils::MM;
-plan !MM->can_run(make()) && $ENV{PERL_CORE} && $Config{'usecrosscompile'}
+use Test::More
+    !MM->can_run(make()) && $ENV{PERL_CORE} && $Config{'usecrosscompile'}
     ? (skip_all => "cross-compiling and make not available")
-    : (tests => 171);
+    : (tests => 186);
 use File::Find;
 use File::Spec;
 use File::Path;
@@ -55,28 +55,33 @@ END {
     }
 }
 
-my $tmpdir = tempdir( DIR => 't', CLEANUP => 1 );
-chdir $tmpdir;
+chdir 't';
+perl_lib; # sets $ENV{PERL5LIB} relative to t/
 
-perl_lib;
+my $tmpdir = tempdir( DIR => '../t', CLEANUP => 1 );
+use Cwd; my $cwd = getcwd; END { chdir $cwd } # so File::Temp can cleanup
+chdir $tmpdir;
 
 my $Touch_Time = calibrate_mtime();
 
 $| = 1;
 
+delete @ENV{qw(PERL_CORE)};
+
 ok( setup_recurs(), 'setup' );
-END {
-    ok chdir File::Spec->updir or die;
-    ok teardown_recurs, "teardown";
-}
 
 ok( chdir('Big-Dummy'), "chdir'd to Big-Dummy" ) ||
   diag("chdir failed: $!");
 
-sub extrachar { $] > 5.008 && !$ENV{PERL_CORE} ? utf8::decode(my $c='š') : 's' }
+sub extrachar {
+  return 's'
+    if 1; # until Perl gains native support for Unicode filenames
+#    if $] <= 5.008 || $ENV{PERL_CORE}
+#      || $^O =~ /bsd|dragonfly|mswin32/i;
+  'š';
+}
 my $DUMMYINST = '../dummy-in'.extrachar().'tall';
 my @mpl_out = run(qq{$perl Makefile.PL "PREFIX=$DUMMYINST"});
-END { rmtree $DUMMYINST; }
 
 cmp_ok( $?, '==', 0, 'Makefile.PL exited with zero' ) ||
   diag(@mpl_out);
@@ -96,8 +101,6 @@ ok( -e $makefile,       'Makefile exists' );
 my $mtime = (stat($makefile))[9];
 cmp_ok( $Touch_Time, '<=', $mtime,  '  been touched' );
 
-END { unlink makefile_name(), makefile_backup() }
-
 my $make = make_run();
 
 {
@@ -108,8 +111,6 @@ my $make = make_run();
     ok( -s 'MANIFEST',      '  not empty' );
 }
 
-END { unlink 'MANIFEST'; }
-
 my $ppd_out = run("$make ppd");
 is( $?, 0,                      '  exited normally' ) || diag $ppd_out;
 ok( open(PPD, 'Big-Dummy.ppd'), '  .ppd file generated' );
@@ -138,8 +139,6 @@ like( $ppd_html, qr{^\s*<ARCHITECTURE NAME="$archname" />}m,
 like( $ppd_html, qr{^\s*<CODEBASE HREF="" />}m,            '  <CODEBASE>');
 like( $ppd_html, qr{^\s*</IMPLEMENTATION>}m,           '  </IMPLEMENTATION>');
 like( $ppd_html, qr{^\s*</SOFTPKG>}m,                      '  </SOFTPKG>');
-END { unlink 'Big-Dummy.ppd' }
-
 
 my $test_out = run("$make test");
 like( $test_out, qr/All tests successful/, 'make test' );
@@ -150,10 +149,28 @@ is( $?, 0,                                 '  exited normally' ) ||
 my $make_test_verbose = make_macro($make, 'test', TEST_VERBOSE => 1);
 $test_out = run("$make_test_verbose");
 like( $test_out, qr/ok \d+ - TEST_VERBOSE/, 'TEST_VERBOSE' );
+like( $test_out, qr/ok \d+ - testing test.pl/, 'test.pl' ); # in test.pl
+like( $test_out, qr/ok \d+ - testing t\/\*.t/, 't/*.t' ); # in *.t
 like( $test_out, qr/All tests successful/,  '  successful' );
 is( $?, 0,                                  '  exited normally' ) ||
     diag $test_out;
 
+# Test 'make testdb TEST_FILE=t/compile.t'
+# TESTDB_SW override is because perl -d is too clever for me to outwit
+my $make_testdb_file = make_macro(
+    $make,
+    'testdb',
+    TEST_FILE => 't/compile.t',
+    TESTDB_SW => '-Ixyzzy',
+);
+$test_out = run($make_testdb_file);
+unlike( $test_out, qr/harness/, 'no harness' );
+unlike( $test_out, qr/sanity\.t/, 'no wrong test' );
+like( $test_out, qr/compile\.t/, 'get right test' );
+like( $test_out, qr/xyzzy/, 'signs of TESTDB_SW' );
+is( $?, 0,                                  '  exited normally' ) ||
+    diag $test_out;
+
 # now simulate what Module::Install does, and edit $(PERL) to add flags
 open my $fh, '<', $makefile;
 my $mtext = join '', <$fh>;
@@ -168,7 +185,7 @@ is( $?, 0, 'install' ) || diag $install_out;
 like( $install_out, qr/^Installing /m );
 
 sub check_dummy_inst {
-    my $loc = shift;
+    my ($loc, $skipsubdir) = @_;
     my %files = ();
     find( sub {
        # do it case-insensitive for non-case preserving OSs
@@ -178,7 +195,7 @@ sub check_dummy_inst {
        $files{$file} = $File::Find::name;
     }, $loc );
     ok( $files{'dummy.pm'},     '  Dummy.pm installed' );
-    ok( $files{'liar.pm'},      '  Liar.pm installed'  );
+    ok( $files{'liar.pm'},      '  Liar.pm installed'  ) unless $skipsubdir;
     ok( $files{'program'},      '  program installed'  );
     ok( $files{'.packlist'},    '  packlist created'   );
     ok( $files{'perllocal.pod'},'  perllocal.pod created' );
@@ -263,8 +280,9 @@ my $mymeta_yml = "$distdir/MYMETA.yml";
 my $meta_json = "$distdir/META.json";
 my $mymeta_json = "$distdir/MYMETA.json";
 
-note "META file validity"; {
-    require CPAN::Meta;
+note "META file validity"; SKIP: {
+    eval { require CPAN::Meta; };
+    skip 'Loading CPAN::Meta failed', 104 if $@;
 
     ok( !-f 'META.yml',  'META.yml not written to source dir' );
     ok( -f $meta_yml,    'META.yml written to dist dir' );
@@ -438,6 +456,27 @@ is( $?, 0, 'realclean' ) || diag($realclean_out);
 open(STDERR, ">&SAVERR") or die $!;
 close SAVERR;
 
+# test linkext=>{LINKTYPE=>''} still installs a pure-perl installation
+# warning, edits the Makefile.PL so either rewrite after this or do this last
+my $file = 'Makefile.PL';
+my $text = slurp $file;
+ok(($text =~ s#\);#    linkext=>{LINKTYPE=>''},\n$&#), 'successful M.PL edit');
+open $fh, '>', $file or die "$file: $!";
+print $fh $text;
+close $fh;
+# now do with "Liar" subdir still there
+rmtree $DUMMYINST; # so no false positive from before
+@mpl_out = run(qq{$perl Makefile.PL "PREFIX=$DUMMYINST"});
+$install_out = run("$make install");
+check_dummy_inst($DUMMYINST);
+# now clean, delete "Liar" subdir, do again
+$realclean_out = run("$make realclean");
+rmtree 'Liar';
+rmtree $DUMMYINST; # so no false positive from before
+@mpl_out = run(qq{$perl Makefile.PL "PREFIX=$DUMMYINST"});
+$install_out = run("$make install");
+check_dummy_inst($DUMMYINST, 1);
+
 sub _normalize {
     my $hash = shift;
 
index 47e5f4b..a88ccd2 100644 (file)
@@ -7,7 +7,7 @@ BEGIN {
 }
 
 use strict;
-use Test::More tests => 9;
+use Test::More tests => 10;
 
 use File::Spec;
 use File::Temp qw[tempdir];
@@ -22,31 +22,37 @@ use ExtUtils::MakeMaker::Config;
 # ensure these tests will still work.
 $Config{installman3dir} = 'none';
 
-my $tmpdir = tempdir( DIR => 't', CLEANUP => 1 );
-chdir $tmpdir;
+chdir 't';
+perl_lib; # sets $ENV{PERL5LIB} relative to t/
 
-perl_lib();
+my $tmpdir = tempdir( DIR => '../t', CLEANUP => 1 );
+use Cwd; my $cwd = getcwd; END { chdir $cwd } # so File::Temp can cleanup
+chdir $tmpdir;
 
 ok( setup_recurs(), 'setup' );
 END {
-    ok( chdir File::Spec->updir );
-    ok( teardown_recurs(), 'teardown' );
+    ok chdir File::Spec->updir, 'chdir updir';
+    ok teardown_recurs(), 'teardown';
 }
 
 ok( chdir 'Big-Dummy', "chdir'd to Big-Dummy" ) ||
   diag("chdir failed: $!");
+my $README = 'README.pod';
+{ open my $fh, '>', $README or die "$README: $!"; }
 
-ok( my $stdout = tie *STDOUT, 'TieOut' );
+ok((my $stdout = tie *STDOUT, 'TieOut'), 'tie stdout');
 
 {
     local $Config{installman3dir} = File::Spec->catdir(qw(t lib));
-
     my $mm = WriteMakefile(
         NAME            => 'Big::Dummy',
         VERSION_FROM    => 'lib/Big/Dummy.pm',
     );
-
-    ok( keys %{ $mm->{MAN3PODS} } );
+    my %got = %{ $mm->{MAN3PODS} };
+    # because value too OS-specific
+    my $delete_key = $^O eq 'VMS' ? '[.lib.Big]Dummy.pm' : 'lib/Big/Dummy.pm';
+    ok delete($got{$delete_key}), 'normal man3pod';
+    is_deeply \%got, {}, 'no extra man3pod';
 }
 
 {
@@ -55,28 +61,23 @@ ok( my $stdout = tie *STDOUT, 'TieOut' );
         VERSION_FROM    => 'lib/Big/Dummy.pm',
         INSTALLMAN3DIR  => 'none'
     );
-
-    is_deeply( $mm->{MAN3PODS}, {} );
+    is_deeply $mm->{MAN3PODS}, {}, 'suppress man3pod with "none"';
 }
 
-
 {
     my $mm = WriteMakefile(
         NAME            => 'Big::Dummy',
         VERSION_FROM    => 'lib/Big/Dummy.pm',
         MAN3PODS        => {}
     );
-
-    is_deeply( $mm->{MAN3PODS}, { } );
+    is_deeply $mm->{MAN3PODS}, {}, 'suppress man3pod with {}';
 }
 
-
 {
     my $mm = WriteMakefile(
         NAME            => 'Big::Dummy',
         VERSION_FROM    => 'lib/Big/Dummy.pm',
         MAN3PODS        => { "Foo.pm" => "Foo.1" }
     );
-
-    is_deeply( $mm->{MAN3PODS}, { "Foo.pm" => "Foo.1" } );
+    is_deeply $mm->{MAN3PODS}, { "Foo.pm" => "Foo.1" }, 'override man3pod';
 }
index 67dfd98..57da1df 100644 (file)
@@ -6,6 +6,7 @@ BEGIN {
 
 use File::Temp qw[tempdir];
 my $tmpdir = tempdir( DIR => 't', CLEANUP => 1 );
+use Cwd; my $cwd = getcwd; END { chdir $cwd } # so File::Temp can cleanup
 chdir $tmpdir;
 
 my $Is_VMS = $^O eq 'VMS';
index 5cb8e49..95dce69 100644 (file)
@@ -4,6 +4,7 @@ use lib 't/lib';
 
 use File::Temp qw[tempdir];
 my $tmpdir = tempdir( DIR => 't', CLEANUP => 1 );
+use Cwd; my $cwd = getcwd; END { chdir $cwd } # so File::Temp can cleanup
 chdir $tmpdir;
 
 use Test::More tests => 1;
index 6d424d1..872c2b1 100644 (file)
@@ -14,11 +14,11 @@ use MakeMaker::Test::Utils;
 use File::Temp;
 use Cwd 'abs_path';
 
-use Test::More;
 use ExtUtils::MM;
-plan !MM->can_run(make()) && $ENV{PERL_CORE} && $Config{'usecrosscompile'}
+use Test::More
+    !MM->can_run(make()) && $ENV{PERL_CORE} && $Config{'usecrosscompile'}
     ? (skip_all => "cross-compiling and make not available")
-    : ();
+    : (tests => 18);
 
 #--------------------- Setup
 
@@ -117,5 +117,3 @@ test_for_echo(
     "Foo\nBar\nBaz\n",
     "append"
 );
-
-done_testing;
index 72c86ef..061e456 100644 (file)
@@ -7,10 +7,6 @@ BEGIN {
     unshift @INC, 't/lib/';
 }
 
-use File::Temp qw[tempdir];
-my $tmpdir = tempdir( DIR => 't', CLEANUP => 1 );
-chdir $tmpdir;
-
 use File::Spec;
 
 use Test::More tests => 22;
@@ -23,8 +19,12 @@ use MakeMaker::Test::Setup::BFD;
 use ExtUtils::MakeMaker;
 
 chdir 't';
+perl_lib; # sets $ENV{PERL5LIB} relative to t/
 
-perl_lib();
+use File::Temp qw[tempdir];
+my $tmpdir = tempdir( DIR => '../t', CLEANUP => 1 );
+use Cwd; my $cwd = getcwd; END { chdir $cwd } # so File::Temp can cleanup
+chdir $tmpdir;
 
 ok( setup_recurs(), 'setup' );
 END {
index af4d183..6b3cf73 100644 (file)
@@ -7,6 +7,7 @@ use lib 't/lib';
 
 use File::Temp qw[tempdir];
 my $tmpdir = tempdir( DIR => 't', CLEANUP => 1 );
+use Cwd; my $cwd = getcwd; END { chdir $cwd } # so File::Temp can cleanup
 chdir $tmpdir;
 use File::Spec;
 
@@ -41,7 +42,7 @@ CLOO
 
     $mm->check_hints;
     is( $mm->{CCFLAGS}, 'basset hounds got long ears' );
-    is( $stderr, "Processing hints file $Hint_File\n" );
+    is( $stderr, "" );
 }
 
 
@@ -61,7 +62,6 @@ CLOO
 
     $mm->check_hints;
     is( $stderr, <<OUT, 'hint files produce errors' );
-Processing hints file $Hint_File
 Argh!
 OUT
 }
index 58516bc..9ac9bb6 100644 (file)
@@ -12,7 +12,7 @@ use less;
 
 use lib './lib';
 use ExtUtils::MakeMaker;
-use Test::More;
+use Test::More tests => 4;
 use File::Spec;
 
 
@@ -43,6 +43,3 @@ sub path_is {
     my $want = $INC{"Test/More.pm"};
     path_is( MM->_installed_file_for_module("Test::More"), $want, "Foo::Bar style" );
 }
-
-
-done_testing(4);
index e5af93c..3d093fc 100644 (file)
@@ -55,16 +55,20 @@ program - this is a program
 1;
 END
 
-             'Big-Dummy/t/compile.t'          => <<'END',
-print "1..2\n";
+             'Big-Dummy/test.pl'          => <<'END',
+print "1..1\n";
+print "ok 1 - testing test.pl\n";
+END
 
+             'Big-Dummy/t/compile.t'          => <<'END',
+print "1..3\n";
 print eval "use Big::Dummy; 1;" ? "ok 1\n" : "not ok 1\n";
 print "ok 2 - TEST_VERBOSE\n";
+print "ok 3 - testing t/*.t\n";
 END
 
              'Big-Dummy/Liar/t/sanity.t'      => <<'END',
 print "1..3\n";
-
 print eval "use Big::Dummy; 1;" ? "ok 1\n" : "not ok 1\n";
 print eval "use Big::Liar; 1;" ? "ok 2\n" : "not ok 2\n";
 print "ok 3 - TEST_VERBOSE\n";
@@ -96,11 +100,13 @@ END
             );
 
 
+# if given args, those are inserted as components in resulting path, eg:
+# setup_recurs('dir') means instead of creating Big-Dummy/*, dir/Big-Dummy/*
 sub setup_recurs {
-
     while(my($file, $text) = each %Files) {
         # Convert to a relative, native file path.
-        $file = File::Spec->catfile(File::Spec->curdir, split m{\/}, $file);
+        $file = File::Spec->catfile(File::Spec->curdir, @_, split m{\/}, $file);
+        $file = File::Spec->rel2abs($file);
 
         my $dir = dirname($file);
         mkpath $dir;
diff --git a/cpan/ExtUtils-MakeMaker/t/lib/MakeMaker/Test/Setup/MPV.pm b/cpan/ExtUtils-MakeMaker/t/lib/MakeMaker/Test/Setup/MPV.pm
deleted file mode 100644 (file)
index f30d65f..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-package MakeMaker::Test::Setup::MPV;
-
-@ISA = qw(Exporter);
-require Exporter;
-@EXPORT = qw(setup_recurs teardown_recurs);
-
-use strict;
-use File::Path;
-use File::Basename;
-
-my %Files = (
-             'Min-PerlVers/Makefile.PL'   => <<'END',
-use ExtUtils::MakeMaker;
-
-WriteMakefile(
-    NAME             => 'Min::PerlVers',
-    AUTHOR           => 'John Doe <jd@example.com>',
-    VERSION_FROM     => 'lib/Min/PerlVers.pm',
-    PREREQ_PM        => { strict => 0 },
-    MIN_PERL_VERSION => '5.005',
-);
-END
-
-             'Min-PerlVers/lib/Min/PerlVers.pm'    => <<'END',
-package Min::PerlVers;
-
-$VERSION = 0.05;
-
-=head1 NAME
-
-Min::PerlVers - being picky about perl versions
-
-=cut
-
-1;
-END
-
-);
-
-
-sub setup_recurs {
-    while(my($file, $text) = each %Files) {
-        # Convert to a relative, native file path.
-        $file = File::Spec->catfile(File::Spec->curdir, split m{\/}, $file);
-
-        my $dir = dirname($file);
-        mkpath $dir;
-        open(FILE, ">$file") || die "Can't create $file: $!";
-        print FILE $text;
-        close FILE;
-    }
-
-    return 1;
-}
-
-sub teardown_recurs {
-    foreach my $file (keys %Files) {
-        my $dir = dirname($file);
-        if( -e $dir ) {
-            rmtree($dir) || return;
-        }
-    }
-    return 1;
-}
-
-
-1;
diff --git a/cpan/ExtUtils-MakeMaker/t/lib/MakeMaker/Test/Setup/PL_FILES.pm b/cpan/ExtUtils-MakeMaker/t/lib/MakeMaker/Test/Setup/PL_FILES.pm
deleted file mode 100644 (file)
index f412368..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-package MakeMaker::Test::Setup::PL_FILES;
-
-@ISA = qw(Exporter);
-require Exporter;
-@EXPORT = qw(setup teardown);
-
-use strict;
-use File::Path;
-use File::Basename;
-use File::Spec;
-use MakeMaker::Test::Utils;
-
-my %Files = (
-             'PL_FILES-Module/Makefile.PL'   => <<'END',
-use ExtUtils::MakeMaker;
-
-# A module for testing PL_FILES
-WriteMakefile(
-    NAME     => 'PL_FILES::Module',
-    PL_FILES => { 'single.PL' => 'single.out',
-                  'multi.PL'  => [qw(1.out 2.out)],
-                  'Bar_pm.PL' => '$(INST_LIB)/PL/Bar.pm',
-    }
-);
-END
-
-            'PL_FILES-Module/single.PL'        => _gen_pl_files(),
-            'PL_FILES-Module/multi.PL'         => _gen_pl_files(),
-            'PL_FILES-Module/Bar_pm.PL'        => _gen_pm_files(),
-            'PL_FILES-Module/lib/PL/Foo.pm' => <<'END',
-# Module to load to ensure PL_FILES have blib in @INC.
-package PL::Foo;
-sub bar { 42 }
-1;
-END
-
-);
-
-
-sub _gen_pl_files {
-    my $test = <<'END';
-#!/usr/bin/perl -w
-
-# Ensure we have blib in @INC
-use PL::Foo;
-die unless PL::Foo::bar() == 42;
-
-# Had a bug where PL_FILES weren't sent the file to generate
-die "argv empty\n" unless @ARGV;
-die "too many in argv: @ARGV\n" unless @ARGV == 1;
-
-my $file = $ARGV[0];
-open OUT, ">$file" or die $!;
-
-print OUT "Testing\n";
-close OUT
-END
-
-    $test =~ s/^\n//;
-
-    return $test;
-}
-
-
-sub _gen_pm_files {
-    my $test = <<'END';
-#!/usr/bin/perl -w
-
-# Ensure we do NOT have blib in @INC when building a module
-eval { require PL::Foo; };
-#die $@ unless $@ =~ m{^Can't locate PL/Foo.pm in \@INC };
-
-# Had a bug where PL_FILES weren't sent the file to generate
-die "argv empty\n" unless @ARGV;
-die "too many in argv: @ARGV\n" unless @ARGV == 1;
-
-my $file = $ARGV[0];
-open OUT, ">$file" or die $!;
-
-print OUT "Testing\n";
-close OUT
-END
-
-    $test =~ s/^\n//;
-
-    return $test;
-}
-
-
-sub setup {
-
-    while(my($file, $text) = each %Files) {
-        # Convert to a relative, native file path.
-        $file = File::Spec->catfile(File::Spec->curdir, split m{\/}, $file);
-
-        my $dir = dirname($file);
-        mkpath $dir;
-        open(FILE, ">$file") || die "Can't create $file: $!";
-        print FILE $text;
-        close FILE;
-
-        # ensure file at least 1 second old for makes that assume
-        # files with the same time are out of date.
-        my $time = calibrate_mtime();
-        utime $time, $time - 1, $file;
-    }
-
-    return 1;
-}
-
-sub teardown {
-    foreach my $file (keys %Files) {
-        my $dir = dirname($file);
-        if( -e $dir ) {
-            rmtree($dir) || return;
-        }
-    }
-    return 1;
-}
diff --git a/cpan/ExtUtils-MakeMaker/t/lib/MakeMaker/Test/Setup/Problem.pm b/cpan/ExtUtils-MakeMaker/t/lib/MakeMaker/Test/Setup/Problem.pm
deleted file mode 100644 (file)
index 59ac151..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-package MakeMaker::Test::Setup::Problem;
-
-@ISA = qw(Exporter);
-require Exporter;
-@EXPORT = qw(setup_recurs teardown_recurs);
-
-use strict;
-use File::Path;
-use File::Basename;
-use MakeMaker::Test::Utils;
-
-my %Files = (
-             'Problem-Module/Makefile.PL'   => <<'END',
-use ExtUtils::MakeMaker;
-
-WriteMakefile(
-    NAME    => 'Problem::Module',
-);
-END
-
-             'Problem-Module/subdir/Makefile.PL'    => <<'END',
-printf "\@INC %s .\n", (grep { $_ eq '.' } @INC) ? "has" : "doesn't have";
-
-warn "I think I'm going to be sick\n";
-die "YYYAaaaakkk\n";
-END
-
-);
-
-
-sub setup_recurs {
-    while(my($file, $text) = each %Files) {
-        # Convert to a relative, native file path.
-        $file = File::Spec->catfile(File::Spec->curdir, split m{\/}, $file);
-
-        my $dir = dirname($file);
-        mkpath $dir;
-        open(FILE, ">$file") || die "Can't create $file: $!";
-        print FILE $text;
-        close FILE;
-
-        # ensure file at least 1 second old for makes that assume
-        # files with the same time are out of date.
-        my $time = calibrate_mtime();
-        utime $time, $time - 1, $file;
-    }
-
-    return 1;
-}
-
-sub teardown_recurs {
-    foreach my $file (keys %Files) {
-        my $dir = dirname($file);
-        if( -e $dir ) {
-            rmtree($dir) || return;
-        }
-    }
-    return 1;
-}
-
-
-1;
diff --git a/cpan/ExtUtils-MakeMaker/t/lib/MakeMaker/Test/Setup/Recurs.pm b/cpan/ExtUtils-MakeMaker/t/lib/MakeMaker/Test/Setup/Recurs.pm
deleted file mode 100644 (file)
index 8694321..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-package MakeMaker::Test::Setup::Recurs;
-
-@ISA = qw(Exporter);
-require Exporter;
-@EXPORT = qw(setup_recurs teardown_recurs);
-
-use strict;
-use File::Path;
-use File::Basename;
-use MakeMaker::Test::Utils;
-
-my %Files = (
-             'Recurs/Makefile.PL'          => <<'END',
-use ExtUtils::MakeMaker;
-
-WriteMakefile(
-    NAME          => 'Recurs',
-    VERSION       => 1.00,
-);
-END
-
-             'Recurs/prj2/Makefile.PL'     => <<'END',
-use ExtUtils::MakeMaker;
-
-WriteMakefile(
-    NAME => 'Recurs::prj2',
-    VERSION => 1.00,
-);
-END
-
-             # Check if a test failure in a subdir causes make test to fail
-             'Recurs/prj2/t/fail.t'         => <<'END',
-#!/usr/bin/perl -w
-
-print "1..1\n";
-print "not ok 1\n";
-END
-            );
-
-sub setup_recurs {
-
-    while(my($file, $text) = each %Files) {
-        # Convert to a relative, native file path.
-        $file = File::Spec->catfile(File::Spec->curdir, split m{\/}, $file);
-
-        my $dir = dirname($file);
-        mkpath $dir;
-        open(FILE, ">$file") || die "Can't create $file: $!";
-        print FILE $text;
-        close FILE;
-
-        # ensure file at least 1 second old for makes that assume
-        # files with the same time are out of date.
-        my $time = calibrate_mtime();
-        utime $time, $time - 1, $file;
-    }
-
-    return 1;
-}
-
-sub teardown_recurs {
-    foreach my $file (keys %Files) {
-        my $dir = dirname($file);
-        if( -e $dir ) {
-            rmtree($dir) || return;
-        }
-    }
-    return 1;
-}
-
-
-1;
diff --git a/cpan/ExtUtils-MakeMaker/t/lib/MakeMaker/Test/Setup/SAS.pm b/cpan/ExtUtils-MakeMaker/t/lib/MakeMaker/Test/Setup/SAS.pm
deleted file mode 100644 (file)
index 04d9bd3..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-package MakeMaker::Test::Setup::SAS;
-
-@ISA = qw(Exporter);
-require Exporter;
-@EXPORT = qw(setup_recurs teardown_recurs);
-
-use strict;
-use File::Path;
-use File::Basename;
-
-our $dirname='Multiple-Authors';
-my %Files = (
-             $dirname.'/Makefile.PL'   => <<'END',
-use ExtUtils::MakeMaker;
-
-WriteMakefile(
-    NAME             => 'Multiple::Authors',
-    AUTHOR           => ['John Doe <jd@example.com>', 'Jane Doe <jd@example.com>'],
-    VERSION_FROM     => 'lib/Multiple/Authors.pm',
-    PREREQ_PM        => { strict => 0 },
-);
-END
-
-             $dirname.'/lib/Multiple/Authors.pm'    => <<'END',
-package Multiple::Authors;
-
-$VERSION = 0.05;
-
-=head1 NAME
-
-Multiple::Authors - several authors
-
-=cut
-
-1;
-END
-
-);
-
-
-sub setup_recurs {
-    while(my($file, $text) = each %Files) {
-        # Convert to a relative, native file path.
-        $file = File::Spec->catfile(File::Spec->curdir, split m{\/}, $file);
-
-        my $dir = dirname($file);
-        mkpath $dir;
-        open(FILE, ">$file") || die "Can't create $file: $!";
-        print FILE $text;
-        close FILE;
-    }
-
-    return 1;
-}
-
-sub teardown_recurs {
-    foreach my $file (keys %Files) {
-        my $dir = dirname($file);
-        if( -e $dir ) {
-            rmtree($dir) || return;
-        }
-    }
-    return 1;
-}
-
-
-1;
diff --git a/cpan/ExtUtils-MakeMaker/t/lib/MakeMaker/Test/Setup/Unicode.pm b/cpan/ExtUtils-MakeMaker/t/lib/MakeMaker/Test/Setup/Unicode.pm
deleted file mode 100644 (file)
index 76641f0..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-package MakeMaker::Test::Setup::Unicode;
-
-@ISA = qw(Exporter);
-require Exporter;
-@EXPORT = qw(setup_recurs teardown_recurs);
-
-use strict;
-use File::Path;
-use File::Basename;
-use MakeMaker::Test::Utils;
-use utf8;
-use Config;
-
-my %Files = (
-             'Problem-Module/Makefile.PL'   => <<'PL_END',
-use ExtUtils::MakeMaker;
-use utf8;
-
-WriteMakefile(
-    NAME          => 'Problem::Module',
-    ABSTRACT_FROM => 'lib/Problem/Module.pm',
-    AUTHOR        => q{Danijel Tašov},
-    EXE_FILES     => [ qw(bin/probscript) ],
-    INSTALLMAN1DIR => "some", # even if disabled in $Config{man1dir}
-    MAN1EXT       => 1, # set to 0 if man pages disabled
-);
-PL_END
-
-            'Problem-Module/lib/Problem/Module.pm'  => <<'pm_END',
-use utf8;
-
-=pod
-
-=encoding utf8
-
-=head1 NAME
-
-Problem::Module - Danijel Tašov's great new module
-
-=cut
-
-1;
-pm_END
-
-            'Problem-Module/bin/probscript'  => <<'pl_END',
-#!/usr/bin/perl
-use utf8;
-
-=encoding utf8
-
-=head1 NAME
-
-文档 - Problem script
-pl_END
-);
-
-
-sub setup_recurs {
-    while(my($file, $text) = each %Files) {
-        # Convert to a relative, native file path.
-        $file = File::Spec->catfile(File::Spec->curdir, split m{\/}, $file);
-
-        my $dir = dirname($file);
-        mkpath $dir;
-        my $utf8 = ($] < 5.008 or !$Config{useperlio}) ? "" : ":utf8";
-        open(FILE, ">$utf8", $file) || die "Can't create $file: $!";
-        print FILE $text;
-        close FILE;
-
-        # ensure file at least 1 second old for makes that assume
-        # files with the same time are out of date.
-        my $time = calibrate_mtime();
-        utime $time, $time - 1, $file;
-    }
-
-    return 1;
-}
-
-sub teardown_recurs {
-    foreach my $file (keys %Files) {
-        my $dir = dirname($file);
-        if( -e $dir ) {
-            rmtree($dir) || return;
-        }
-    }
-    return 1;
-}
-
-
-1;
index 6ebca59..2c3ac61 100644 (file)
@@ -2,101 +2,396 @@ package MakeMaker::Test::Setup::XS;
 
 @ISA = qw(Exporter);
 require Exporter;
-@EXPORT = qw(setup_xs teardown_xs);
+@EXPORT = qw(run_tests list_dynamic list_static);
 
 use strict;
 use File::Path;
-use File::Basename;
 use MakeMaker::Test::Utils;
 use Config;
+use Carp qw(croak);
+use Test::More;
+use File::Spec;
 
+use File::Temp qw[tempdir];
+use Cwd;
 use ExtUtils::MM;
+# this is to avoid MM->new overwriting _eumm in top dir
+my $tempdir = tempdir(DIR => getcwd, CLEANUP => 1);
+chdir $tempdir;
 my $typemap = 'type map';
-$typemap =~ s/ //g unless MM->new({NAME=>'name'})->can_dep_space;
+$typemap =~ s/ //g unless MM->new({NAME=>'name', NORECURS=>1})->can_dep_space;
+chdir File::Spec->updir;
 
-my %Files = (
-             'XS-Test/lib/XS/Test.pm'     => <<'END',
+my $PM_TEST = <<'END';
 package XS::Test;
-
 require Exporter;
 require DynaLoader;
-
 $VERSION = 1.01;
 @ISA    = qw(Exporter DynaLoader);
 @EXPORT = qw(is_even);
-
 bootstrap XS::Test $VERSION;
-
 1;
 END
 
-             'XS-Test/Makefile.PL'          => <<END,
-use ExtUtils::MakeMaker;
+my $XS_TEST = <<'END';
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+MODULE = XS::Test       PACKAGE = XS::Test
+PROTOTYPES: DISABLE
+int
+is_even(input)
+       int     input
+   CODE:
+       RETVAL = (input % 2 == 0);
+   OUTPUT:
+       RETVAL
+END
 
+my $T_TEST = <<'END';
+#!/usr/bin/perl -w
+use Test::More tests => 3;
+use_ok "XS::Test";
+ok !is_even(1);
+ok is_even(2);
+END
+
+my $MAKEFILEPL = <<'END';
+use ExtUtils::MakeMaker;
 WriteMakefile(
-    NAME          => 'XS::Test',
-    VERSION_FROM  => 'lib/XS/Test.pm',
-    TYPEMAPS      => [ '$typemap' ],
-    PERL          => "\$^X -w",
+  NAME          => 'XS::%s',
+  VERSION_FROM  => '%s',
+  TYPEMAPS      => [ %s ],
+  PERL          => "$^X -w",
+  %s
 );
 END
 
-             "XS-Test/$typemap"             => '',
+my $BS_TEST = '$DynaLoader::bscode = q(warn "BIG NOISE";)';
+
+my $T_BOOTSTRAP = <<'EOF';
+use Test::More tests => 1;
+my $w = '';
+$SIG{__WARN__} = sub { $w .= join '', @_; };
+require XS::Test;
+like $w, qr/NOISE/;
+EOF
+
+my $PM_OTHER = <<'END';
+package XS::Other;
+require Exporter;
+require DynaLoader;
+$VERSION = 1.20;
+@ISA    = qw(Exporter DynaLoader);
+@EXPORT = qw(is_odd);
+bootstrap XS::Other $VERSION;
+1;
+END
 
-             'XS-Test/Test.xs'              => <<'END',
+my $XS_OTHER = <<'END';
 #include "EXTERN.h"
 #include "perl.h"
 #include "XSUB.h"
-
-MODULE = XS::Test       PACKAGE = XS::Test
-
+MODULE = XS::Other       PACKAGE = XS::Other
 PROTOTYPES: DISABLE
-
 int
-is_even(input)
+is_odd(input)
        int     input
    CODE:
-       RETVAL = (input % 2 == 0);
+       RETVAL = (INVAR % 2 == 1);
    OUTPUT:
        RETVAL
 END
 
-             'XS-Test/t/is_even.t'          => <<'END',
+my $T_OTHER = <<'END';
 #!/usr/bin/perl -w
-
 use Test::More tests => 3;
+use_ok "XS::Other";
+ok is_odd(1);
+ok !is_odd(2);
+END
 
-use_ok "XS::Test";
-ok !is_even(1);
-ok is_even(2);
+my $PLUS1_C = <<'EOF';
+#ifdef __cplusplus
+extern "C" {
+int plus1(int i)
+#else
+int plus1(i)
+int i;
+#endif
+{ return i + 1; }
+#ifdef __cplusplus
+}
+#endif
+EOF
+
+my %Files = (
+  'lib/XS/Test.pm' => $PM_TEST,
+  $typemap => '',
+  'Test.xs' => $XS_TEST,
+  't/is_even.t' => $T_TEST,
+  'Makefile.PL' => sprintf($MAKEFILEPL, 'Test', 'lib/XS/Test.pm', qq{'$typemap'}, ''),
+);
+
+my %label2files = (basic => \%Files);
+
+$label2files{bscode} = +{
+  %{ $label2files{'basic'} }, # make copy
+  'Test_BS' => $BS_TEST,
+  't/bs.t' => $T_BOOTSTRAP,
+};
+delete $label2files{bscode}->{'t/is_even.t'};
+
+$label2files{static} = +{
+  %{ $label2files{'basic'} }, # make copy
+  'Makefile.PL' => sprintf(
+    $MAKEFILEPL, 'Test', 'lib/XS/Test.pm', qq{'$typemap'},
+    q{LINKTYPE => 'static'},
+  ),
+};
+
+$label2files{subdirs} = +{
+  %{ $label2files{'basic'} }, # make copy
+  'Makefile.PL' => sprintf(
+    $MAKEFILEPL, 'Test', 'Test.pm', qq{'$typemap'},
+    q{DEFINE => '-DINVAR=input', INC => "-Inewline\n", LIBS => "-Lnewline\n",},
+  ),
+  'Other/Makefile.PL' => sprintf($MAKEFILEPL, 'Other', 'Other.pm', qq{}, ''),
+  'Other/Other.pm' => $PM_OTHER,
+  'Other/Other.xs' => $XS_OTHER,
+  't/is_odd.t' => $T_OTHER,
+};
+virtual_rename('subdirs', 'lib/XS/Test.pm', 'Test.pm');
+
+# to mimic behaviour of Unicode-LineBreak version 2015.07.16
+$label2files{subdirscomplex} = +{
+  %{ $label2files{'subdirs'} }, # make copy
+  'Other/Makefile.PL' => sprintf(
+    $MAKEFILEPL,
+    'Other', 'Other.pm', qq{},
+    <<'EOF',
+C => [qw(lib$(DIRFILESEP)file.c)],
+OBJECT => 'lib$(DIRFILESEP)file$(OBJ_EXT)',
+EOF
+  ) . <<'EOF',
+sub MY::c_o {
+  package MY;
+  my $self = shift;
+  my $inherited = $self->SUPER::c_o(@_);
+  $inherited =~ s{(:\n\t)(.*(?:\n\t.*)*)}
+      { $1 . $self->cd('lib', split /(?<!\\)\n\t/, $2) }eg;
+  $inherited =~ s{(\s)(\$\*\.c\s)}
+      { "$1..\$(DIRFILESEP)$2" }eg;
+  $inherited;
+}
+
+sub MY::top_targets {
+  <<'SNIP';
+all :: lib$(DIRFILESEP)file$(OBJ_EXT)
+       $(NOECHO) $(NOOP)
+
+config ::
+       $(NOECHO) $(NOOP)
+
+pure_all ::
+       $(NOECHO) $(NOOP)
+SNIP
+}
+EOF
+  'Other/lib/file.c' => $PLUS1_C,
+};
+delete $label2files{subdirscomplex}{'Other/Other.xs'};
+delete $label2files{subdirscomplex}{'t/is_odd.t'};
+
+$label2files{subdirsstatic} = +{
+  %{ $label2files{'subdirs'} }, # make copy
+  'Makefile.PL' => sprintf(
+    $MAKEFILEPL, 'Test', 'Test.pm', qq{'$typemap'},
+    q{DEFINE => '-DINVAR=input', LINKTYPE => 'static',},
+  ),
+};
+
+my $XS_MULTI = $XS_OTHER;
+# check compiling from top dir still can include local
+$XS_MULTI =~ s:(#include "XSUB.h"):$1\n#include "header.h":;
+$label2files{multi} = +{
+  %{ $label2files{'basic'} }, # make copy
+  'Makefile.PL' => sprintf(
+    $MAKEFILEPL, 'Test', 'lib/XS/Test.pm', qq{'lib/XS/$typemap'},
+    q{XSMULTI => 1,},
+  ),
+  'lib/XS/Other.pm' => $PM_OTHER,
+  'lib/XS/Other.xs' => $XS_MULTI,
+  't/is_odd.t' => $T_OTHER,
+  'lib/XS/header.h' => "#define INVAR input\n",
+};
+virtual_rename('multi', $typemap, "lib/XS/$typemap");
+virtual_rename('multi', 'Test.xs', 'lib/XS/Test.xs');
+
+$label2files{bscodemulti} = +{
+  %{ $label2files{'multi'} }, # make copy
+  'lib/XS/Test_BS' => $BS_TEST,
+  't/bs.t' => $T_BOOTSTRAP,
+};
+delete $label2files{bscodemulti}->{'t/is_even.t'};
+delete $label2files{bscodemulti}->{'t/is_odd.t'};
+
+$label2files{staticmulti} = +{
+  %{ $label2files{'multi'} }, # make copy
+  'Makefile.PL' => sprintf(
+    $MAKEFILEPL, 'Test', 'lib/XS/Test.pm', qq{'$typemap'},
+    q{LINKTYPE => 'static', XSMULTI => 1,},
+  ),
+};
+
+$label2files{xsbuild} = +{
+  %{ $label2files{'multi'} }, # make copy
+  'Makefile.PL' => sprintf(
+    $MAKEFILEPL, 'Test', 'lib/XS/Test.pm', qq{'$typemap'},
+    q{
+      XSMULTI => 1,
+      XSBUILD => {
+        xs => {
+          'lib/XS/Other' => {
+            DEFINE => '-DINVAR=input',
+            OBJECT => 'lib/XS/Other$(OBJ_EXT) lib/XS/plus1$(OBJ_EXT)'
+          }
+        },
+      },
+    },
+  ),
+
+  'lib/XS/Other.xs' => <<EOF,
+#ifdef __cplusplus
+extern "C" {
+#endif
+int plus1(int);
+#ifdef __cplusplus
+}
+#endif
+$XS_OTHER
+int
+plus1(input)
+       int     input
+   CODE:
+       RETVAL = plus1(INVAR);
+   OUTPUT:
+       RETVAL
+EOF
+
+  'lib/XS/plus1.c' => $PLUS1_C,
+
+  't/is_odd.t' => <<'END',
+#!/usr/bin/perl -w
+use Test::More tests => 4;
+use_ok "XS::Other";
+ok is_odd(1);
+ok !is_odd(2);
+is XS::Other::plus1(3), 4;
 END
-            );
 
+};
+
+sub virtual_rename {
+  my ($label, $oldfile, $newfile) = @_;
+  $label2files{$label}->{$newfile} = delete $label2files{$label}->{$oldfile};
+}
 
 sub setup_xs {
+  my ($label, $sublabel) = @_;
+  croak "Must supply label" unless defined $label;
+  my $files = $label2files{$label};
+  croak "Must supply valid label" unless defined $files;
+  croak "Must supply sublabel" unless defined $sublabel;
+  my $prefix = "XS-Test$label$sublabel";
+  hash2files($prefix, $files);
+  return $prefix;
+}
+
+sub list_static {
+  (
+    ( !$Config{usedl} ? [ 'basic', '', '' ] : ()), # still needs testing on static perl
+    [ 'static', '', '' ],
+    [ 'basic', ' static', '_static' ],
+    [ 'multi', ' static', '_static' ],
+    [ 'subdirs', ' LINKTYPE=static', ' LINKTYPE=static' ],
+    [ 'subdirsstatic', '', '' ],
+    [ 'staticmulti', '', '' ],
+  );
+}
+
+sub list_dynamic {
+  (
+    [ 'basic', '', '' ],
+    $^O ne 'MSWin32' ? (
+        [ 'bscode', '', '' ],
+        [ 'bscodemulti', '', '' ],
+        [ 'subdirscomplex', '', '' ],
+    ) : (), # DynaLoader different
+    [ 'subdirs', '', '' ],
+    [ 'subdirsstatic', ' LINKTYPE=dynamic', ' LINKTYPE=dynamic' ],
+    [ 'subdirsstatic', ' dynamic', '_dynamic' ],
+    [ 'multi', '', '' ],
+    [ 'staticmulti', ' LINKTYPE=dynamic', ' LINKTYPE=dynamic' ],
+    [ 'staticmulti', ' dynamic', '_dynamic' ],
+    [ 'xsbuild', '', '' ],
+  );
+}
 
-    while(my($file, $text) = each %Files) {
-        # Convert to a relative, native file path.
-        $file = File::Spec->catfile(File::Spec->curdir, split m{\/}, $file);
+sub run_tests {
+  my ($perl, $label, $add_target, $add_testtarget) = @_;
+  my $sublabel = $add_target;
+  $sublabel =~ s#[\s=]##g;
+  ok( my $dir = setup_xs($label, $sublabel), "setup $label$sublabel" );
 
-        my $dir = dirname($file);
-        mkpath $dir;
-        open(FILE, ">$file") || die "Can't create $file: $!";
-        print FILE $text;
-        close FILE;
+  ok( chdir($dir), "chdir'd to $dir" ) || diag("chdir failed: $!");
+
+  my @mpl_out = run(qq{$perl Makefile.PL});
+  SKIP: {
+    unless (cmp_ok( $?, '==', 0, 'Makefile.PL exited with zero' )) {
+      diag(@mpl_out);
+      skip 'perl Makefile.PL failed', 2;
     }
 
-    return 1;
-}
+    my $make = make_run();
+    my $target = '';
+    my %macros = ();
+    if (defined($add_target)) {
+        if ($add_target =~ m/(\S+)=(\S+)/) {
+            $macros{$1} = $2;
+        }
+        else {
+            $target = $add_target;
+        }
+    }
+    my $make_cmd = make_macro($make, $target, %macros);
+    my $make_out = run($make_cmd);
+    unless (is( $?, 0, "$make_cmd exited normally" )) {
+        diag $make_out;
+        skip 'Make failed - skipping test', 1;
+    }
 
-sub teardown_xs {
-    foreach my $file (keys %Files) {
-        my $dir = dirname($file);
-        if( -e $dir ) {
-            rmtree($dir) || return;
+    $target = 'test';
+    %macros = ();
+    if (defined($add_testtarget) && length($add_testtarget)) {
+        if ($add_testtarget =~ m/(\S+)=(\S+)/) {
+            $macros{$1} = $2;
+        }
+        else {
+            # an underscore prefix means combine, e.g. 'test' + '_dynamic'
+            unless ($add_testtarget =~ m/^_/) {
+                $target .= ($make =~ m/^MM(K|S)/i) ? ',' : ' ';
+            }
+            $target .= $add_testtarget;
         }
     }
-    return 1;
+    my $test_cmd = make_macro($make, $target, %macros);
+    my $test_out = run($test_cmd);
+    is( $?, 0, "$test_cmd exited normally" ) || diag "$make_out\n$test_out";
+  }
+
+  chdir File::Spec->updir or die;
+  ok rmtree($dir), "teardown $dir";
 }
 
 1;
index 16d6688..ce73b30 100644 (file)
@@ -3,6 +3,10 @@ package MakeMaker::Test::Utils;
 use File::Spec;
 use strict;
 use Config;
+use Cwd qw(getcwd);
+use Carp qw(croak);
+use File::Path;
+use File::Basename;
 
 require Exporter;
 our @ISA = qw(Exporter);
@@ -16,6 +20,8 @@ our @EXPORT = qw(which_perl perl_lib makefile_name makefile_backup
                  have_compiler slurp
                  $Is_VMS $Is_MacOS
                  run_ok
+                 hash2files
+                 in_dir
                 );
 
 
@@ -155,6 +161,9 @@ Sets up environment variables so perl can find its libraries.
 my $old5lib = $ENV{PERL5LIB};
 my $had5lib = exists $ENV{PERL5LIB};
 sub perl_lib {
+    my $basecwd = (File::Spec->splitdir(getcwd))[-1];
+    croak "Basename of cwd needs to be 't' but is '$basecwd'\n"
+        unless $basecwd eq 't';
                                # perl-src/t/
     my $lib =  $ENV{PERL_CORE} ? qq{../lib}
                                # ExtUtils-MakeMaker/t/
@@ -255,14 +264,18 @@ sub make_macro {
 
     my $is_mms = $make =~ /^MM(K|S)/i;
 
-    my $cmd = $make;
-    my $macros = '';
+    my @macros;
     while( my($key,$val) = splice(@_, 0, 2) ) {
-        if( $is_mms ) {
-            $macros .= qq{/macro="$key=$val"};
+        push @macros, qq{$key=$val};
+    }
+    my $macros = '';
+    if (scalar(@macros)) {
+        if ($is_mms) {
+            map { $_ = qq{"$_"} } @macros;
+            $macros = '/MACRO=(' . join(',', @macros) . ')';
         }
         else {
-            $macros .= qq{ $key=$val};
+            $macros = join(' ', @macros);
         }
     }
 
@@ -280,11 +293,12 @@ touched.
 =cut
 
 sub calibrate_mtime {
-    open(FILE, ">calibrate_mtime.tmp") || die $!;
+    my $file = "calibrate_mtime-$$.tmp";
+    open(FILE, ">$file") || die $!;
     print FILE "foo";
     close FILE;
-    my($mtime) = (stat('calibrate_mtime.tmp'))[9];
-    unlink 'calibrate_mtime.tmp';
+    my($mtime) = (stat($file))[9];
+    unlink $file;
     return $mtime;
 }
 
@@ -345,23 +359,11 @@ Returns true if there is a compiler available for XS builds.
 
 sub have_compiler {
     my $have_compiler = 0;
-
-    # ExtUtils::CBuilder prints its compilation lines to the screen.
-    # Shut it up.
-    use TieOut;
-    local *STDOUT = *STDOUT;
-    local *STDERR = *STDERR;
-
-    tie *STDOUT, 'TieOut';
-    tie *STDERR, 'TieOut';
-
     eval {
-       require ExtUtils::CBuilder;
-       my $cb = ExtUtils::CBuilder->new;
-
-       $have_compiler = $cb->have_compiler;
+        require ExtUtils::CBuilder;
+        my $cb = ExtUtils::CBuilder->new(quiet=>1);
+        $have_compiler = $cb->have_compiler;
     };
-
     return $have_compiler;
 }
 
@@ -386,6 +388,72 @@ sub slurp {
     return $text;
 }
 
+=item hash2files
+
+  hash2files('dirname', { 'filename' => 'some content' });
+
+Goes through given hash-ref, treating each key as a /-separated filename
+under the specified directory, and writing the value into it. Will create
+any necessary directories.
+
+Will die if errors occur.
+
+=cut
+
+sub hash2files {
+    my ($prefix, $hashref) = @_;
+    while(my ($file, $text) = each %$hashref) {
+        # Convert to a relative, native file path.
+        $file = File::Spec->catfile(File::Spec->curdir, $prefix, split m{\/}, $file);
+        my $dir = dirname($file);
+        mkpath $dir;
+        my $utf8 = ($] < 5.008 or !$Config{useperlio}) ? "" : ":utf8";
+        open(FILE, ">$utf8", $file) || die "Can't create $file: $!";
+        print FILE $text;
+        close FILE;
+        # ensure file at least 1 second old for makes that assume
+        # files with the same time are out of date.
+        my $time = calibrate_mtime();
+        utime $time, $time - 1, $file;
+    }
+}
+
+=item in_dir
+
+  $retval = in_dir(\&coderef);
+  $retval = in_dir(\&coderef, $specified_dir);
+  $retval = in_dir { somecode(); };
+  $retval = in_dir { somecode(); } $specified_dir;
+
+Does a C<chdir> to either a directory. If none is specified, one is
+created with L<File::Temp> and then automatically deleted after. It ends
+by C<chdir>ing back to where it started.
+
+If the given code throws an exception, it will be re-thrown after the
+re-C<chdir>.
+
+Returns the return value of the given code.
+
+=cut
+
+sub in_dir(&;$) {
+    my $code = shift;
+    require File::Temp;
+    my $dir = shift || File::Temp::tempdir(TMPDIR => 1, CLEANUP => 1);
+    # chdir to the new directory
+    my $orig_dir = getcwd();
+    chdir $dir or die "Can't chdir to $dir: $!";
+    # Run the code, but trap the error so we can chdir back
+    my $return;
+    my $ok = eval { $return = $code->(); 1; };
+    my $err = $@;
+    # chdir back
+    chdir $orig_dir or die "Can't chdir to $orig_dir: $!";
+    # rethrow if necessary
+    die $err unless $ok;
+    return $return;
+}
+
 =back
 
 =head1 AUTHOR
index 7053c33..c99926d 100644 (file)
-BEGIN {
-    chdir '..' if -d '../t';
-    unshift @INC, 't/lib';
-    use lib 'lib';
-}
+#!perl -w
 
 use strict;
 use warnings;
-use Test::More 'no_plan';
 
+BEGIN { unshift @INC, 't/lib'; }
+use Test::More eval { require CPAN::Meta; CPAN::Meta->VERSION(2.143240) } ? ()
+  : (skip_all => 'CPAN::Meta 2.143240 required for this test');
+use File::Temp qw[tempdir];
 require ExtUtils::MM_Any;
 
-sub ExtUtils::MM_Any::quote_literal { $_[1] }
-
-my $new_mm = sub {
-    return bless { ARGS => {@_}, @_ }, 'ExtUtils::MM_Any';
-};
+my $tmpdir = tempdir( DIR => 't', CLEANUP => 1 );
+use Cwd; my $cwd = getcwd; END { chdir $cwd } # so File::Temp can cleanup
+chdir $tmpdir or die "chdir $tmpdir: $!";
+
+my $EMPTY = qr/['"]?version['"]?\s*:\s*['"]['"]/;
+my @DATA = (
+    [
+        [ DISTNAME => 'Net::FTP::Recursive', VERSION  => 'Recursive.pm', ],
+        qr{Can't parse version 'Recursive.pm'},
+        'VERSION => filename',
+        $EMPTY,
+    ],
+    [
+        [ DISTNAME => 'Image::Imgur', VERSION  => 'undef', ],
+        qr{Can't parse version 'undef'},
+        'no $VERSION in file -> VERSION=>"undef"',
+        $EMPTY,
+    ],
+    [
+        [ DISTNAME => 'SQL::Library', VERSION  => 0.0.3, ],
+        qr{Can't parse version '\x00\x00\x03'},
+        "x.y.z version",
+        $EMPTY,
+    ],
+    [
+        [ DISTNAME => 'Array::Suffix', VERSION  => '.5', ],
+        qr{Can't parse version '.5'},
+        ".5 version",
+        $EMPTY,
+    ],
+    [
+        [
+            DISTNAME   => 'Attribute::Signature',
+            META_MERGE => {
+                resources => {
+                    repository         => 'http://github.com/chorny/Attribute-Signature',
+                    'Repository-clone' => 'git://github.com/chorny/Attribute-Signature.git',
+                },
+            },
+        ],
+        qr/^$/,
+        "Non-camel case metadata",
+        qr/x_Repositoryclone/,
+    ],
+    [
+        [
+            DISTNAME   => 'CPAN::Testers::ParseReport',
+            VERSION    => '2.34',
+            META_ADD => {
+                provides => {
+                    "CPAN::Testers::ParseReport" => {
+                        version => version->new("v1.2.3"),
+                        file    => "lib/CPAN/Testers/ParseReport.pm"
+                    }
+                }
+            },
+        ],
+        qr/^$/,
+        "version object in provides",
+        qr/['"]?version['"]?\s*:\s*['"]v1\.2\.3['"]/,
+    ],
+    [
+        [
+            DISTNAME   => 'Bad::License',
+            VERSION    => '2.34',
+            LICENSE   => 'death and retribution',
+        ],
+        qr/Invalid LICENSE value/,
+        "Bad licence warns",
+        qr/['"]?version['"]?\s*:\s*['"]2\.34['"]/,
+    ],
+);
+
+plan tests => 3 * @DATA;
+run_test(@$_) for @DATA;
 
-my $warn_ok = sub {
-    my($code, $want, $name) = @_;
+sub ExtUtils::MM_Any::quote_literal { $_[1] }
 
-    my @have;
+sub run_test {
+    my ($mmargs, $expected, $label, $metadata_re) = @_;
+    my $mm = bless { ARGS => {@$mmargs}, @$mmargs }, 'ExtUtils::MM_Any';
+    my @warnings;
     my $ret;
     {
-        local $SIG{__WARN__} = sub { push @have, @_ };
-        $ret = $code->();
+        local $SIG{__WARN__} = sub { push @warnings, @_ };
+        eval { $ret = $mm->metafile_target; };
+    }
+    SKIP: {
+        if ($@) {
+            diag $@;
+            skip "$label got exception", 3 if $@;
+        }
+        ok 1, "$label metafile_target";
+        like join("", @warnings), $expected, "$label right warning";
+        like $ret, $metadata_re, "$label metadata";
     }
-
-    like join("", @have), $want, $name;
-    return $ret;
-};
-
-my $version_regex = qr/version: ''/;
-my $version_action = "they're converted to empty string";
-
-
-note "Filename as version"; {
-    my $mm = $new_mm->(
-        DISTNAME => 'Net::FTP::Recursive',
-        VERSION  => 'Recursive.pm',
-    );
-
-    my $res = $warn_ok->(
-        sub { eval { $mm->metafile_target } },
-        qr{Can't parse version 'Recursive.pm'}
-    );
-    ok $res, 'we know how to deal with bogus versions defined in Makefile.PL';
-    like $res, $version_regex, $version_action;
-}
-
-
-note "'undef' version from parse_version"; {
-    my $mm = $new_mm->(
-        DISTNAME => 'Image::Imgur',
-        VERSION  => 'undef',
-    );
-    my $res = $warn_ok->(
-        sub { eval { $mm->metafile_target } },
-        qr{Can't parse version 'undef'}
-    );
-    ok $res, q|when there's no $VERSION in Module.pm, $self->{VERSION} = 'undef'; via MM_Unix::parse_version and we know how to deal with that|;
-    like $res, $version_regex, $version_action;
-}
-
-
-note "x.y.z version"; {
-    my $mm = $new_mm->(
-        DISTNAME => 'SQL::Library',
-        VERSION  => 0.0.3,
-    );
-
-    # It would be more useful if the warning got translated to visible characters
-    my $res = $warn_ok->(
-        sub { eval { $mm->metafile_target } },
-        qr{Can't parse version '\x00\x00\x03'}
-    );
-    ok $res, q|we know how to deal with our $VERSION = 0.0.3; style versions defined in the module|;
-    like $res, $version_regex, $version_action;
-}
-
-
-note ".5 version"; {
-    my $mm = $new_mm->(
-        DISTNAME => 'Array::Suffix',
-        VERSION  => '.5',
-    );
-    my $res = $warn_ok->(
-        sub { eval { $mm->metafile_target } },
-        qr{Can't parse version '.5'}
-    );
-    ok $res, q|we know how to deal with our $VERSION = '.5'; style versions defined in the module|;
-    like $res, $version_regex, $version_action;
-}
-
-
-note "Non-camel case metadata"; {
-    my $mm = $new_mm->(
-        DISTNAME   => 'Attribute::Signature',
-        META_MERGE => {
-            resources => {
-                repository         => 'http://github.com/chorny/Attribute-Signature',
-                'Repository-clone' => 'git://github.com/chorny/Attribute-Signature.git',
-            },
-        },
-    );
-    my $res = eval { $mm->metafile_target };
-    ok $res, q|we know how to deal with non-camel-cased custom meta resource keys defined in Makefile.PL|;
-    like $res, qr/x_Repositoryclone/, "they're camel-cased";
-}
-
-
-note "version object in provides"; {
-    my $mm = $new_mm->(
-        DISTNAME   => 'CPAN::Testers::ParseReport',
-        VERSION    => '2.34',
-        META_ADD => {
-            provides => {
-                "CPAN::Testers::ParseReport" => {
-                    version => version->new("v1.2.3"),
-                    file    => "lib/CPAN/Testers/ParseReport.pm"
-                }
-            }
-        },
-    );
-    my $res = eval { $mm->metafile_target };
-    like $res, qr{version: \s* v1.2.3}x;
 }
index a9c90ae..01d72d8 100644 (file)
@@ -3,226 +3,133 @@ BEGIN {
 }
 
 use strict;
-use Test::More tests => 31;
-
+use Test::More;
+BEGIN {
+  eval { require CPAN::Meta; CPAN::Meta->VERSION(2.143240) }
+    or plan skip_all => 'CPAN::Meta 2.143240 required for this test';
+  eval { require CPAN::Meta::Converter; }
+    or plan skip_all => 'CPAN::Meta::Converter required for this test';
+  eval { require Parse::CPAN::Meta; }
+    or plan skip_all => 'Parse::CPAN::Meta required for this test';
+}
 use Data::Dumper;
 use File::Temp;
 use Cwd;
-use Parse::CPAN::Meta;
+use MakeMaker::Test::Utils;
 
+plan tests => 31;
 require ExtUtils::MM_Any;
 
-sub in_dir(&;$) {
-    my $code = shift;
-    my $dir = shift || File::Temp->newdir;
-
-    # chdir to the new directory
-    my $orig_dir = cwd();
-    chdir $dir or die "Can't chdir to $dir: $!";
-
-    # Run the code, but trap the error so we can chdir back
-    my $return;
-    my $ok = eval { $return = $code->(); 1; };
-    my $err = $@;
-
-    # chdir back
-    chdir $orig_dir or die "Can't chdir to $orig_dir: $!";
-
-    # rethrow if necessary
-    die $err unless $ok;
-
-    return $return;
-}
-
 sub mymeta_ok {
     my($have, $want, $name) = @_;
-
     local $Test::Builder::Level = $Test::Builder::Level + 1;
-
     my $have_gen = delete $have->{generated_by};
     my $want_gen = delete $want->{generated_by};
     my $have_url = delete $have->{'meta-spec'}->{url};
     my $want_url = delete $want->{'meta-spec'}->{url};
-
     is_deeply $have, $want, $name;
     like $have_gen, qr{CPAN::Meta}, "CPAN::Meta mentioned in the generated_by";
     like $have_url, qr{CPAN::Meta::Spec}, "CPAN::Meta::Spec mentioned in meta-spec URL";
-
     return;
 }
 
 my $new_mm = sub {
     return bless { ARGS => {@_}, @_ }, 'ExtUtils::MM_Any';
 };
+my @METASPEC14 = (
+    'meta-spec'  => {
+        url => 'http://module-build.sourceforge.net/META-spec-v1.4.html',
+        version => 1.4
+    },
+);
+my @METASPEC20 = (
+    'meta-spec'  => {
+        url => 'https://metacpan.org/pod/CPAN::Meta::Spec',
+        version => 2
+    },
+);
+my @REQ20 = (
+    configure => { requires => { 'ExtUtils::MakeMaker' => 0, }, },
+    build => { requires => { 'ExtUtils::MakeMaker' => 0, }, },
+);
+my @GENERIC_IN = (
+    DISTNAME => 'Foo-Bar',
+    VERSION  => 1.23,
+    PM       => { "Foo::Bar" => 'lib/Foo/Bar.pm', },
+);
+my @GENERIC_OUT = (
+    # mandatory
+    abstract          => 'unknown',
+    author            => [qw(unknown)],
+    dynamic_config    => 1,
+    generated_by      => "ExtUtils::MakeMaker version $ExtUtils::MakeMaker::VERSION",
+    license           => ['unknown'],
+    @METASPEC20,
+    name              => 'Foo-Bar',
+    release_status    => 'stable',
+    version           => 1.23,
+    # optional
+    no_index          => { directory => [qw(t inc)], },
+);
 
 {
-    my $mm = $new_mm->(
-        DISTNAME        => 'Foo-Bar',
-        VERSION         => 1.23,
-        PM              => {
-            "Foo::Bar"          => 'lib/Foo/Bar.pm',
-        },
-    );
-
-    is_deeply {$mm->metafile_data}, {
-        name            => 'Foo-Bar',
-        version         => 1.23,
-        abstract        => 'unknown',
-        author          => [],
-        license         => 'unknown',
-        dynamic_config  => 1,
-        distribution_type       => 'module',
-
-        configure_requires      => {
-            'ExtUtils::MakeMaker'       => 0,
-        },
-        build_requires      => {
-            'ExtUtils::MakeMaker'       => 0,
-        },
-
-        no_index        => {
-            directory           => [qw(t inc)],
-        },
-
-        generated_by => "ExtUtils::MakeMaker version $ExtUtils::MakeMaker::VERSION",
-        'meta-spec'  => {
-            url         => 'http://module-build.sourceforge.net/META-spec-v1.4.html',
-            version     => 1.4
-        },
+    my $mm = $new_mm->(@GENERIC_IN);
+    is_deeply $mm->metafile_data, {
+        @GENERIC_OUT,
+        prereqs => { @REQ20, },
     };
-
-
-    is_deeply {$mm->metafile_data({}, { no_index => { directory => [qw(foo)] } })}, {
-        name            => 'Foo-Bar',
-        version         => 1.23,
-        abstract        => 'unknown',
-        author          => [],
-        license         => 'unknown',
-        dynamic_config  => 1,
-        distribution_type       => 'module',
-
-        configure_requires      => {
-            'ExtUtils::MakeMaker'       => 0,
-        },
-        build_requires      => {
-            'ExtUtils::MakeMaker'       => 0,
-        },
-
-        no_index        => {
-            directory           => [qw(t inc foo)],
-        },
-
-        generated_by => "ExtUtils::MakeMaker version $ExtUtils::MakeMaker::VERSION",
-        'meta-spec'  => {
-            url         => 'http://module-build.sourceforge.net/META-spec-v1.4.html',
-            version     => 1.4
-        },
+    is_deeply $mm->metafile_data({}, { no_index => { directory => [qw(foo)] } }), {
+        @GENERIC_OUT,
+        prereqs => { @REQ20, },
+        no_index        => { directory => [qw(t inc foo)], },
     }, 'rt.cpan.org 39348';
 }
 
-
 {
     my $mm = $new_mm->(
         DISTNAME        => 'Foo-Bar',
         VERSION         => 1.23,
         AUTHOR          => ['Some Guy'],
-        PREREQ_PM       => {
-            Foo                 => 2.34,
-            Bar                 => 4.56,
-        },
+        PREREQ_PM       => { Foo => 2.34, Bar => 4.56, },
     );
-
-    is_deeply {$mm->metafile_data(
+    is_deeply $mm->metafile_data(
         {
-            configure_requires => {
-                Stuff   => 2.34
-            },
+            configure_requires => { Stuff   => 2.34 },
             wobble      => 42
         },
         {
-            no_index    => {
-                package => "Thing"
-            },
+            no_index    => { package => "Thing" },
             wibble      => 23
         },
-    )},
+    ),
     {
-        name            => 'Foo-Bar',
-        version         => 1.23,
-        abstract        => 'unknown',
+        @GENERIC_OUT, # some overridden, which is fine
         author          => ['Some Guy'],
-        license         => 'unknown',
-        dynamic_config  => 1,
-        distribution_type       => 'script',
-
-        configure_requires      => {
-            Stuff       => 2.34,
-        },
-        build_requires      => {
-            'ExtUtils::MakeMaker'       => 0,
-        },
-
-        requires       => {
-            Foo                 => 2.34,
-            Bar                 => 4.56,
+        prereqs => {
+            @REQ20,
+            configure => { requires => { Stuff => 2.34, }, },
+            runtime => { requires => { Foo => 2.34, Bar => 4.56, }, },
         },
-
         no_index        => {
             directory           => [qw(t inc)],
-            package             => 'Thing',
+            package             => ['Thing'],
         },
-
-        generated_by => "ExtUtils::MakeMaker version $ExtUtils::MakeMaker::VERSION",
-        'meta-spec'  => {
-            url         => 'http://module-build.sourceforge.net/META-spec-v1.4.html',
-            version     => 1.4
-        },
-
-        wibble  => 23,
-        wobble  => 42,
-    };
+        x_wibble  => 23,
+        x_wobble  => 42,
+    }, '_add vs _merge';
 }
 
-
 # Test MIN_PERL_VERSION meta-spec 1.4
 {
     my $mm = $new_mm->(
-        DISTNAME        => 'Foo-Bar',
-        VERSION         => 1.23,
-        PM              => {
-            "Foo::Bar"          => 'lib/Foo/Bar.pm',
-        },
+        @GENERIC_IN,
         MIN_PERL_VERSION => 5.006,
     );
-
-    is_deeply {$mm->metafile_data}, {
-        name            => 'Foo-Bar',
-        version         => 1.23,
-        abstract        => 'unknown',
-        author          => [],
-        license         => 'unknown',
-        dynamic_config  => 1,
-        distribution_type       => 'module',
-
-        configure_requires      => {
-            'ExtUtils::MakeMaker'       => 0,
-        },
-        build_requires      => {
-            'ExtUtils::MakeMaker'       => 0,
-        },
-
-        requires        => {
-            perl        => '5.006',
-        },
-
-        no_index        => {
-            directory           => [qw(t inc)],
-        },
-
-        generated_by => "ExtUtils::MakeMaker version $ExtUtils::MakeMaker::VERSION",
-        'meta-spec'  => {
-            url         => 'http://module-build.sourceforge.net/META-spec-v1.4.html',
-            version     => 1.4
+    is_deeply $mm->metafile_data( {}, { @METASPEC14 }, ), {
+        @GENERIC_OUT,
+        prereqs => {
+            @REQ20,
+            runtime => { requires => { perl => 5.006, }, },
         },
     }, 'MIN_PERL_VERSION meta-spec 1.4';
 }
@@ -230,104 +137,35 @@ my $new_mm = sub {
 # Test MIN_PERL_VERSION meta-spec 2.0
 {
     my $mm = $new_mm->(
-        DISTNAME        => 'Foo-Bar',
-        VERSION         => 1.23,
-        PM              => {
-            "Foo::Bar"          => 'lib/Foo/Bar.pm',
-        },
+        @GENERIC_IN,
         MIN_PERL_VERSION => 5.006,
     );
-
-    is_deeply {
-        $mm->metafile_data(
-                {}, {
-                'meta-spec' => {
-                url     => 'http://search.cpan.org/perldoc?CPAN::Meta::Spec',
-                version => 2
-                } } )
-    }, {
-        name            => 'Foo-Bar',
-        version         => 1.23,
-        abstract        => 'unknown',
-        author          => [],
-        license         => 'unknown',
-        dynamic_config  => 1,
-        distribution_type       => 'module',
-
+    is_deeply $mm->metafile_data, {
         prereqs => {
-            configure       => {
-                requires    => {
-                    'ExtUtils::MakeMaker'   => 0,
-                },
-            },
-            build           => {
-                requires    => {
-                    'ExtUtils::MakeMaker'   => 0,
-                },
-            },
-            runtime         => {
-                requires    => {
-                    'perl'  => '5.006',
-                },
-            },
-        },
-
-        no_index        => {
-            directory           => [qw(t inc)],
-        },
-
-        generated_by => "ExtUtils::MakeMaker version $ExtUtils::MakeMaker::VERSION",
-        'meta-spec'  => {
-
-            url     => 'http://search.cpan.org/perldoc?CPAN::Meta::Spec',
-            version => 2
+            @REQ20,
+            runtime => { requires => { 'perl' => '5.006', }, },
         },
+        @GENERIC_OUT,
     }, 'MIN_PERL_VERSION meta-spec 2.0';
 }
 
 # Test MIN_PERL_VERSION meta-spec 1.4
 {
     my $mm = $new_mm->(
-        DISTNAME        => 'Foo-Bar',
-        VERSION         => 1.23,
-        PM              => {
-            "Foo::Bar"          => 'lib/Foo/Bar.pm',
-        },
+        @GENERIC_IN,
         MIN_PERL_VERSION => 5.006,
-        PREREQ_PM => {
-            'Foo::Bar'  => 1.23,
-        },
+        PREREQ_PM => { 'Foo::Bar' => 1.23, },
     );
-
-    is_deeply {$mm->metafile_data}, {
-        name            => 'Foo-Bar',
-        version         => 1.23,
-        abstract        => 'unknown',
-        author          => [],
-        license         => 'unknown',
-        dynamic_config  => 1,
-        distribution_type       => 'module',
-
-        configure_requires      => {
-            'ExtUtils::MakeMaker'       => 0,
-        },
-        build_requires      => {
-            'ExtUtils::MakeMaker'       => 0,
-        },
-
-        requires        => {
-            perl        => '5.006',
-            'Foo::Bar'  => 1.23,
-        },
-
-        no_index        => {
-            directory           => [qw(t inc)],
-        },
-
-        generated_by => "ExtUtils::MakeMaker version $ExtUtils::MakeMaker::VERSION",
-        'meta-spec'  => {
-            url         => 'http://module-build.sourceforge.net/META-spec-v1.4.html',
-            version     => 1.4
+    is_deeply $mm->metafile_data, {
+        @GENERIC_OUT,
+        prereqs => {
+            @REQ20,
+            runtime         => {
+                requires    => {
+                    'Foo::Bar'  => 1.23,
+                    'perl'  => '5.006',
+                },
+            },
         },
     }, 'MIN_PERL_VERSION and PREREQ_PM meta-spec 1.4';
 }
@@ -335,339 +173,111 @@ my $new_mm = sub {
 # Test CONFIGURE_REQUIRES meta-spec 1.4
 {
     my $mm = $new_mm->(
-        DISTNAME        => 'Foo-Bar',
-        VERSION         => 1.23,
-        CONFIGURE_REQUIRES => {
-            "Fake::Module1" => 1.01,
-        },
-        PM              => {
-            "Foo::Bar"          => 'lib/Foo/Bar.pm',
-        },
+        @GENERIC_IN,
+        CONFIGURE_REQUIRES => { "Fake::Module1" => 1.01, },
     );
-
-    is_deeply {$mm->metafile_data}, {
-        name            => 'Foo-Bar',
-        version         => 1.23,
-        abstract        => 'unknown',
-        author          => [],
-        license         => 'unknown',
-        dynamic_config  => 1,
-        distribution_type       => 'module',
-
-        configure_requires      => {
-            'Fake::Module1'     => 1.01,
-        },
-        build_requires      => {
-            'ExtUtils::MakeMaker'   => 0,
-        },
-
-        no_index        => {
-            directory           => [qw(t inc)],
-        },
-
-        generated_by => "ExtUtils::MakeMaker version $ExtUtils::MakeMaker::VERSION",
-        'meta-spec'  => {
-            url         => 'http://module-build.sourceforge.net/META-spec-v1.4.html',
-            version     => 1.4
+    is_deeply $mm->metafile_data( {}, { @METASPEC14 }, ), {
+        prereqs => {
+            @REQ20,
+            configure => { requires => { 'Fake::Module1' => 1.01, }, },
         },
+        @GENERIC_OUT,
     },'CONFIGURE_REQUIRES meta-spec 1.4';
 }
 
 # Test CONFIGURE_REQUIRES meta-spec 2.0
 {
     my $mm = $new_mm->(
-        DISTNAME        => 'Foo-Bar',
-        VERSION         => 1.23,
-        CONFIGURE_REQUIRES => {
-            "Fake::Module1" => 1.01,
-        },
-        PM              => {
-            "Foo::Bar"      => 'lib/Foo/Bar.pm',
-        },
+        @GENERIC_IN,
+        CONFIGURE_REQUIRES => { "Fake::Module1" => 1.01, },
     );
-
-    is_deeply {
-        $mm->metafile_data(
-                {}, {
-                'meta-spec' => {
-                url     => 'http://search.cpan.org/perldoc?CPAN::Meta::Spec',
-                version => 2
-                } } )
-    }, {
-        name            => 'Foo-Bar',
-        version         => 1.23,
-        abstract        => 'unknown',
-        author          => [],
-        license         => 'unknown',
-        dynamic_config  => 1,
-        distribution_type       => 'module',
-
+    is_deeply $mm->metafile_data, {
         prereqs => {
-            configure       => {
-                requires    => {
-                    'Fake::Module1'         => 1.01,
-                },
-            },
-            build           => {
-                requires    => {
-                    'ExtUtils::MakeMaker'   => 0,
-                },
-            },
-        },
-
-        no_index        => {
-            directory           => [qw(t inc)],
-        },
-
-        generated_by => "ExtUtils::MakeMaker version $ExtUtils::MakeMaker::VERSION",
-        'meta-spec'  => {
-            url         => 'http://search.cpan.org/perldoc?CPAN::Meta::Spec',
-            version     => 2
+            @REQ20,
+            configure => { requires => { 'Fake::Module1' => 1.01, }, },
         },
+        @GENERIC_OUT,
     },'CONFIGURE_REQUIRES meta-spec 2.0';
 }
 
-
 # Test BUILD_REQUIRES meta-spec 1.4
 {
     my $mm = $new_mm->(
-        DISTNAME        => 'Foo-Bar',
-        VERSION         => 1.23,
-        BUILD_REQUIRES => {
-            "Fake::Module1" => 1.01,
-        },
-        PM              => {
-            "Foo::Bar"          => 'lib/Foo/Bar.pm',
-        },
+        @GENERIC_IN,
+        BUILD_REQUIRES => { "Fake::Module1" => 1.01, },
+        META_MERGE => { "meta-spec" => { version => 1.4 }},
     );
-
-    is_deeply {$mm->metafile_data}, {
-        name            => 'Foo-Bar',
-        version         => 1.23,
-        abstract        => 'unknown',
-        author          => [],
-        license         => 'unknown',
-        dynamic_config  => 1,
-        distribution_type       => 'module',
-
-        configure_requires      => {
-            'ExtUtils::MakeMaker'   => 0,
-        },
-        build_requires      => {
-            'Fake::Module1'         => 1.01,
-        },
-
-        no_index        => {
-            directory           => [qw(t inc)],
-        },
-
-        generated_by => "ExtUtils::MakeMaker version $ExtUtils::MakeMaker::VERSION",
-        'meta-spec'  => {
-            url         => 'http://module-build.sourceforge.net/META-spec-v1.4.html',
-            version     => 1.4
+    is_deeply $mm->metafile_data( {}, { @METASPEC14 }, ), {
+        prereqs => {
+            @REQ20,
+            build => { requires => { 'Fake::Module1' => 1.01, }, },
         },
+        @GENERIC_OUT,
     },'BUILD_REQUIRES meta-spec 1.4';
 }
 
 # Test BUILD_REQUIRES meta-spec 2.0
 {
     my $mm = $new_mm->(
-        DISTNAME        => 'Foo-Bar',
-        VERSION         => 1.23,