+
+# Figure out if this extension is simple enough that it would only use
+# ExtUtils::MakeMaker's pm_to_blib target. If we're confident that it would,
+# then do all the work ourselves (returning an empty list), else return the
+# name of a file that we identified as beyond our ability to handle.
+#
+# While this is clearly quite a bit more work than just letting
+# ExtUtils::MakeMaker do it, and effectively is some code duplication, the time
+# savings are impressive.
+
+sub just_pm_to_blib {
+ my ($target, $ext_dir, $mname, $return_dir) = @_;
+ my ($has_lib, $has_top, $has_topdir);
+ my ($last) = $mname =~ /([^:]+)$/;
+ my ($first) = $mname =~ /^([^:]+)/;
+
+ my $pm_to_blib = IS_VMS ? 'pm_to_blib.ts' : 'pm_to_blib';
+ my $silent = defined $ENV{MAKEFLAGS} && $ENV{MAKEFLAGS} =~ /\b(s|silent|quiet)\b/;
+
+ foreach my $leaf (<*>) {
+ if (-d $leaf) {
+ $leaf =~ s/\.DIR\z//i
+ if IS_VMS;
+ next if $leaf =~ /\A(?:\.|\.\.|t|demo)\z/;
+ if ($leaf eq 'lib') {
+ ++$has_lib;
+ next;
+ }
+ if ($leaf eq $first) {
+ ++$has_topdir;
+ next;
+ }
+ }
+ return $leaf
+ unless -f _;
+ $leaf =~ s/\.\z//
+ if IS_VMS;
+ # Makefile.PL is "safe" to ignore because we will only be called for
+ # directories that hold a Makefile.PL if they are in the exception list.
+ next
+ if $leaf =~ /\A(ChangeLog
+ |Changes
+ |LICENSE
+ |Makefile\.PL
+ |MANIFEST
+ |META\.yml
+ |\Q$pm_to_blib\E
+ |README
+ |README\.patching
+ |README\.release
+ )\z/xi; # /i to deal with case munging systems.
+ if ($leaf eq "$last.pm") {
+ ++$has_top;
+ next;
+ }
+ return $leaf;
+ }
+ return 'no lib/'
+ unless $has_lib || $has_top;
+ die "Inconsistent module $mname has both lib/ and $first/"
+ if $has_lib && $has_topdir;
+
+ print "Running pm_to_blib for $ext_dir directly\n"
+ unless $silent;
+
+ my %pm;
+ if ($has_top) {
+ my $to = $mname =~ s!::!/!gr;
+ $pm{"$last.pm"} = "../../lib/$to.pm";
+ }
+ if ($has_lib || $has_topdir) {
+ # strictly ExtUtils::MakeMaker uses the pm_to_blib target to install
+ # .pm, pod and .pl files. We're just going to do it for .pm and .pod
+ # files, to avoid problems on case munging file systems. Specifically,
+ # _pm.PL which ExtUtils::MakeMaker should run munges to _PM.PL, and
+ # looks a lot like a regular foo.pl (ie FOO.PL)
+ my @found;
+ require File::Find;
+ unless (eval {
+ File::Find::find({
+ no_chdir => 1,
+ wanted => sub {
+ return if -d $_;
+ # Bail out immediately with the problem file:
+ die \$_
+ unless -f _;
+ die \$_
+ unless /\A[^.]+\.(?:pm|pod)\z/i;
+ push @found, $_;
+ }
+ }, $has_lib ? 'lib' : $first);
+ 1;
+ }) {
+ # Problem files aren't really errors:
+ return ${$@}
+ if ref $@ eq 'SCALAR';
+ # But anything else is:
+ die $@;
+ }
+ if ($has_lib) {
+ $pm{$_} = "../../$_"
+ foreach @found;
+ } else {
+ $pm{$_} = "../../lib/$_"
+ foreach @found;
+ }
+ }
+ # This is running under miniperl, so no autodie
+ if ($target eq 'all') {
+ my $need_update = 1;
+ if (-f $pm_to_blib) {
+ # avoid touching pm_to_blib unless there's something that
+ # needs updating, see #126710
+ $need_update = 0;
+ my $test_at = -M _;
+ while (my $from = each(%pm)) {
+ if (-M $from < $test_at) {
+ ++$need_update;
+ last;
+ }
+ }
+ keys %pm; # reset iterator
+ }
+
+ if ($need_update) {
+ local $ENV{PERL_INSTALL_QUIET} = 1;
+ require ExtUtils::Install;
+ ExtUtils::Install::pm_to_blib(\%pm, '../../lib/auto');
+ open my $fh, '>', $pm_to_blib
+ or die "Can't open '$pm_to_blib': $!";
+ print $fh "$0 has handled pm_to_blib directly\n";
+ close $fh
+ or die "Can't close '$pm_to_blib': $!";
+ if (IS_UNIX) {
+ # Fake the fallback cleanup
+ my $fallback
+ = join '', map {s!^\.\./\.\./!!; "rm -f $_\n"} sort values %pm;
+ foreach my $clean_target ('realclean', 'veryclean') {
+ fallback_cleanup($return_dir, $clean_target, $fallback);
+ }
+ }
+ }
+ } else {
+ # A clean target.
+ # For now, make the targets behave the same way as ExtUtils::MakeMaker
+ # does
+ _unlink($pm_to_blib);
+ unless ($target eq 'clean') {
+ # but cheat a bit, by relying on the top level Makefile clean target
+ # to take out our directory lib/auto/...
+ # (which it has to deal with, as cpan/foo/bar creates
+ # lib/auto/foo/bar, but the EU::MM rule will only
+ # rmdir lib/auto/foo/bar, leaving lib/auto/foo
+ _unlink($_)
+ foreach sort values %pm;
+ }
+ }
+ return;
+}
+
+sub fallback_cleanup {
+ my ($dir, $clean_target, $contents) = @_;
+ my $file = "$dir/$clean_target.sh";
+ open my $fh, '>>', $file or die "open $file: $!";
+ # Quite possible that we're being run in parallel here.
+ # Can't use Fcntl this early to get the LOCK_EX
+ flock $fh, 2 or warn "flock $file: $!";
+ print $fh $contents or die "print $file: $!";
+ close $fh or die "close $file: $!";
+}