Spaces:
Running
Running
package ExtUtils::MM_VMS; | |
use strict; | |
use warnings; | |
use ExtUtils::MakeMaker::Config; | |
require Exporter; | |
BEGIN { | |
# so we can compile the thing on non-VMS platforms. | |
if( $^O eq 'VMS' ) { | |
require VMS::Filespec; | |
VMS::Filespec->import; | |
} | |
} | |
use File::Basename; | |
our $VERSION = '7.62'; | |
$VERSION =~ tr/_//d; | |
require ExtUtils::MM_Any; | |
require ExtUtils::MM_Unix; | |
our @ISA = qw( ExtUtils::MM_Any ExtUtils::MM_Unix ); | |
use ExtUtils::MakeMaker qw($Verbose neatvalue _sprintf562); | |
our $Revision = $ExtUtils::MakeMaker::Revision; | |
=head1 NAME | |
ExtUtils::MM_VMS - methods to override UN*X behaviour in ExtUtils::MakeMaker | |
=head1 SYNOPSIS | |
Do not use this directly. | |
Instead, use ExtUtils::MM and it will figure out which MM_* | |
class to use for you. | |
=head1 DESCRIPTION | |
See L<ExtUtils::MM_Unix> for a documentation of the methods provided | |
there. This package overrides the implementation of these methods, not | |
the semantics. | |
=head2 Methods always loaded | |
=over 4 | |
=item wraplist | |
Converts a list into a string wrapped at approximately 80 columns. | |
=cut | |
sub wraplist { | |
my($self) = shift; | |
my($line,$hlen) = ('',0); | |
foreach my $word (@_) { | |
# Perl bug -- seems to occasionally insert extra elements when | |
# traversing array (scalar(@array) doesn't show them, but | |
# foreach(@array) does) (5.00307) | |
next unless $word =~ /\w/; | |
$line .= ' ' if length($line); | |
if ($hlen > 80) { $line .= "\\\n\t"; $hlen = 0; } | |
$line .= $word; | |
$hlen += length($word) + 2; | |
} | |
$line; | |
} | |
# This isn't really an override. It's just here because ExtUtils::MM_VMS | |
# appears in @MM::ISA before ExtUtils::Liblist::Kid, so if there isn't an ext() | |
# in MM_VMS, then AUTOLOAD is called, and bad things happen. So, we just | |
# mimic inheritance here and hand off to ExtUtils::Liblist::Kid. | |
# XXX This hackery will die soon. --Schwern | |
sub ext { | |
require ExtUtils::Liblist::Kid; | |
goto &ExtUtils::Liblist::Kid::ext; | |
} | |
=back | |
=head2 Methods | |
Those methods which override default MM_Unix methods are marked | |
"(override)", while methods unique to MM_VMS are marked "(specific)". | |
For overridden methods, documentation is limited to an explanation | |
of why this method overrides the MM_Unix method; see the L<ExtUtils::MM_Unix> | |
documentation for more details. | |
=over 4 | |
=item guess_name (override) | |
Try to determine name of extension being built. We begin with the name | |
of the current directory. Since VMS filenames are case-insensitive, | |
however, we look for a F<.pm> file whose name matches that of the current | |
directory (presumably the 'main' F<.pm> file for this extension), and try | |
to find a C<package> statement from which to obtain the Mixed::Case | |
package name. | |
=cut | |
sub guess_name { | |
my($self) = @_; | |
my($defname,$defpm,@pm,%xs); | |
local *PM; | |
$defname = basename(fileify($ENV{'DEFAULT'})); | |
$defname =~ s![\d\-_]*\.dir.*$!!; # Clip off .dir;1 suffix, and package version | |
$defpm = $defname; | |
# Fallback in case for some reason a user has copied the files for an | |
# extension into a working directory whose name doesn't reflect the | |
# extension's name. We'll use the name of a unique .pm file, or the | |
# first .pm file with a matching .xs file. | |
if (not -e "${defpm}.pm") { | |
@pm = glob('*.pm'); | |
s/.pm$// for @pm; | |
if (@pm == 1) { ($defpm = $pm[0]) =~ s/.pm$//; } | |
elsif (@pm) { | |
%xs = map { s/.xs$//; ($_,1) } glob('*.xs'); ## no critic | |
if (keys %xs) { | |
foreach my $pm (@pm) { | |
$defpm = $pm, last if exists $xs{$pm}; | |
} | |
} | |
} | |
} | |
if (open(my $pm, '<', "${defpm}.pm")){ | |
while (<$pm>) { | |
if (/^\s*package\s+([^;]+)/i) { | |
$defname = $1; | |
last; | |
} | |
} | |
print "Warning (non-fatal): Couldn't find package name in ${defpm}.pm;\n\t", | |
"defaulting package name to $defname\n" | |
if eof($pm); | |
close $pm; | |
} | |
else { | |
print "Warning (non-fatal): Couldn't find ${defpm}.pm;\n\t", | |
"defaulting package name to $defname\n"; | |
} | |
$defname =~ s#[\d.\-_]+$##; | |
$defname; | |
} | |
=item find_perl (override) | |
Use VMS file specification syntax and CLI commands to find and | |
invoke Perl images. | |
=cut | |
sub find_perl { | |
my($self, $ver, $names, $dirs, $trace) = @_; | |
my($vmsfile,@sdirs,@snames,@cand); | |
my($rslt); | |
my($inabs) = 0; | |
local *TCF; | |
if( $self->{PERL_CORE} ) { | |
# Check in relative directories first, so we pick up the current | |
# version of Perl if we're running MakeMaker as part of the main build. | |
@sdirs = sort { my($absa) = $self->file_name_is_absolute($a); | |
my($absb) = $self->file_name_is_absolute($b); | |
if ($absa && $absb) { return $a cmp $b } | |
else { return $absa ? 1 : ($absb ? -1 : ($a cmp $b)); } | |
} @$dirs; | |
# Check miniperl before perl, and check names likely to contain | |
# version numbers before "generic" names, so we pick up an | |
# executable that's less likely to be from an old installation. | |
@snames = sort { my($ba) = $a =~ m!([^:>\]/]+)$!; # basename | |
my($bb) = $b =~ m!([^:>\]/]+)$!; | |
my($ahasdir) = (length($a) - length($ba) > 0); | |
my($bhasdir) = (length($b) - length($bb) > 0); | |
if ($ahasdir and not $bhasdir) { return 1; } | |
elsif ($bhasdir and not $ahasdir) { return -1; } | |
else { $bb =~ /\d/ <=> $ba =~ /\d/ | |
or substr($ba,0,1) cmp substr($bb,0,1) | |
or length($bb) <=> length($ba) } } @$names; | |
} | |
else { | |
@sdirs = @$dirs; | |
@snames = @$names; | |
} | |
# Image names containing Perl version use '_' instead of '.' under VMS | |
s/\.(\d+)$/_$1/ for @snames; | |
if ($trace >= 2){ | |
print "Looking for perl $ver by these names:\n"; | |
print "\t@snames,\n"; | |
print "in these dirs:\n"; | |
print "\t@sdirs\n"; | |
} | |
foreach my $dir (@sdirs){ | |
next unless defined $dir; # $self->{PERL_SRC} may be undefined | |
$inabs++ if $self->file_name_is_absolute($dir); | |
if ($inabs == 1) { | |
# We've covered relative dirs; everything else is an absolute | |
# dir (probably an installed location). First, we'll try | |
# potential command names, to see whether we can avoid a long | |
# MCR expression. | |
foreach my $name (@snames) { | |
push(@cand,$name) if $name =~ /^[\w\-\$]+$/; | |
} | |
$inabs++; # Should happen above in next $dir, but just in case... | |
} | |
foreach my $name (@snames){ | |
push @cand, ($name !~ m![/:>\]]!) ? $self->catfile($dir,$name) | |
: $self->fixpath($name,0); | |
} | |
} | |
foreach my $name (@cand) { | |
print "Checking $name\n" if $trace >= 2; | |
# If it looks like a potential command, try it without the MCR | |
if ($name =~ /^[\w\-\$]+$/) { | |
open(my $tcf, ">", "temp_mmvms.com") | |
or die('unable to open temp file'); | |
print $tcf "\$ set message/nofacil/nosever/noident/notext\n"; | |
print $tcf "\$ $name -e \"require $ver; print \"\"VER_OK\\n\"\"\"\n"; | |
close $tcf; | |
$rslt = `\@temp_mmvms.com` ; | |
unlink('temp_mmvms.com'); | |
if ($rslt =~ /VER_OK/) { | |
print "Using PERL=$name\n" if $trace; | |
return $name; | |
} | |
} | |
next unless $vmsfile = $self->maybe_command($name); | |
$vmsfile =~ s/;[\d\-]*$//; # Clip off version number; we can use a newer version as well | |
print "Executing $vmsfile\n" if ($trace >= 2); | |
open(my $tcf, '>', "temp_mmvms.com") | |
or die('unable to open temp file'); | |
print $tcf "\$ set message/nofacil/nosever/noident/notext\n"; | |
print $tcf "\$ mcr $vmsfile -e \"require $ver; print \"\"VER_OK\\n\"\"\" \n"; | |
close $tcf; | |
$rslt = `\@temp_mmvms.com`; | |
unlink('temp_mmvms.com'); | |
if ($rslt =~ /VER_OK/) { | |
print "Using PERL=MCR $vmsfile\n" if $trace; | |
return "MCR $vmsfile"; | |
} | |
} | |
print "Unable to find a perl $ver (by these names: @$names, in these dirs: @$dirs)\n"; | |
0; # false and not empty | |
} | |
=item _fixin_replace_shebang (override) | |
Helper routine for L<< MM->fixin()|ExtUtils::MM_Unix/fixin >>, overridden | |
because there's no such thing as an | |
actual shebang line that will be interpreted by the shell, so we just prepend | |
$Config{startperl} and preserve the shebang line argument for any switches it | |
may contain. | |
=cut | |
sub _fixin_replace_shebang { | |
my ( $self, $file, $line ) = @_; | |
my ( undef, $arg ) = split ' ', $line, 2; | |
return $Config{startperl} . "\n" . $Config{sharpbang} . "perl $arg\n"; | |
} | |
=item maybe_command (override) | |
Follows VMS naming conventions for executable files. | |
If the name passed in doesn't exactly match an executable file, | |
appends F<.Exe> (or equivalent) to check for executable image, and F<.Com> | |
to check for DCL procedure. If this fails, checks directories in DCL$PATH | |
and finally F<Sys$System:> for an executable file having the name specified, | |
with or without the F<.Exe>-equivalent suffix. | |
=cut | |
sub maybe_command { | |
my($self,$file) = @_; | |
return $file if -x $file && ! -d _; | |
my(@dirs) = (''); | |
my(@exts) = ('',$Config{'exe_ext'},'.exe','.com'); | |
if ($file !~ m![/:>\]]!) { | |
for (my $i = 0; defined $ENV{"DCL\$PATH;$i"}; $i++) { | |
my $dir = $ENV{"DCL\$PATH;$i"}; | |
$dir .= ':' unless $dir =~ m%[\]:]$%; | |
push(@dirs,$dir); | |
} | |
push(@dirs,'Sys$System:'); | |
foreach my $dir (@dirs) { | |
my $sysfile = "$dir$file"; | |
foreach my $ext (@exts) { | |
return $file if -x "$sysfile$ext" && ! -d _; | |
} | |
} | |
} | |
return 0; | |
} | |
=item pasthru (override) | |
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 { | |
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; | |
} | |
=item pm_to_blib (override) | |
VMS wants a dot in every file so we can't have one called 'pm_to_blib', | |
it becomes 'pm_to_blib.' and MMS/K isn't smart enough to know that when | |
you have a target called 'pm_to_blib' it should look for 'pm_to_blib.'. | |
So in VMS its pm_to_blib.ts. | |
=cut | |
sub pm_to_blib { | |
my $self = shift; | |
my $make = $self->SUPER::pm_to_blib; | |
$make =~ s{^pm_to_blib :}{pm_to_blib.ts :}m; | |
$make =~ s{\$\(TOUCH\) pm_to_blib}{\$(TOUCH) pm_to_blib.ts}; | |
$make = <<'MAKE' . $make; | |
# Dummy target to match Unix target name; we use pm_to_blib.ts as | |
# timestamp file to avoid repeated invocations under VMS | |
pm_to_blib : pm_to_blib.ts | |
$(NOECHO) $(NOOP) | |
MAKE | |
return $make; | |
} | |
=item perl_script (override) | |
If name passed in doesn't specify a readable file, appends F<.com> or | |
F<.pl> and tries again, since it's customary to have file types on all files | |
under VMS. | |
=cut | |
sub perl_script { | |
my($self,$file) = @_; | |
return $file if -r $file && ! -d _; | |
return "$file.com" if -r "$file.com"; | |
return "$file.pl" if -r "$file.pl"; | |
return ''; | |
} | |
=item replace_manpage_separator | |
Use as separator a character which is legal in a VMS-syntax file name. | |
=cut | |
sub replace_manpage_separator { | |
my($self,$man) = @_; | |
$man = unixify($man); | |
$man =~ s#/+#__#g; | |
$man; | |
} | |
=item init_DEST | |
(override) Because of the difficulty concatenating VMS filepaths we | |
must pre-expand the DEST* variables. | |
=cut | |
sub init_DEST { | |
my $self = shift; | |
$self->SUPER::init_DEST; | |
# Expand DEST variables. | |
foreach my $var ($self->installvars) { | |
my $destvar = 'DESTINSTALL'.$var; | |
$self->{$destvar} = $self->eliminate_macros($self->{$destvar}); | |
} | |
} | |
=item init_DIRFILESEP | |
No separator between a directory path and a filename on VMS. | |
=cut | |
sub init_DIRFILESEP { | |
my($self) = shift; | |
$self->{DIRFILESEP} = ''; | |
return 1; | |
} | |
=item init_main (override) | |
=cut | |
sub init_main { | |
my($self) = shift; | |
$self->SUPER::init_main; | |
$self->{DEFINE} ||= ''; | |
if ($self->{DEFINE} ne '') { | |
my(@terms) = split(/\s+/,$self->{DEFINE}); | |
my(@defs,@udefs); | |
foreach my $def (@terms) { | |
next unless $def; | |
my $targ = \@defs; | |
if ($def =~ s/^-([DU])//) { # If it was a Unix-style definition | |
$targ = \@udefs if $1 eq 'U'; | |
$def =~ s/='(.*)'$/=$1/; # then remove shell-protection '' | |
$def =~ s/^'(.*)'$/$1/; # from entire term or argument | |
} | |
if ($def =~ /=/) { | |
$def =~ s/"/""/g; # Protect existing " from DCL | |
$def = qq["$def"]; # and quote to prevent parsing of = | |
} | |
push @$targ, $def; | |
} | |
$self->{DEFINE} = ''; | |
if (@defs) { | |
$self->{DEFINE} = '/Define=(' . join(',',@defs) . ')'; | |
} | |
if (@udefs) { | |
$self->{DEFINE} .= '/Undef=(' . join(',',@udefs) . ')'; | |
} | |
} | |
} | |
=item init_tools (override) | |
Provide VMS-specific forms of various utility commands. | |
Sets DEV_NULL to nothing because I don't know how to do it on VMS. | |
Changes EQUALIZE_TIMESTAMP to set revision date of target file to | |
one second later than source file, since MMK interprets precisely | |
equal revision dates for a source and target file as a sign that the | |
target needs to be updated. | |
=cut | |
sub init_tools { | |
my($self) = @_; | |
$self->{NOOP} = 'Continue'; | |
$self->{NOECHO} ||= '@ '; | |
$self->{MAKEFILE} ||= $self->{FIRST_MAKEFILE} || 'Descrip.MMS'; | |
$self->{FIRST_MAKEFILE} ||= $self->{MAKEFILE}; | |
$self->{MAKE_APERL_FILE} ||= 'Makeaperl.MMS'; | |
$self->{MAKEFILE_OLD} ||= $self->eliminate_macros('$(FIRST_MAKEFILE)_old'); | |
# | |
# If an extension is not specified, then MMS/MMK assumes an | |
# an extension of .MMS. If there really is no extension, | |
# then a trailing "." needs to be appended to specify a | |
# a null extension. | |
# | |
$self->{MAKEFILE} .= '.' unless $self->{MAKEFILE} =~ m/\./; | |
$self->{FIRST_MAKEFILE} .= '.' unless $self->{FIRST_MAKEFILE} =~ m/\./; | |
$self->{MAKE_APERL_FILE} .= '.' unless $self->{MAKE_APERL_FILE} =~ m/\./; | |
$self->{MAKEFILE_OLD} .= '.' unless $self->{MAKEFILE_OLD} =~ m/\./; | |
$self->{MACROSTART} ||= '/Macro=('; | |
$self->{MACROEND} ||= ')'; | |
$self->{USEMAKEFILE} ||= '/Descrip='; | |
$self->{EQUALIZE_TIMESTAMP} ||= '$(ABSPERLRUN) -we "open F,qq{>>$ARGV[1]};close F;utime(0,(stat($ARGV[0]))[9]+1,$ARGV[1])"'; | |
$self->{MOD_INSTALL} ||= | |
$self->oneliner(<<'CODE', ['-MExtUtils::Install']); | |
install([ from_to => {split('\|', <STDIN>)}, verbose => '$(VERBINST)', uninstall_shadows => '$(UNINST)', dir_mode => '$(PERM_DIR)' ]); | |
CODE | |
$self->{UMASK_NULL} = '! '; | |
$self->SUPER::init_tools; | |
# Use the default shell | |
$self->{SHELL} ||= 'Posix'; | |
# Redirection on VMS goes before the command, not after as on Unix. | |
# $(DEV_NULL) is used once and its not worth going nuts over making | |
# it work. However, Unix's DEV_NULL is quite wrong for VMS. | |
$self->{DEV_NULL} = ''; | |
return; | |
} | |
=item init_platform (override) | |
Add PERL_VMS, MM_VMS_REVISION and MM_VMS_VERSION. | |
MM_VMS_REVISION is for backwards compatibility before MM_VMS had a | |
$VERSION. | |
=cut | |
sub init_platform { | |
my($self) = shift; | |
$self->{MM_VMS_REVISION} = $Revision; | |
$self->{MM_VMS_VERSION} = $VERSION; | |
$self->{PERL_VMS} = $self->catdir($self->{PERL_SRC}, 'VMS') | |
if $self->{PERL_SRC}; | |
} | |
=item platform_constants | |
=cut | |
sub platform_constants { | |
my($self) = shift; | |
my $make_frag = ''; | |
foreach my $macro (qw(PERL_VMS MM_VMS_REVISION MM_VMS_VERSION)) | |
{ | |
next unless defined $self->{$macro}; | |
$make_frag .= "$macro = $self->{$macro}\n"; | |
} | |
return $make_frag; | |
} | |
=item init_VERSION (override) | |
Override the *DEFINE_VERSION macros with VMS semantics. Translate the | |
MAKEMAKER filepath to VMS style. | |
=cut | |
sub init_VERSION { | |
my $self = shift; | |
$self->SUPER::init_VERSION; | |
$self->{DEFINE_VERSION} = '"$(VERSION_MACRO)=""$(VERSION)"""'; | |
$self->{XS_DEFINE_VERSION} = '"$(XS_VERSION_MACRO)=""$(XS_VERSION)"""'; | |
$self->{MAKEMAKER} = vmsify($INC{'ExtUtils/MakeMaker.pm'}); | |
} | |
=item constants (override) | |
Fixes up numerous file and directory macros to insure VMS syntax | |
regardless of input syntax. Also makes lists of files | |
comma-separated. | |
=cut | |
sub constants { | |
my($self) = @_; | |
# Be kind about case for pollution | |
for (@ARGV) { $_ = uc($_) if /POLLUTE/i; } | |
# Cleanup paths for directories in MMS macros. | |
foreach my $macro ( qw [ | |
INST_BIN INST_SCRIPT INST_LIB INST_ARCHLIB | |
PERL_LIB PERL_ARCHLIB PERL_ARCHLIBDEP | |
PERL_INC PERL_SRC ], | |
(map { 'INSTALL'.$_ } $self->installvars), | |
(map { 'DESTINSTALL'.$_ } $self->installvars) | |
) | |
{ | |
next unless defined $self->{$macro}; | |
next if $macro =~ /MAN/ && $self->{$macro} eq 'none'; | |
$self->{$macro} = $self->fixpath($self->{$macro},1); | |
} | |
# Cleanup paths for files in MMS macros. | |
foreach my $macro ( qw[LIBPERL_A FIRST_MAKEFILE MAKEFILE_OLD | |
MAKE_APERL_FILE MYEXTLIB] ) | |
{ | |
next unless defined $self->{$macro}; | |
$self->{$macro} = $self->fixpath($self->{$macro},0); | |
} | |
# Fixup files for MMS macros | |
# XXX is this list complete? | |
for my $macro (qw/ | |
FULLEXT VERSION_FROM | |
/ ) { | |
next unless defined $self->{$macro}; | |
$self->{$macro} = $self->fixpath($self->{$macro},0); | |
} | |
for my $macro (qw/ | |
OBJECT LDFROM | |
/ ) { | |
next unless defined $self->{$macro}; | |
# Must expand macros before splitting on unescaped whitespace. | |
$self->{$macro} = $self->eliminate_macros($self->{$macro}); | |
if ($self->{$macro} =~ /(?<!\^)\s/) { | |
$self->{$macro} =~ s/(\\)?\n+\s+/ /g; | |
$self->{$macro} = $self->wraplist( | |
map $self->fixpath($_,0), split /,?(?<!\^)\s+/, $self->{$macro} | |
); | |
} | |
else { | |
$self->{$macro} = $self->fixpath($self->{$macro},0); | |
} | |
} | |
for my $macro (qw/ XS MAN1PODS MAN3PODS PM /) { | |
# Where is the space coming from? --jhi | |
next unless $self ne " " && defined $self->{$macro}; | |
my %tmp = (); | |
for my $key (keys %{$self->{$macro}}) { | |
$tmp{$self->fixpath($key,0)} = | |
$self->fixpath($self->{$macro}{$key},0); | |
} | |
$self->{$macro} = \%tmp; | |
} | |
for my $macro (qw/ C O_FILES H /) { | |
next unless defined $self->{$macro}; | |
my @tmp = (); | |
for my $val (@{$self->{$macro}}) { | |
push(@tmp,$self->fixpath($val,0)); | |
} | |
$self->{$macro} = \@tmp; | |
} | |
# mms/k does not define a $(MAKE) macro. | |
$self->{MAKE} = '$(MMS)$(MMSQUALIFIERS)'; | |
return $self->SUPER::constants; | |
} | |
=item special_targets | |
Clear the default .SUFFIXES and put in our own list. | |
=cut | |
sub special_targets { | |
my $self = shift; | |
my $make_frag .= <<'MAKE_FRAG'; | |
.SUFFIXES : | |
.SUFFIXES : $(OBJ_EXT) .c .cpp .cxx .xs | |
MAKE_FRAG | |
return $make_frag; | |
} | |
=item cflags (override) | |
Bypass shell script and produce qualifiers for CC directly (but warn | |
user if a shell script for this extension exists). Fold multiple | |
/Defines into one, since some C compilers pay attention to only one | |
instance of this qualifier on the command line. | |
=cut | |
sub cflags { | |
my($self,$libperl) = @_; | |
my($quals) = $self->{CCFLAGS} || $Config{'ccflags'}; | |
my($definestr,$undefstr,$flagoptstr) = ('','',''); | |
my($incstr) = '/Include=($(PERL_INC)'; | |
my($name,$sys,@m); | |
( $name = $self->{NAME} . "_cflags" ) =~ s/:/_/g ; | |
print "Unix shell script ".$Config{"$self->{'BASEEXT'}_cflags"}. | |
" required to modify CC command for $self->{'BASEEXT'}\n" | |
if ($Config{$name}); | |
if ($quals =~ / -[DIUOg]/) { | |
while ($quals =~ / -([Og])(\d*)\b/) { | |
my($type,$lvl) = ($1,$2); | |
$quals =~ s/ -$type$lvl\b\s*//; | |
if ($type eq 'g') { $flagoptstr = '/NoOptimize'; } | |
else { $flagoptstr = '/Optimize' . (defined($lvl) ? "=$lvl" : ''); } | |
} | |
while ($quals =~ / -([DIU])(\S+)/) { | |
my($type,$def) = ($1,$2); | |
$quals =~ s/ -$type$def\s*//; | |
$def =~ s/"/""/g; | |
if ($type eq 'D') { $definestr .= qq["$def",]; } | |
elsif ($type eq 'I') { $incstr .= ',' . $self->fixpath($def,1); } | |
else { $undefstr .= qq["$def",]; } | |
} | |
} | |
if (length $quals and $quals !~ m!/!) { | |
warn "MM_VMS: Ignoring unrecognized CCFLAGS elements \"$quals\"\n"; | |
$quals = ''; | |
} | |
$definestr .= q["PERL_POLLUTE",] if $self->{POLLUTE}; | |
if (length $definestr) { chop($definestr); $quals .= "/Define=($definestr)"; } | |
if (length $undefstr) { chop($undefstr); $quals .= "/Undef=($undefstr)"; } | |
# Deal with $self->{DEFINE} here since some C compilers pay attention | |
# to only one /Define clause on command line, so we have to | |
# conflate the ones from $Config{'ccflags'} and $self->{DEFINE} | |
# ($self->{DEFINE} has already been VMSified in constants() above) | |
if ($self->{DEFINE}) { $quals .= $self->{DEFINE}; } | |
for my $type (qw(Def Undef)) { | |
my(@terms); | |
while ($quals =~ m:/${type}i?n?e?=([^/]+):ig) { | |
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; | |
# PASTHRU_DEFINE will have its own comma | |
$quals .= "/${type}ine=(" . join(',',@terms) . ($type eq 'Def' ? '$(PASTHRU_DEFINE)' : '') . ')'; | |
} | |
} | |
$libperl or $libperl = $self->{LIBPERL_A} || "libperl.olb"; | |
# Likewise with $self->{INC} and /Include | |
if ($self->{'INC'}) { | |
my(@includes) = split(/\s+/,$self->{INC}); | |
foreach (@includes) { | |
s/^-I//; | |
$incstr .= ','.$self->fixpath($_,1); | |
} | |
} | |
$quals .= "$incstr)"; | |
# $quals =~ s/,,/,/g; $quals =~ s/\(,/(/g; | |
$self->{CCFLAGS} = $quals; | |
$self->{PERLTYPE} ||= ''; | |
$self->{OPTIMIZE} ||= $flagoptstr || $Config{'optimize'}; | |
if ($self->{OPTIMIZE} !~ m!/!) { | |
if ($self->{OPTIMIZE} =~ m!-g!) { $self->{OPTIMIZE} = '/Debug/NoOptimize' } | |
elsif ($self->{OPTIMIZE} =~ /-O(\d*)/) { | |
$self->{OPTIMIZE} = '/Optimize' . (defined($1) ? "=$1" : ''); | |
} | |
else { | |
warn "MM_VMS: Can't parse OPTIMIZE \"$self->{OPTIMIZE}\"; using default\n" if length $self->{OPTIMIZE}; | |
$self->{OPTIMIZE} = '/Optimize'; | |
} | |
} | |
return $self->{CFLAGS} = qq{ | |
CCFLAGS = $self->{CCFLAGS} | |
OPTIMIZE = $self->{OPTIMIZE} | |
PERLTYPE = $self->{PERLTYPE} | |
}; | |
} | |
=item const_cccmd (override) | |
Adds directives to point C preprocessor to the right place when | |
handling #include E<lt>sys/foo.hE<gt> directives. Also constructs CC | |
command line a bit differently than MM_Unix method. | |
=cut | |
sub const_cccmd { | |
my($self,$libperl) = @_; | |
my(@m); | |
return $self->{CONST_CCCMD} if $self->{CONST_CCCMD}; | |
return '' unless $self->needs_linking(); | |
if ($Config{'vms_cc_type'} eq 'gcc') { | |
push @m,' | |
.FIRST | |
',$self->{NOECHO},'If F$TrnLnm("Sys").eqs."" Then Define/NoLog SYS GNU_CC_Include:[VMS]'; | |
} | |
elsif ($Config{'vms_cc_type'} eq 'vaxc') { | |
push @m,' | |
.FIRST | |
',$self->{NOECHO},'If F$TrnLnm("Sys").eqs."" .and. F$TrnLnm("VAXC$Include").eqs."" Then Define/NoLog SYS Sys$Library | |
',$self->{NOECHO},'If F$TrnLnm("Sys").eqs."" .and. F$TrnLnm("VAXC$Include").nes."" Then Define/NoLog SYS VAXC$Include'; | |
} | |
else { | |
push @m,' | |
.FIRST | |
',$self->{NOECHO},'If F$TrnLnm("Sys").eqs."" .and. F$TrnLnm("DECC$System_Include").eqs."" Then Define/NoLog SYS ', | |
($Config{'archname'} eq 'VMS_AXP' ? 'Sys$Library' : 'DECC$Library_Include'),' | |
',$self->{NOECHO},'If F$TrnLnm("Sys").eqs."" .and. F$TrnLnm("DECC$System_Include").nes."" Then Define/NoLog SYS DECC$System_Include'; | |
} | |
push(@m, "\n\nCCCMD = $Config{'cc'} \$(CCFLAGS)\$(OPTIMIZE)\n"); | |
$self->{CONST_CCCMD} = join('',@m); | |
} | |
=item tools_other (override) | |
Throw in some dubious extra macros for Makefile args. | |
Also keep around the old $(SAY) macro in case somebody's using it. | |
=cut | |
sub tools_other { | |
my($self) = @_; | |
# XXX Are these necessary? Does anyone override them? They're longer | |
# than just typing the literal string. | |
my $extra_tools = <<'EXTRA_TOOLS'; | |
# Just in case anyone is using the old macro. | |
USEMACROS = $(MACROSTART) | |
SAY = $(ECHO) | |
EXTRA_TOOLS | |
return $self->SUPER::tools_other . $extra_tools; | |
} | |
=item init_dist (override) | |
VMSish defaults for some values. | |
macro description default | |
ZIPFLAGS flags to pass to ZIP -Vu | |
COMPRESS compression command to gzip | |
use for tarfiles | |
SUFFIX suffix to put on -gz | |
compressed files | |
SHAR shar command to use vms_share | |
DIST_DEFAULT default target to use to tardist | |
create a distribution | |
DISTVNAME Use VERSION_SYM instead of $(DISTNAME)-$(VERSION_SYM) | |
VERSION for the name | |
=cut | |
sub init_dist { | |
my($self) = @_; | |
$self->{ZIPFLAGS} ||= '-Vu'; | |
$self->{COMPRESS} ||= 'gzip'; | |
$self->{SUFFIX} ||= '-gz'; | |
$self->{SHAR} ||= 'vms_share'; | |
$self->{DIST_DEFAULT} ||= 'zipdist'; | |
$self->SUPER::init_dist; | |
$self->{DISTVNAME} = "$self->{DISTNAME}-$self->{VERSION_SYM}" | |
unless $self->{ARGS}{DISTVNAME}; | |
return; | |
} | |
=item c_o (override) | |
Use VMS syntax on command line. In particular, $(DEFINE) and | |
$(PERL_INC) have been pulled into $(CCCMD). Also use MM[SK] macros. | |
=cut | |
sub c_o { | |
my($self) = @_; | |
return '' unless $self->needs_linking(); | |
' | |
.c$(OBJ_EXT) : | |
$(CCCMD) $(CCCDLFLAGS) $(MMS$TARGET_NAME).c /OBJECT=$(MMS$TARGET_NAME)$(OBJ_EXT) | |
.cpp$(OBJ_EXT) : | |
$(CCCMD) $(CCCDLFLAGS) $(MMS$TARGET_NAME).cpp /OBJECT=$(MMS$TARGET_NAME)$(OBJ_EXT) | |
.cxx$(OBJ_EXT) : | |
$(CCCMD) $(CCCDLFLAGS) $(MMS$TARGET_NAME).cxx /OBJECT=$(MMS$TARGET_NAME)$(OBJ_EXT) | |
'; | |
} | |
=item xs_c (override) | |
Use MM[SK] macros. | |
=cut | |
sub xs_c { | |
my($self) = @_; | |
return '' unless $self->needs_linking(); | |
' | |
.xs.c : | |
$(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $(MMS$TARGET_NAME).xs >$(MMS$TARGET_NAME).xsc | |
$(MV) $(MMS$TARGET_NAME).xsc $(MMS$TARGET_NAME).c | |
'; | |
} | |
=item xs_o (override) | |
Use MM[SK] macros, and VMS command line for C compiler. | |
=cut | |
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).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) | |
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. | |
=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 _xsbuild_value { | |
my ($self, $xstype, $ext, $varname) = @_; | |
$ext = unixify($ext); | |
return $self->SUPER::_xsbuild_value($xstype, $ext, $varname); | |
} | |
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 @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; | |
} | |
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) . ')'; | |
} | |
return $flags; | |
} | |
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 @m, '\n$(INST_ARCHAUTODIR)' . $olb_base . '$(LIB_EXT)/Library\n"";" >>$(MMS$TARGET)',"\n"; | |
} | |
if (length $self->{LDLOADLIBS}) { | |
my($line) = ''; | |
foreach my $lib (split ' ', $self->{LDLOADLIBS}) { | |
$lib =~ s%\$%\\\$%g; # Escape '$' in VMS filespecs | |
if (length($line) + length($lib) > 160) { | |
push @m, "\t\$(PERL) -e \"print qq{$line}\" >>\$(MMS\$TARGET)\n"; | |
$line = $lib . '\n'; | |
} | |
else { $line .= $lib . '\n'; } | |
} | |
push @m, "\t\$(PERL) -e \"print qq{$line}\" >>\$(MMS\$TARGET)\n" if $line; | |
} | |
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) | |
Use VMS Link command. | |
=cut | |
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 | |
} | |
sub xs_make_dynamic_lib { | |
my ($self, $attribs, $from, $to, $todir, $ldfrom, $exportlist) = @_; | |
my $shr = $Config{'dbgprefix'} . 'PerlShr'; | |
$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 xs_make_static_lib (override) | |
Use VMS commands to manipulate object library. | |
=cut | |
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; | |
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)); | |
# 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}; | |
push(@m,"\t",'If F$Search("$(MMS$TARGET)").eqs."" Then Library/Object/Create $(MMS$TARGET)',"\n"); | |
# if there was a library to copy, then we can't use MMS$SOURCE_LIST, | |
# '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}) { | |
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"); | |
} | |
push @m, "\t\$(NOECHO) \$(PERL) -e 1 >\$(INST_ARCHAUTODIR)extralibs.ld\n"; | |
foreach my $lib (split ' ', $self->{EXTRALIBS}) { | |
push(@m,"\t",'$(NOECHO) $(PERL) -e "print qq{',$lib,'\n}" >>$(INST_ARCHAUTODIR)extralibs.ld',"\n"); | |
} | |
join('',@m); | |
} | |
=item static_lib_pure_cmd (override) | |
Use VMS commands to manipulate object library. | |
=cut | |
sub static_lib_pure_cmd { | |
my ($self, $from) = @_; | |
sprintf <<'MAKE_FRAG', $from; | |
If F$Search("$(MMS$TARGET)").eqs."" Then Library/Object/Create $(MMS$TARGET) | |
Library/Object/Replace $(MMS$TARGET) %s | |
MAKE_FRAG | |
} | |
=item xs_static_lib_is_xs | |
=cut | |
sub xs_static_lib_is_xs { | |
return 1; | |
} | |
=item extra_clean_files | |
Clean up some OS specific files. Plus the temp file used to shorten | |
a lot of commands. And the name mangler database. | |
=cut | |
sub extra_clean_files { | |
return qw( | |
*.Map *.Dmp *.Lis *.cpp *.$(DLEXT) *.Opt $(BASEEXT).bso | |
.MM_Tmp cxx_repository | |
); | |
} | |
=item zipfile_target | |
=item tarfile_target | |
=item shdist_target | |
Syntax for invoking shar, tar and zip differs from that for Unix. | |
=cut | |
sub zipfile_target { | |
my($self) = shift; | |
return <<'MAKE_FRAG'; | |
$(DISTVNAME).zip : distdir | |
$(PREOP) | |
$(ZIP) "$(ZIPFLAGS)" $(MMS$TARGET) [.$(DISTVNAME)...]*.*; | |
$(RM_RF) $(DISTVNAME) | |
$(POSTOP) | |
MAKE_FRAG | |
} | |
sub tarfile_target { | |
my($self) = shift; | |
return <<'MAKE_FRAG'; | |
$(DISTVNAME).tar$(SUFFIX) : distdir | |
$(PREOP) | |
$(TO_UNIX) | |
$(TAR) "$(TARFLAGS)" $(DISTVNAME).tar [.$(DISTVNAME)...] | |
$(RM_RF) $(DISTVNAME) | |
$(COMPRESS) $(DISTVNAME).tar | |
$(POSTOP) | |
MAKE_FRAG | |
} | |
sub shdist_target { | |
my($self) = shift; | |
return <<'MAKE_FRAG'; | |
shdist : distdir | |
$(PREOP) | |
$(SHAR) [.$(DISTVNAME)...]*.*; $(DISTVNAME).share | |
$(RM_RF) $(DISTVNAME) | |
$(POSTOP) | |
MAKE_FRAG | |
} | |
# --- Test and Installation Sections --- | |
=item install (override) | |
Work around DCL's 255 character limit several times,and use | |
VMS-style command line quoting in a few cases. | |
=cut | |
sub install { | |
my($self, %attribs) = @_; | |
my(@m); | |
push @m, q[ | |
install :: all pure_install doc_install | |
$(NOECHO) $(NOOP) | |
install_perl :: all pure_perl_install doc_perl_install | |
$(NOECHO) $(NOOP) | |
install_site :: all pure_site_install doc_site_install | |
$(NOECHO) $(NOOP) | |
install_vendor :: all pure_vendor_install doc_vendor_install | |
$(NOECHO) $(NOOP) | |
pure_install :: pure_$(INSTALLDIRS)_install | |
$(NOECHO) $(NOOP) | |
doc_install :: doc_$(INSTALLDIRS)_install | |
$(NOECHO) $(NOOP) | |
pure__install : pure_site_install | |
$(NOECHO) $(ECHO) "INSTALLDIRS not defined, defaulting to INSTALLDIRS=site" | |
doc__install : doc_site_install | |
$(NOECHO) $(ECHO) "INSTALLDIRS not defined, defaulting to INSTALLDIRS=site" | |
# This hack brought to you by DCL's 255-character command line limit | |
pure_perl_install :: | |
]; | |
push @m, | |
q[ $(NOECHO) $(PERLRUN) "-MFile::Spec" -e "print 'read|'.File::Spec->catfile('$(PERL_ARCHLIB)','auto','$(FULLEXT)','.packlist').'|'" >.MM_tmp | |
$(NOECHO) $(PERLRUN) "-MFile::Spec" -e "print 'write|'.File::Spec->catfile('$(DESTINSTALLARCHLIB)','auto','$(FULLEXT)','.packlist').'|'" >>.MM_tmp | |
] unless $self->{NO_PACKLIST}; | |
push @m, | |
q[ $(NOECHO) $(ECHO_N) "$(INST_LIB)|$(DESTINSTALLPRIVLIB)|" >>.MM_tmp | |
$(NOECHO) $(ECHO_N) "$(INST_ARCHLIB)|$(DESTINSTALLARCHLIB)|" >>.MM_tmp | |
$(NOECHO) $(ECHO_N) "$(INST_BIN)|$(DESTINSTALLBIN)|" >>.MM_tmp | |
$(NOECHO) $(ECHO_N) "$(INST_SCRIPT)|$(DESTINSTALLSCRIPT)|" >>.MM_tmp | |
$(NOECHO) $(ECHO_N) "$(INST_MAN1DIR) $(DESTINSTALLMAN1DIR) " >>.MM_tmp | |
$(NOECHO) $(ECHO_N) "$(INST_MAN3DIR)|$(DESTINSTALLMAN3DIR)" >>.MM_tmp | |
$(NOECHO) $(MOD_INSTALL) <.MM_tmp | |
$(NOECHO) $(RM_F) .MM_tmp | |
$(NOECHO) $(WARN_IF_OLD_PACKLIST) "].$self->catfile($self->{SITEARCHEXP},'auto',$self->{FULLEXT},'.packlist').q[" | |
# Likewise | |
pure_site_install :: | |
]; | |
push @m, | |
q[ $(NOECHO) $(PERLRUN) "-MFile::Spec" -e "print 'read|'.File::Spec->catfile('$(SITEARCHEXP)','auto','$(FULLEXT)','.packlist').'|'" >.MM_tmp | |
$(NOECHO) $(PERLRUN) "-MFile::Spec" -e "print 'write|'.File::Spec->catfile('$(DESTINSTALLSITEARCH)','auto','$(FULLEXT)','.packlist').'|'" >>.MM_tmp | |
] unless $self->{NO_PACKLIST}; | |
push @m, | |
q[ $(NOECHO) $(ECHO_N) "$(INST_LIB)|$(DESTINSTALLSITELIB)|" >>.MM_tmp | |
$(NOECHO) $(ECHO_N) "$(INST_ARCHLIB)|$(DESTINSTALLSITEARCH)|" >>.MM_tmp | |
$(NOECHO) $(ECHO_N) "$(INST_BIN)|$(DESTINSTALLSITEBIN)|" >>.MM_tmp | |
$(NOECHO) $(ECHO_N) "$(INST_SCRIPT)|$(DESTINSTALLSCRIPT)|" >>.MM_tmp | |
$(NOECHO) $(ECHO_N) "$(INST_MAN1DIR)|$(DESTINSTALLSITEMAN1DIR)|" >>.MM_tmp | |
$(NOECHO) $(ECHO_N) "$(INST_MAN3DIR)|$(DESTINSTALLSITEMAN3DIR)" >>.MM_tmp | |
$(NOECHO) $(MOD_INSTALL) <.MM_tmp | |
$(NOECHO) $(RM_F) .MM_tmp | |
$(NOECHO) $(WARN_IF_OLD_PACKLIST) "].$self->catfile($self->{PERL_ARCHLIB},'auto',$self->{FULLEXT},'.packlist').q[" | |
pure_vendor_install :: | |
]; | |
push @m, | |
q[ $(NOECHO) $(PERLRUN) "-MFile::Spec" -e "print 'read|'.File::Spec->catfile('$(VENDORARCHEXP)','auto','$(FULLEXT)','.packlist').'|'" >.MM_tmp | |
$(NOECHO) $(PERLRUN) "-MFile::Spec" -e "print 'write|'.File::Spec->catfile('$(DESTINSTALLVENDORARCH)','auto','$(FULLEXT)','.packlist').'|'" >>.MM_tmp | |
] unless $self->{NO_PACKLIST}; | |
push @m, | |
q[ $(NOECHO) $(ECHO_N) "$(INST_LIB)|$(DESTINSTALLVENDORLIB)|" >>.MM_tmp | |
$(NOECHO) $(ECHO_N) "$(INST_ARCHLIB)|$(DESTINSTALLVENDORARCH)|" >>.MM_tmp | |
$(NOECHO) $(ECHO_N) "$(INST_BIN)|$(DESTINSTALLVENDORBIN)|" >>.MM_tmp | |
$(NOECHO) $(ECHO_N) "$(INST_SCRIPT)|$(DESTINSTALLSCRIPT)|" >>.MM_tmp | |
$(NOECHO) $(ECHO_N) "$(INST_MAN1DIR)|$(DESTINSTALLVENDORMAN1DIR)|" >>.MM_tmp | |
$(NOECHO) $(ECHO_N) "$(INST_MAN3DIR)|$(DESTINSTALLVENDORMAN3DIR)" >>.MM_tmp | |
$(NOECHO) $(MOD_INSTALL) <.MM_tmp | |
$(NOECHO) $(RM_F) .MM_tmp | |
]; | |
push @m, q[ | |
# Ditto | |
doc_perl_install :: | |
$(NOECHO) $(NOOP) | |
# And again | |
doc_site_install :: | |
$(NOECHO) $(NOOP) | |
doc_vendor_install :: | |
$(NOECHO) $(NOOP) | |
] if $self->{NO_PERLLOCAL}; | |
push @m, q[ | |
# Ditto | |
doc_perl_install :: | |
$(NOECHO) $(ECHO) "Appending installation info to ].$self->catfile($self->{DESTINSTALLARCHLIB}, 'perllocal.pod').q[" | |
$(NOECHO) $(MKPATH) $(DESTINSTALLARCHLIB) | |
$(NOECHO) $(ECHO_N) "installed into|$(INSTALLPRIVLIB)|" >.MM_tmp | |
$(NOECHO) $(ECHO_N) "LINKTYPE|$(LINKTYPE)|VERSION|$(VERSION)|EXE_FILES|$(EXE_FILES) " >>.MM_tmp | |
$(NOECHO) $(DOC_INSTALL) "Module" "$(NAME)" <.MM_tmp >>].$self->catfile($self->{DESTINSTALLARCHLIB},'perllocal.pod').q[ | |
$(NOECHO) $(RM_F) .MM_tmp | |
# And again | |
doc_site_install :: | |
$(NOECHO) $(ECHO) "Appending installation info to ].$self->catfile($self->{DESTINSTALLARCHLIB}, 'perllocal.pod').q[" | |
$(NOECHO) $(MKPATH) $(DESTINSTALLARCHLIB) | |
$(NOECHO) $(ECHO_N) "installed into|$(INSTALLSITELIB)|" >.MM_tmp | |
$(NOECHO) $(ECHO_N) "LINKTYPE|$(LINKTYPE)|VERSION|$(VERSION)|EXE_FILES|$(EXE_FILES) " >>.MM_tmp | |
$(NOECHO) $(DOC_INSTALL) "Module" "$(NAME)" <.MM_tmp >>].$self->catfile($self->{DESTINSTALLARCHLIB},'perllocal.pod').q[ | |
$(NOECHO) $(RM_F) .MM_tmp | |
doc_vendor_install :: | |
$(NOECHO) $(ECHO) "Appending installation info to ].$self->catfile($self->{DESTINSTALLARCHLIB}, 'perllocal.pod').q[" | |
$(NOECHO) $(MKPATH) $(DESTINSTALLARCHLIB) | |
$(NOECHO) $(ECHO_N) "installed into|$(INSTALLVENDORLIB)|" >.MM_tmp | |
$(NOECHO) $(ECHO_N) "LINKTYPE|$(LINKTYPE)|VERSION|$(VERSION)|EXE_FILES|$(EXE_FILES) " >>.MM_tmp | |
$(NOECHO) $(DOC_INSTALL) "Module" "$(NAME)" <.MM_tmp >>].$self->catfile($self->{DESTINSTALLARCHLIB},'perllocal.pod').q[ | |
$(NOECHO) $(RM_F) .MM_tmp | |
] unless $self->{NO_PERLLOCAL}; | |
push @m, q[ | |
uninstall :: uninstall_from_$(INSTALLDIRS)dirs | |
$(NOECHO) $(NOOP) | |
uninstall_from_perldirs :: | |
$(NOECHO) $(UNINSTALL) ].$self->catfile($self->{PERL_ARCHLIB},'auto',$self->{FULLEXT},'.packlist').q[ | |
uninstall_from_sitedirs :: | |
$(NOECHO) $(UNINSTALL) ].$self->catfile($self->{SITEARCHEXP},'auto',$self->{FULLEXT},'.packlist').q[ | |
uninstall_from_vendordirs :: | |
$(NOECHO) $(UNINSTALL) ].$self->catfile($self->{VENDORARCHEXP},'auto',$self->{FULLEXT},'.packlist').q[ | |
]; | |
join('',@m); | |
} | |
=item perldepend (override) | |
Use VMS-style syntax for files; it's cheaper to just do it directly here | |
than to have the L<MM_Unix|ExtUtils::MM_Unix> method call C<catfile> | |
repeatedly. Also, if we have to rebuild Config.pm, use MM[SK] to do it. | |
=cut | |
sub perldepend { | |
my($self) = @_; | |
my(@m); | |
if ($self->{OBJECT}) { | |
# Need to add an object file dependency on the perl headers. | |
# this is very important for XS modules in perl.git development. | |
push @m, $self->_perl_header_files_fragment(""); # empty separator on VMS as its in the $(PERL_INC) | |
} | |
if ($self->{PERL_SRC}) { | |
my(@macros); | |
my($mmsquals) = '$(USEMAKEFILE)[.vms]$(FIRST_MAKEFILE)'; | |
push(@macros,'__AXP__=1') if $Config{'archname'} eq 'VMS_AXP'; | |
push(@macros,'DECC=1') if $Config{'vms_cc_type'} eq 'decc'; | |
push(@macros,'GNUC=1') if $Config{'vms_cc_type'} eq 'gcc'; | |
push(@macros,'SOCKET=1') if $Config{'d_has_sockets'}; | |
push(@macros,qq["CC=$Config{'cc'}"]) if $Config{'cc'} =~ m!/!; | |
$mmsquals .= '$(USEMACROS)' . join(',',@macros) . '$(MACROEND)' if @macros; | |
push(@m,q[ | |
# Check for unpropagated config.sh changes. Should never happen. | |
# We do NOT just update config.h because that is not sufficient. | |
# An out of date config.h is not fatal but complains loudly! | |
$(PERL_INC)config.h : $(PERL_SRC)config.sh | |
$(NOOP) | |
$(PERL_ARCHLIB)Config.pm : $(PERL_SRC)config.sh | |
$(NOECHO) Write Sys$Error "$(PERL_ARCHLIB)Config.pm may be out of date with config.h or genconfig.pl" | |
olddef = F$Environment("Default") | |
Set Default $(PERL_SRC) | |
$(MMS)],$mmsquals,); | |
if ($self->{PERL_ARCHLIB} =~ m|\[-| && $self->{PERL_SRC} =~ m|(\[-+)|) { | |
my($prefix,$target) = ($1,$self->fixpath('$(PERL_ARCHLIB)Config.pm',0)); | |
$target =~ s/\Q$prefix/[/; | |
push(@m," $target"); | |
} | |
else { push(@m,' $(MMS$TARGET)'); } | |
push(@m,q[ | |
Set Default 'olddef' | |
]); | |
} | |
push(@m, join(" ", map($self->fixpath($_,0),sort values %{$self->{XS}}))." : \$(XSUBPPDEPS)\n") | |
if %{$self->{XS}}; | |
join('',@m); | |
} | |
=item makeaperl (override) | |
Undertake to build a new set of Perl images using VMS commands. Since | |
VMS does dynamic loading, it's not necessary to statically link each | |
extension into the Perl image, so this isn't the normal build path. | |
Consequently, it hasn't really been tested, and may well be incomplete. | |
=cut | |
our %olbs; # needs to be localized | |
sub makeaperl { | |
my($self, %attribs) = @_; | |
my($makefilename, $searchdirs, $static, $extra, $perlinc, $target, $tmpdir, $libperl) = | |
@attribs{qw(MAKE DIRS STAT EXTRA INCL TARGET TMP LIBPERL)}; | |
my(@m); | |
push @m, " | |
# --- MakeMaker makeaperl section --- | |
MAP_TARGET = $target | |
"; | |
return join '', @m if $self->{PARENT}; | |
my($dir) = join ":", @{$self->{DIR}}; | |
unless ($self->{MAKEAPERL}) { | |
push @m, q{ | |
$(MAKE_APERL_FILE) : $(FIRST_MAKEFILE) | |
$(NOECHO) $(ECHO) "Writing ""$(MMS$TARGET)"" for this $(MAP_TARGET)" | |
$(NOECHO) $(PERLRUNINST) \ | |
Makefile.PL DIR=}, $dir, q{ \ | |
FIRST_MAKEFILE=$(MAKE_APERL_FILE) LINKTYPE=static \ | |
MAKEAPERL=1 NORECURS=1 }; | |
push @m, map(q[ \\\n\t\t"$_"], @ARGV),q{ | |
$(MAP_TARGET) :: $(MAKE_APERL_FILE) | |
$(MAKE)$(USEMAKEFILE)$(MAKE_APERL_FILE) static $(MMS$TARGET) | |
}; | |
push @m, "\n"; | |
return join '', @m; | |
} | |
my($linkcmd,@optlibs,@staticpkgs,$extralist,$targdir,$libperldir,%libseen); | |
local($_); | |
# The front matter of the linkcommand... | |
$linkcmd = join ' ', $Config{'ld'}, | |
grep($_, @Config{qw(large split ldflags ccdlflags)}); | |
$linkcmd =~ s/\s+/ /g; | |
# Which *.olb files could we make use of... | |
local(%olbs); # XXX can this be lexical? | |
$olbs{$self->{INST_ARCHAUTODIR}} = "$self->{BASEEXT}\$(LIB_EXT)"; | |
require File::Find; | |
File::Find::find(sub { | |
return unless m/\Q$self->{LIB_EXT}\E$/; | |
return if m/^libperl/; | |
if( exists $self->{INCLUDE_EXT} ){ | |
my $found = 0; | |
(my $xx = $File::Find::name) =~ s,.*?/auto/,,; | |
$xx =~ s,/?$_,,; | |
$xx =~ s,/,::,g; | |
# Throw away anything not explicitly marked for inclusion. | |
# DynaLoader is implied. | |
foreach my $incl ((@{$self->{INCLUDE_EXT}},'DynaLoader')){ | |
if( $xx eq $incl ){ | |
$found++; | |
last; | |
} | |
} | |
return unless $found; | |
} | |
elsif( exists $self->{EXCLUDE_EXT} ){ | |
(my $xx = $File::Find::name) =~ s,.*?/auto/,,; | |
$xx =~ s,/?$_,,; | |
$xx =~ s,/,::,g; | |
# Throw away anything explicitly marked for exclusion | |
foreach my $excl (@{$self->{EXCLUDE_EXT}}){ | |
return if( $xx eq $excl ); | |
} | |
} | |
$olbs{$ENV{DEFAULT}} = $_; | |
}, grep( -d $_, @{$searchdirs || []})); | |
# We trust that what has been handed in as argument will be buildable | |
$static = [] unless $static; | |
@olbs{@{$static}} = (1) x @{$static}; | |
$extra = [] unless $extra && ref $extra eq 'ARRAY'; | |
# Sort the object libraries in inverse order of | |
# filespec length to try to insure that dependent extensions | |
# will appear before their parents, so the linker will | |
# search the parent library to resolve references. | |
# (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) || $a cmp $b } keys %olbs) { | |
next unless $olbs{$_} =~ /\Q$self->{LIB_EXT}\E$/; | |
my($dir) = $self->fixpath($_,1); | |
my($extralibs) = $dir . "extralibs.ld"; | |
my($extopt) = $dir . $olbs{$_}; | |
$extopt =~ s/$self->{LIB_EXT}$/.opt/; | |
push @optlibs, "$dir$olbs{$_}"; | |
# Get external libraries this extension will need | |
if (-f $extralibs ) { | |
my %seenthis; | |
open my $list, "<", $extralibs or warn $!,next; | |
while (<$list>) { | |
chomp; | |
# Include a library in the link only once, unless it's mentioned | |
# multiple times within a single extension's options file, in which | |
# case we assume the builder needed to search it again later in the | |
# link. | |
my $skip = exists($libseen{$_}) && !exists($seenthis{$_}); | |
$libseen{$_}++; $seenthis{$_}++; | |
next if $skip; | |
push @$extra,$_; | |
} | |
} | |
# Get full name of extension for ExtUtils::Miniperl | |
if (-f $extopt) { | |
open my $opt, '<', $extopt or die $!; | |
while (<$opt>) { | |
next unless /(?:UNIVERSAL|VECTOR)=boot_([\w_]+)/; | |
my $pkg = $1; | |
$pkg =~ s#__*#::#g; | |
push @staticpkgs,$pkg; | |
} | |
} | |
} | |
# Place all of the external libraries after all of the Perl extension | |
# libraries in the final link, in order to maximize the opportunity | |
# for XS code from multiple extensions to resolve symbols against the | |
# same external library while only including that library once. | |
push @optlibs, @$extra; | |
$target = "Perl$Config{'exe_ext'}" unless $target; | |
my $shrtarget; | |
($shrtarget,$targdir) = fileparse($target); | |
$shrtarget =~ s/^([^.]*)/$1Shr/; | |
$shrtarget = $targdir . $shrtarget; | |
$target = "Perlshr.$Config{'dlext'}" unless $target; | |
$tmpdir = "[]" unless $tmpdir; | |
$tmpdir = $self->fixpath($tmpdir,1); | |
if (@optlibs) { $extralist = join(' ',@optlibs); } | |
else { $extralist = ''; } | |
# Let ExtUtils::Liblist find the necessary libs for us (but skip PerlShr) | |
# that's what we're building here). | |
push @optlibs, grep { !/PerlShr/i } split ' ', +($self->ext())[2]; | |
if ($libperl) { | |
unless (-f $libperl || -f ($libperl = $self->catfile($Config{'installarchlib'},'CORE',$libperl))) { | |
print "Warning: $libperl not found\n"; | |
undef $libperl; | |
} | |
} | |
unless ($libperl) { | |
if (defined $self->{PERL_SRC}) { | |
$libperl = $self->catfile($self->{PERL_SRC},"libperl$self->{LIB_EXT}"); | |
} elsif (-f ($libperl = $self->catfile($Config{'installarchlib'},'CORE',"libperl$self->{LIB_EXT}")) ) { | |
} else { | |
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"; | |
} | |
} | |
$libperldir = $self->fixpath((fileparse($libperl))[1],1); | |
push @m, ' | |
# Fill in the target you want to produce if it\'s not perl | |
MAP_TARGET = ',$self->fixpath($target,0),' | |
MAP_SHRTARGET = ',$self->fixpath($shrtarget,0)," | |
MAP_LINKCMD = $linkcmd | |
MAP_PERLINC = ", $perlinc ? map('"$_" ',@{$perlinc}) : ''," | |
MAP_EXTRA = $extralist | |
MAP_LIBPERL = ",$self->fixpath($libperl,0),' | |
'; | |
push @m,"\n${tmpdir}Makeaperl.Opt : \$(MAP_EXTRA)\n"; | |
foreach (@optlibs) { | |
push @m,' $(NOECHO) $(PERL) -e "print q{',$_,'}" >>$(MMS$TARGET)',"\n"; | |
} | |
push @m,"\n${tmpdir}PerlShr.Opt :\n\t"; | |
push @m,'$(NOECHO) $(PERL) -e "print q{$(MAP_SHRTARGET)}" >$(MMS$TARGET)',"\n"; | |
push @m,' | |
$(MAP_SHRTARGET) : $(MAP_LIBPERL) Makeaperl.Opt ',"${libperldir}Perlshr_Attr.Opt",' | |
$(MAP_LINKCMD)/Shareable=$(MMS$TARGET) $(MAP_LIBPERL), Makeaperl.Opt/Option ',"${libperldir}Perlshr_Attr.Opt/Option",' | |
$(MAP_TARGET) : $(MAP_SHRTARGET) ',"${tmpdir}perlmain\$(OBJ_EXT) ${tmpdir}PerlShr.Opt",' | |
$(MAP_LINKCMD) ',"${tmpdir}perlmain\$(OBJ_EXT)",', PerlShr.Opt/Option | |
$(NOECHO) $(ECHO) "To install the new ""$(MAP_TARGET)"" binary, say" | |
$(NOECHO) $(ECHO) " $(MAKE)$(USEMAKEFILE)$(FIRST_MAKEFILE) inst_perl $(USEMACROS)MAP_TARGET=$(MAP_TARGET)$(ENDMACRO)" | |
$(NOECHO) $(ECHO) "To remove the intermediate files, say | |
$(NOECHO) $(ECHO) " $(MAKE)$(USEMAKEFILE)$(FIRST_MAKEFILE) map_clean" | |
'; | |
push @m,"\n${tmpdir}perlmain.c : \$(FIRST_MAKEFILE)\n\t\$(NOECHO) \$(PERL) -e 1 >${tmpdir}Writemain.tmp\n"; | |
push @m, "# More from the 255-char line length limit\n"; | |
foreach (@staticpkgs) { | |
push @m,' $(NOECHO) $(PERL) -e "print q{',$_,qq[}" >>${tmpdir}Writemain.tmp\n]; | |
} | |
push @m, sprintf <<'MAKE_FRAG', $tmpdir, $tmpdir; | |
$(NOECHO) $(PERL) $(MAP_PERLINC) -ane "use ExtUtils::Miniperl; writemain(@F)" %sWritemain.tmp >$(MMS$TARGET) | |
$(NOECHO) $(RM_F) %sWritemain.tmp | |
MAKE_FRAG | |
push @m, q[ | |
# Still more from the 255-char line length limit | |
doc_inst_perl : | |
$(NOECHO) $(MKPATH) $(DESTINSTALLARCHLIB) | |
$(NOECHO) $(ECHO) "Perl binary $(MAP_TARGET)|" >.MM_tmp | |
$(NOECHO) $(ECHO) "MAP_STATIC|$(MAP_STATIC)|" >>.MM_tmp | |
$(NOECHO) $(PERL) -pl040 -e " " ].$self->catfile('$(INST_ARCHAUTODIR)','extralibs.all'),q[ >>.MM_tmp | |
$(NOECHO) $(ECHO) -e "MAP_LIBPERL|$(MAP_LIBPERL)|" >>.MM_tmp | |
$(NOECHO) $(DOC_INSTALL) <.MM_tmp >>].$self->catfile('$(DESTINSTALLARCHLIB)','perllocal.pod').q[ | |
$(NOECHO) $(RM_F) .MM_tmp | |
]; | |
push @m, " | |
inst_perl : pure_inst_perl doc_inst_perl | |
\$(NOECHO) \$(NOOP) | |
pure_inst_perl : \$(MAP_TARGET) | |
$self->{CP} \$(MAP_SHRTARGET) ",$self->fixpath($Config{'installbin'},1)," | |
$self->{CP} \$(MAP_TARGET) ",$self->fixpath($Config{'installbin'},1)," | |
clean :: map_clean | |
\$(NOECHO) \$(NOOP) | |
map_clean : | |
\$(RM_F) ${tmpdir}perlmain\$(OBJ_EXT) ${tmpdir}perlmain.c \$(FIRST_MAKEFILE) | |
\$(RM_F) ${tmpdir}Makeaperl.Opt ${tmpdir}PerlShr.Opt \$(MAP_TARGET) | |
"; | |
join '', @m; | |
} | |
# --- Output postprocessing section --- | |
=item maketext_filter (override) | |
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. | |
=cut | |
sub maketext_filter { | |
my($self, $text) = @_; | |
$text =~ s/^([^\s:=]+)(:+\s)/$1 $2/mg; | |
return $text; | |
} | |
=item prefixify (override) | |
prefixifying on VMS is simple. Each should simply be: | |
perl_root:[some.dir] | |
which can just be converted to: | |
volume:[your.prefix.some.dir] | |
otherwise you get the default layout. | |
In effect, your search prefix is ignored and $Config{vms_prefix} is | |
used instead. | |
=cut | |
sub prefixify { | |
my($self, $var, $sprefix, $rprefix, $default) = @_; | |
# Translate $(PERLPREFIX) to a real path. | |
$rprefix = $self->eliminate_macros($rprefix); | |
$rprefix = vmspath($rprefix) if $rprefix; | |
$sprefix = vmspath($sprefix) if $sprefix; | |
$default = vmsify($default) | |
unless $default =~ /\[.*\]/; | |
(my $var_no_install = $var) =~ s/^install//; | |
my $path = $self->{uc $var} || | |
$ExtUtils::MM_Unix::Config_Override{lc $var} || | |
$Config{lc $var} || $Config{lc $var_no_install}; | |
if( !$path ) { | |
warn " no Config found for $var.\n" if $Verbose >= 2; | |
$path = $self->_prefixify_default($rprefix, $default); | |
} | |
elsif( !$self->{ARGS}{PREFIX} || !$self->file_name_is_absolute($path) ) { | |
# do nothing if there's no prefix or if its relative | |
} | |
elsif( $sprefix eq $rprefix ) { | |
warn " no new prefix.\n" if $Verbose >= 2; | |
} | |
else { | |
warn " prefixify $var => $path\n" if $Verbose >= 2; | |
warn " from $sprefix to $rprefix\n" if $Verbose >= 2; | |
my($path_vol, $path_dirs) = $self->splitpath( $path ); | |
if( $path_vol eq $Config{vms_prefix}.':' ) { | |
warn " $Config{vms_prefix}: seen\n" if $Verbose >= 2; | |
$path_dirs =~ s{^\[}{\[.} unless $path_dirs =~ m{^\[\.}; | |
$path = $self->_catprefix($rprefix, $path_dirs); | |
} | |
else { | |
$path = $self->_prefixify_default($rprefix, $default); | |
} | |
} | |
print " now $path\n" if $Verbose >= 2; | |
return $self->{uc $var} = $path; | |
} | |
sub _prefixify_default { | |
my($self, $rprefix, $default) = @_; | |
warn " cannot prefix, using default.\n" if $Verbose >= 2; | |
if( !$default ) { | |
warn "No default!\n" if $Verbose >= 1; | |
return; | |
} | |
if( !$rprefix ) { | |
warn "No replacement prefix!\n" if $Verbose >= 1; | |
return ''; | |
} | |
return $self->_catprefix($rprefix, $default); | |
} | |
sub _catprefix { | |
my($self, $rprefix, $default) = @_; | |
my($rvol, $rdirs) = $self->splitpath($rprefix); | |
if( $rvol ) { | |
return $self->catpath($rvol, | |
$self->catdir($rdirs, $default), | |
'' | |
) | |
} | |
else { | |
return $self->catdir($rdirs, $default); | |
} | |
} | |
=item cd | |
=cut | |
sub cd { | |
my($self, $dir, @cmds) = @_; | |
$dir = vmspath($dir); | |
my $cmd = join "\n\t", map "$_", @cmds; | |
# No leading tab makes it look right when embedded | |
my $make_frag = sprintf <<'MAKE_FRAG', $dir, $cmd; | |
startdir = F$Environment("Default") | |
Set Default %s | |
%s | |
Set Default 'startdir' | |
MAKE_FRAG | |
# No trailing newline makes this easier to embed | |
chomp $make_frag; | |
return $make_frag; | |
} | |
=item oneliner | |
=cut | |
sub oneliner { | |
my($self, $cmd, $switches) = @_; | |
$switches = [] unless defined $switches; | |
# Strip leading and trailing newlines | |
$cmd =~ s{^\n+}{}; | |
$cmd =~ s{\n+$}{}; | |
my @cmds = split /\n/, $cmd; | |
$cmd = join " \n\t -e ", map $self->quote_literal($_), @cmds; | |
$cmd = $self->escape_newlines($cmd); | |
# Switches must be quoted else they will be lowercased. | |
$switches = join ' ', map { qq{"$_"} } @$switches; | |
return qq{\$(ABSPERLRUN) $switches -e $cmd "--"}; | |
} | |
=item B<echo> | |
perl trips up on "<foo>" thinking it's an input redirect. So we use the | |
native Write command instead. Besides, it's faster. | |
=cut | |
sub echo { | |
my($self, $text, $file, $opts) = @_; | |
# Compatibility with old options | |
if( !ref $opts ) { | |
my $append = $opts; | |
$opts = { append => $append || 0 }; | |
} | |
my $opencmd = $opts->{append} ? 'Open/Append' : 'Open/Write'; | |
$opts->{allow_variables} = 0 unless defined $opts->{allow_variables}; | |
my $ql_opts = { allow_variables => $opts->{allow_variables} }; | |
my @cmds = ("\$(NOECHO) $opencmd MMECHOFILE $file "); | |
push @cmds, map { '$(NOECHO) Write MMECHOFILE '.$self->quote_literal($_, $ql_opts) } | |
split /\n/, $text; | |
push @cmds, '$(NOECHO) Close MMECHOFILE'; | |
return @cmds; | |
} | |
=item quote_literal | |
=cut | |
sub quote_literal { | |
my($self, $text, $opts) = @_; | |
$opts->{allow_variables} = 1 unless defined $opts->{allow_variables}; | |
# I believe this is all we should need. | |
$text =~ s{"}{""}g; | |
$text = $opts->{allow_variables} | |
? $self->escape_dollarsigns($text) : $self->escape_all_dollarsigns($text); | |
return qq{"$text"}; | |
} | |
=item escape_dollarsigns | |
Quote, don't escape. | |
=cut | |
sub escape_dollarsigns { | |
my($self, $text) = @_; | |
# Quote dollar signs which are not starting a variable | |
$text =~ s{\$ (?!\() }{"\$"}gx; | |
return $text; | |
} | |
=item escape_all_dollarsigns | |
Quote, don't escape. | |
=cut | |
sub escape_all_dollarsigns { | |
my($self, $text) = @_; | |
# Quote dollar signs | |
$text =~ s{\$}{"\$\"}gx; | |
return $text; | |
} | |
=item escape_newlines | |
=cut | |
sub escape_newlines { | |
my($self, $text) = @_; | |
$text =~ s{\n}{-\n}g; | |
return $text; | |
} | |
=item max_exec_len | |
256 characters. | |
=cut | |
sub max_exec_len { | |
my $self = shift; | |
return $self->{_MAX_EXEC_LEN} ||= 256; | |
} | |
=item init_linker | |
=cut | |
sub init_linker { | |
my $self = shift; | |
$self->{EXPORT_LIST} ||= '$(BASEEXT).opt'; | |
my $shr = $Config{dbgprefix} . 'PERLSHR'; | |
if ($self->{PERL_SRC}) { | |
$self->{PERL_ARCHIVE} ||= | |
$self->catfile($self->{PERL_SRC}, "$shr.$Config{'dlext'}"); | |
} | |
else { | |
$self->{PERL_ARCHIVE} ||= | |
$ENV{$shr} ? $ENV{$shr} : "Sys\$Share:$shr.$Config{'dlext'}"; | |
} | |
$self->{PERL_ARCHIVEDEP} ||= ''; | |
$self->{PERL_ARCHIVE_AFTER} ||= ''; | |
} | |
=item catdir (override) | |
=item catfile (override) | |
Eliminate the macros in the output to the MMS/MMK file. | |
(L<File::Spec::VMS> used to do this for us, but it's being removed) | |
=cut | |
sub catdir { | |
my $self = shift; | |
# Process the macros on VMS MMS/MMK | |
my @args = map { m{\$\(} ? $self->eliminate_macros($_) : $_ } @_; | |
my $dir = $self->SUPER::catdir(@args); | |
# Fix up the directory and force it to VMS format. | |
$dir = $self->fixpath($dir, 1); | |
return $dir; | |
} | |
sub catfile { | |
my $self = shift; | |
# Process the macros on VMS MMS/MMK | |
my @args = map { m{\$\(} ? $self->eliminate_macros($_) : $_ } @_; | |
my $file = $self->SUPER::catfile(@args); | |
$file = vmsify($file); | |
return $file | |
} | |
=item eliminate_macros | |
Expands MM[KS]/Make macros in a text string, using the contents of | |
identically named elements of C<%$self>, and returns the result | |
as a file specification in Unix syntax. | |
NOTE: This is the canonical version of the method. The version in | |
L<File::Spec::VMS> is deprecated. | |
=cut | |
sub eliminate_macros { | |
my($self,$path) = @_; | |
return '' unless $path; | |
$self = {} unless ref $self; | |
my($npath) = unixify($path); | |
# sometimes unixify will return a string with an off-by-one trailing null | |
$npath =~ s{\0$}{}; | |
my($complex) = 0; | |
my($head,$macro,$tail); | |
# perform m##g in scalar context so it acts as an iterator | |
while ($npath =~ m#(.*?)\$\((\S+?)\)(.*)#gs) { | |
if (defined $self->{$2}) { | |
($head,$macro,$tail) = ($1,$2,$3); | |
if (ref $self->{$macro}) { | |
if (ref $self->{$macro} eq 'ARRAY') { | |
$macro = join ' ', @{$self->{$macro}}; | |
} | |
else { | |
print "Note: can't expand macro \$($macro) containing ",ref($self->{$macro}), | |
"\n\t(using MMK-specific deferred substitutuon; MMS will break)\n"; | |
$macro = "\cB$macro\cB"; | |
$complex = 1; | |
} | |
} | |
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"; | |
} | |
} | |
if ($complex) { $npath =~ s#\cB(.*?)\cB#\${$1}#gs; } | |
$npath; | |
} | |
=item fixpath | |
my $path = $mm->fixpath($path); | |
my $path = $mm->fixpath($path, $is_dir); | |
Catchall routine to clean up problem MM[SK]/Make macros. Expands macros | |
in any directory specification, in order to avoid juxtaposing two | |
VMS-syntax directories when MM[SK] is run. Also expands expressions which | |
are all macro, so that we can tell how long the expansion is, and avoid | |
overrunning DCL's command buffer when MM[KS] is running. | |
fixpath() checks to see whether the result matches the name of a | |
directory in the current default directory and returns a directory or | |
file specification accordingly. C<$is_dir> can be set to true to | |
force fixpath() to consider the path to be a directory or false to force | |
it to be a file. | |
NOTE: This is the canonical version of the method. The version in | |
L<File::Spec::VMS> is deprecated. | |
=cut | |
sub fixpath { | |
my($self,$path,$force_path) = @_; | |
return '' unless $path; | |
$self = bless {}, $self unless ref $self; | |
my($fixedpath,$prefix,$name); | |
if ($path =~ m#^\$\([^\)]+\)\Z(?!\n)#s || $path =~ m#[/:>\]]#) { | |
if ($force_path or $path =~ /(?:DIR\)|\])\Z(?!\n)/) { | |
$fixedpath = vmspath($self->eliminate_macros($path)); | |
} | |
else { | |
$fixedpath = vmsify($self->eliminate_macros($path)); | |
} | |
} | |
elsif ((($prefix,$name) = ($path =~ m#^\$\(([^\)]+)\)(.+)#s)) && $self->{$prefix}) { | |
my($vmspre) = $self->eliminate_macros("\$($prefix)"); | |
# is it a dir or just a name? | |
$vmspre = ($vmspre =~ m|/| or $prefix =~ /DIR\Z(?!\n)/) ? vmspath($vmspre) : ''; | |
$fixedpath = ($vmspre ? $vmspre : $self->{$prefix}) . $name; | |
$fixedpath = vmspath($fixedpath) if $force_path; | |
} | |
else { | |
$fixedpath = $path; | |
$fixedpath = vmspath($fixedpath) if $force_path; | |
} | |
# No hints, so we try to guess | |
if (!defined($force_path) and $fixedpath !~ /[:>(.\]]/) { | |
$fixedpath = vmspath($fixedpath) if -d $fixedpath; | |
} | |
# Trim off root dirname if it's had other dirs inserted in front of it. | |
$fixedpath =~ s/\.000000([\]>])/$1/; | |
# Special case for VMS absolute directory specs: these will have had device | |
# prepended during trip through Unix syntax in eliminate_macros(), since | |
# Unix syntax has no way to express "absolute from the top of this device's | |
# directory tree". | |
if ($path =~ /^[\[>][^.\-]/) { $fixedpath =~ s/^[^\[<]+//; } | |
return $fixedpath; | |
} | |
=item os_flavor | |
VMS is VMS. | |
=cut | |
sub os_flavor { | |
return('VMS'); | |
} | |
=item is_make_type (override) | |
None of the make types being checked for is viable on VMS, | |
plus our $self->{MAKE} is an unexpanded (and unexpandable) | |
macro whose value is known only to the make utility itself. | |
=cut | |
sub is_make_type { | |
my($self, $type) = @_; | |
return 0; | |
} | |
=item make_type (override) | |
Returns a suitable string describing the type of makefile being written. | |
=cut | |
sub make_type { "$Config{make}-style"; } | |
=back | |
=head1 AUTHOR | |
Original author Charles Bailey F<[email protected]> | |
Maintained by Michael G Schwern F<[email protected]> | |
See L<ExtUtils::MakeMaker> for patching and contact information. | |
=cut | |
1; | |