use strict;
use warnings;
use Config;
+BEGIN {
+ if ($^O eq 'MSWin32') {
+ unshift @INC, '../dist/Cwd';
+ require FindExt;
+ } else {
+ unshift @INC, 'dist/Cwd';
+ }
+}
use Cwd;
+my $is_Win32 = $^O eq 'MSWin32';
+my $is_VMS = $^O eq 'VMS';
+my $is_Unix = !$is_Win32 && !$is_VMS;
+
+my @ext_dirs = qw(cpan dist ext);
+my $ext_dirs_re = '(?:' . join('|', @ext_dirs) . ')';
+
# This script acts as a simple interface for building extensions.
# It's actually a cut and shut of the Unix version ext/utils/makeext and the
# Windows version win32/build_ext.pl hence the two invocation styles.
-# On Unix, it primarily used by the perl Makefile one extention at a time:
+# On Unix, it primarily used by the perl Makefile one extension at a time:
#
# d_dummy $(dynamic_ext): miniperl preplibrary FORCE
# @$(RUN) ./miniperl make_ext.pl --target=dynamic $@ MAKE=$(MAKE) LIBPERL_A=$(LIBPERL)
#
# On Windows or VMS,
# If '--static' is specified, static extensions will be built.
-# If '--dynamic' is specified, dynamic (and nonxs) extensions will be built.
+# If '--dynamic' is specified, dynamic extensions will be built.
+# If '--nonxs' is specified, nonxs extensions will be built.
+# If '--dynaloader' is specified, DynaLoader will be built.
# If '--all' is specified, all extensions will be built.
#
# make_ext.pl "MAKE=make [-make_opts]" --dir=directory [--target=target] [--static|--dynamic|--all] +ext2 !ext1
# It may be deleted in a later release of perl so try to
# avoid using it for other purposes.
-my $is_Win32 = $^O eq 'MSWin32';
-my $is_VMS = $^O eq 'VMS';
-my $is_Unix = !$is_Win32 && !$is_VMS;
-
-require FindExt if $is_Win32;
-
my (%excl, %incl, %opts, @extspec, @pass_through);
foreach (@ARGV) {
} elsif (/^--([\w\-]+)$/) {
$opts{$1} = 1;
} elsif (/^--([\w\-]+)=(.*)$/) {
- $opts{$1} = $2;
+ push @{$opts{$1}}, $2;
} elsif (/=/) {
push @pass_through, $_;
} elsif (length) {
my $static = $opts{static} || $opts{all};
my $dynamic = $opts{dynamic} || $opts{all};
+my $nonxs = $opts{nonxs} || $opts{all};
+my $dynaloader = $opts{dynaloader} || $opts{all};
# The Perl Makefile.SH will expand all extensions to
# lib/auto/X/X.a (or lib/auto/X/Y/Y.a if nested)
if (s{^lib/auto/}{}) {
# Remove lib/auto prefix and /*.* suffix
s{/[^/]+\.[^/]+$}{};
- } elsif (s{^ext/}{}) {
+ } elsif (s{^$ext_dirs_re/}{}) {
# Remove ext/ prefix and /pm_to_blib suffix
s{/pm_to_blib$}{};
# Targets are given as files on disk, but the extension spec is still
my $makecmd = shift @pass_through; # Should be something like MAKE=make
unshift @pass_through, 'PERL_CORE=1';
-my $dir = $opts{dir} || 'ext';
-my $target = $opts{target};
+my @dirs = @{$opts{dir} || \@ext_dirs};
+my $target = $opts{target}[0];
$target = 'all' unless defined $target;
# Previously, $make was taken from config.sh. However, the user might
die "$0: unknown make target '$target'\n";
}
-if (!@extspec and !$static and !$dynamic) {
+if (!@extspec and !$static and !$dynamic and !$nonxs and !$dynaloader) {
die "$0: no extension specified\n";
}
my %extra_passthrough;
if ($is_Win32) {
- (my $here = getcwd()) =~ s{/}{\\}g;
+ my $build = getcwd();
$perl = $^X;
if ($perl =~ m#^\.\.#) {
+ my $here = $build;
+ $here =~ s{/}{\\}g;
$perl = "$here\\$perl";
}
(my $topdir = $perl) =~ s/\\[^\\]+$//;
$ENV{PATH} = "$topdir;$topdir\\win32\\bin;$ENV{PATH}";
my $pl2bat = "$topdir\\win32\\bin\\pl2bat";
unless (-f "$pl2bat.bat") {
- my @args = ($perl, ("$pl2bat.pl") x 2);
+ my @args = ($perl, "-I$topdir\\lib", ("$pl2bat.pl") x 2);
print "@args\n";
system(@args) unless defined $::Cross::platform;
}
- print "In ", getcwd();
- chdir($dir) || die "Cannot cd to $dir\n";
- (my $ext = getcwd()) =~ s{/}{\\}g;
- FindExt::scan_ext($ext);
- FindExt::set_static_extensions(split ' ', $Config{static_ext});
+ print "In $build";
+ foreach my $dir (@dirs) {
+ chdir($dir) or die "Cannot cd to $dir: $!\n";
+ (my $ext = getcwd()) =~ s{/}{\\}g;
+ FindExt::scan_ext($ext);
+ FindExt::set_static_extensions(split ' ', $Config{static_ext});
+ chdir $build
+ or die "Couldn't chdir to '$build': $!"; # restore our start directory
+ }
my @ext;
push @ext, FindExt::static_ext() if $static;
- push @ext, FindExt::dynamic_ext(), FindExt::nonxs_ext() if $dynamic;
+ push @ext, FindExt::dynamic_ext() if $dynamic;
+ push @ext, FindExt::nonxs_ext() if $nonxs;
+ push @ext, 'DynaLoader' if $dynaloader;
foreach (sort @ext) {
if (%incl and !exists $incl{$_}) {
- #warn "Skipping extension $ext\\$_, not in inclusion list\n";
+ #warn "Skipping extension $_, not in inclusion list\n";
next;
}
if (exists $excl{$_}) {
- warn "Skipping extension $ext\\$_, not ported to current platform";
+ warn "Skipping extension $_, not ported to current platform";
next;
}
push @extspec, $_;
- if(FindExt::is_static($_)) {
+ if($_ eq 'DynaLoader' and $target !~ /clean$/) {
+ # No, we don't know why nmake can't work out the dependency chain
+ push @{$extra_passthrough{$_}}, 'DynaLoader.c';
+ } elsif(FindExt::is_static($_)) {
push @{$extra_passthrough{$_}}, 'LINKTYPE=static';
}
}
- chdir '..'; # now in the Perl build directory
+
+ chdir '..'
+ or die "Couldn't chdir to build directory: $!"; # now in the Perl build
}
elsif ($is_VMS) {
$perl = $^X;
push @extspec, (split ' ', $Config{static_ext}) if $static;
push @extspec, (split ' ', $Config{dynamic_ext}) if $dynamic;
+ push @extspec, (split ' ', $Config{nonxs_ext}) if $nonxs;
+ push @extspec, 'DynaLoader' if $dynaloader;
+}
+
+{
+ # Cwd needs to be built before Encode recurses into subdirectories.
+ # This seems to be the simplest way to ensure this ordering:
+ my (@first, @other);
+ foreach (@extspec) {
+ if ($_ eq 'Cwd') {
+ push @first, $_;
+ } else {
+ push @other, $_;
+ }
+ }
+ @extspec = (@first, @other);
+}
+
+if ($Config{osname} eq 'catamount' and @extspec) {
+ # Snowball's chance of building extensions.
+ die "This is $Config{osname}, not building $extspec[0], sorry.\n";
}
foreach my $spec (@extspec) {
my $mname = $spec;
$mname =~ s!/!::!g;
my $ext_pathname;
- if (-d "ext/$spec") {
- # Old style ext/Data/Dumper/
- $ext_pathname = "ext/$spec";
- } else {
- # New style ext/Data-Dumper/
- my $copy = $spec;
- $copy =~ tr!/!-!;
- $ext_pathname = "ext/$copy";
+
+ # Try new style ext/Data-Dumper/ first
+ my $copy = $spec;
+ $copy =~ tr!/!-!;
+ foreach my $dir (@ext_dirs) {
+ if (-d "$dir/$copy") {
+ $ext_pathname = "$dir/$copy";
+ last;
+ }
}
- if ($Config{osname} eq 'catamount') {
- # Snowball's chance of building extensions.
- die "This is $Config{osname}, not building $mname, sorry.\n";
+ if (!defined $ext_pathname) {
+ if (-d "ext/$spec") {
+ # Old style ext/Data/Dumper/
+ $ext_pathname = "ext/$spec";
+ } else {
+ warn "Can't find extension $spec in any of @ext_dirs";
+ next;
+ }
}
print "\tMaking $mname ($target)\n";
sub build_extension {
my ($ext_dir, $perl, $mname, $pass_through) = @_;
+ unless (chdir "$ext_dir") {
+ warn "Cannot cd to $ext_dir: $!";
+ return;
+ }
+
my $up = $ext_dir;
$up =~ s![^/]+!..!g;
$perl ||= "$up/miniperl";
my $return_dir = $up;
my $lib_dir = "$up/lib";
- $ENV{PERL5LIB} = $lib_dir;
+ $ENV{PERL_CORE} = 1;
- unless (chdir "$ext_dir") {
- warn "Cannot cd to $ext_dir: $!";
- return;
- }
my $makefile;
if ($is_VMS) {
$makefile = 'descrip.mms';
if (!-f $makefile) {
if (!-f 'Makefile.PL') {
print "\nCreating Makefile.PL in $ext_dir for $mname\n";
- # We need to cope well with various possible layouts
- my @dirs = split /::/, $mname;
- my $leaf = pop @dirs;
- my $leafname = "$leaf.pm";
- my $pathname = join '/', @dirs, $leafname;
- my @locations = ($leafname, $pathname, "lib/$pathname");
- my $fromname;
- foreach (@locations) {
- if (-f $_) {
- $fromname = $_;
- last;
+ my ($fromname, $key, $value);
+ if ($mname eq 'podlators') {
+ # We need to special case this somewhere, and this is fewer
+ # lines of code than a core-only Makefile.PL, and no more
+ # complex
+ $fromname = 'VERSION';
+ $key = 'DISTNAME';
+ $value = 'podlators';
+ $mname = 'Pod';
+ } else {
+ $key = 'ABSTRACT_FROM';
+ # We need to cope well with various possible layouts
+ my @dirs = split /::/, $mname;
+ my $leaf = pop @dirs;
+ my $leafname = "$leaf.pm";
+ my $pathname = join '/', @dirs, $leafname;
+ my @locations = ($leafname, $pathname, "lib/$pathname");
+ foreach (@locations) {
+ if (-f $_) {
+ $fromname = $_;
+ last;
+ }
}
- }
- unless ($fromname) {
- die "For $mname tried @locations in in $ext_dir but can't find source";
+ unless ($fromname) {
+ die "For $mname tried @locations in in $ext_dir but can't find source";
+ }
+ ($value = $fromname) =~ s/\.pm\z/.pod/;
+ $value = $fromname unless -e $value;
}
open my $fh, '>', 'Makefile.PL'
or die "Can't open Makefile.PL for writing: $!";
- print $fh <<"EOM";
+ printf $fh <<'EOM', $0, $mname, $fromname, $key, $value;
#-*- buffer-read-only: t -*-
-# This Makefile.PL was written by $0.
+# This Makefile.PL was written by %s.
# It will be deleted automatically by make realclean
use strict;
use ExtUtils::MakeMaker;
+# This is what the .PL extracts to. Not the ultimate file that is installed.
+# (ie Win32 runs pl2bat after this)
+
+# Doing this here avoids all sort of quoting issues that would come from
+# attempting to write out perl source with literals to generate the arrays and
+# hash.
+my @temps = 'Makefile.PL';
+foreach (glob('scripts/pod*.PL')) {
+ # The various pod*.PL extractors change directory. Doing that with relative
+ # paths in @INC breaks. It seems the lesser of two evils to copy (to avoid)
+ # the chdir doing anything, than to attempt to convert lib paths to
+ # absolute, and potentially run into problems with quoting special
+ # characters in the path to our build dir (such as spaces)
+ require File::Copy;
+
+ my $temp = $_;
+ $temp =~ s!scripts/!!;
+ File::Copy::copy($_, $temp) or die "Can't copy $temp to $_: $!";
+ push @temps, $temp;
+}
+
+my $script_ext = $^O eq 'VMS' ? '.com' : '';
+my %%pod_scripts;
+foreach (glob('pod*.PL')) {
+ my $script = $_;
+ s/.PL$/$script_ext/i;
+ $pod_scripts{$script} = $_;
+}
+my @exe_files = values %%pod_scripts;
+
WriteMakefile(
- NAME => '$mname',
- VERSION_FROM => '$fromname',
- ABSTRACT_FROM => '$fromname',
- realclean => {FILES => 'Makefile.PL'},
+ NAME => '%s',
+ VERSION_FROM => '%s',
+ %-13s => '%s',
+ realclean => { FILES => "@temps" },
+ (%%pod_scripts ? (
+ PL_FILES => \%%pod_scripts,
+ EXE_FILES => \@exe_files,
+ clean => { FILES => "@exe_files" },
+ ) : ()),
);
# ex: set ro:
@cross = '-MCross';
}
- my @args = (@cross, 'Makefile.PL');
+ my @args = ("-I$lib_dir", @cross, 'Makefile.PL');
if ($is_VMS) {
my $libd = VMS::Filespec::vmspath($lib_dir);
push @args, "INST_LIB=$libd", "INST_ARCHLIB=$libd";