Spaces:
Running
Running
package ExtUtils::MM_Any; | |
use strict; | |
use warnings; | |
our $VERSION = '7.62'; | |
$VERSION =~ tr/_//d; | |
use Carp; | |
use File::Spec; | |
use File::Basename; | |
BEGIN { our @ISA = qw(File::Spec); } | |
# We need $Verbose | |
use ExtUtils::MakeMaker qw($Verbose neatvalue _sprintf562); | |
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 $Updir = __PACKAGE__->updir; | |
my $METASPEC_URL = 'https://metacpan.org/pod/CPAN::Meta::Spec'; | |
my $METASPEC_V = 2; | |
=head1 NAME | |
ExtUtils::MM_Any - Platform-agnostic MM methods | |
=head1 SYNOPSIS | |
FOR INTERNAL USE ONLY! | |
package ExtUtils::MM_SomeOS; | |
# Temporarily, you have to subclass both. Put MM_Any first. | |
require ExtUtils::MM_Any; | |
require ExtUtils::MM_Unix; | |
@ISA = qw(ExtUtils::MM_Any ExtUtils::Unix); | |
=head1 DESCRIPTION | |
B<FOR INTERNAL USE ONLY!> | |
ExtUtils::MM_Any is a superclass for the ExtUtils::MM_* set of | |
modules. It contains methods which are either inherently | |
cross-platform or are written in a cross-platform manner. | |
Subclass off of ExtUtils::MM_Any I<and> L<ExtUtils::MM_Unix>. This is a | |
temporary solution. | |
B<THIS MAY BE TEMPORARY!> | |
=head1 METHODS | |
Any methods marked I<Abstract> must be implemented by subclasses. | |
=head2 Cross-platform helper methods | |
These are methods which help writing cross-platform code. | |
=head3 os_flavor I<Abstract> | |
my @os_flavor = $mm->os_flavor; | |
@os_flavor is the style of operating system this is, usually | |
corresponding to the MM_*.pm file we're using. | |
The first element of @os_flavor is the major family (ie. Unix, | |
Windows, VMS, OS/2, etc...) and the rest are sub families. | |
Some examples: | |
Cygwin98 ('Unix', 'Cygwin', 'Cygwin9x') | |
Windows ('Win32') | |
Win98 ('Win32', 'Win9x') | |
Linux ('Unix', 'Linux') | |
MacOS X ('Unix', 'Darwin', 'MacOS', 'MacOS X') | |
OS/2 ('OS/2') | |
This is used to write code for styles of operating system. | |
See os_flavor_is() for use. | |
=head3 os_flavor_is | |
my $is_this_flavor = $mm->os_flavor_is($this_flavor); | |
my $is_this_flavor = $mm->os_flavor_is(@one_of_these_flavors); | |
Checks to see if the current operating system is one of the given flavors. | |
This is useful for code like: | |
if( $mm->os_flavor_is('Unix') ) { | |
$out = `foo 2>&1`; | |
} | |
else { | |
$out = `foo`; | |
} | |
=cut | |
sub os_flavor_is { | |
my $self = shift; | |
my %flavors = map { ($_ => 1) } $self->os_flavor; | |
return (grep { $flavors{$_} } @_) ? 1 : 0; | |
} | |
=head3 can_load_xs | |
my $can_load_xs = $self->can_load_xs; | |
Returns true if we have the ability to load XS. | |
This is important because miniperl, used to build XS modules in the | |
core, can not load XS. | |
=cut | |
sub can_load_xs { | |
return defined &DynaLoader::boot_DynaLoader ? 1 : 0; | |
} | |
=head3 can_run | |
use ExtUtils::MM; | |
my $runnable = MM->can_run($Config{make}); | |
If called in a scalar context it will return the full path to the binary | |
you asked for if it was found, or C<undef> if it was not. | |
If called in a list context, it will return a list of the full paths to instances | |
of the binary where found in C<PATH>, or an empty list if it was not found. | |
Copied from L<IPC::Cmd|IPC::Cmd/"$path = can_run( PROGRAM );">, but modified into | |
a method (and removed C<$INSTANCES> capability). | |
=cut | |
sub can_run { | |
my ($self, $command) = @_; | |
# a lot of VMS executables have a symbol defined | |
# check those first | |
if ( $^O eq 'VMS' ) { | |
require VMS::DCLsym; | |
my $syms = VMS::DCLsym->new; | |
return $command if scalar $syms->getsym( uc $command ); | |
} | |
my @possibles; | |
if( File::Spec->file_name_is_absolute($command) ) { | |
return $self->maybe_command($command); | |
} else { | |
for my $dir ( | |
File::Spec->path, | |
File::Spec->curdir | |
) { | |
next if ! $dir || ! -d $dir; | |
my $abs = File::Spec->catfile($self->os_flavor_is('Win32') ? Win32::GetShortPathName( $dir ) : $dir, $command); | |
push @possibles, $abs if $abs = $self->maybe_command($abs); | |
} | |
} | |
return @possibles if wantarray; | |
return shift @possibles; | |
} | |
=head3 can_redirect_error | |
$useredirect = MM->can_redirect_error; | |
True if on an OS where qx operator (or backticks) can redirect C<STDERR> | |
onto C<STDOUT>. | |
=cut | |
sub can_redirect_error { | |
my $self = shift; | |
$self->os_flavor_is('Unix') | |
or ($self->os_flavor_is('Win32') and !$self->os_flavor_is('Win9x')) | |
or $self->os_flavor_is('OS/2') | |
} | |
=head3 is_make_type | |
my $is_dmake = $self->is_make_type('dmake'); | |
Returns true if C<< $self->make >> is the given type; possibilities are: | |
gmake GNU make | |
dmake | |
nmake | |
bsdmake BSD pmake-derived | |
=cut | |
my %maketype2true; | |
# undocumented - so t/cd.t can still do its thing | |
sub _clear_maketype_cache { %maketype2true = () } | |
sub is_make_type { | |
my($self, $type) = @_; | |
return $maketype2true{$type} if defined $maketype2true{$type}; | |
(undef, undef, my $make_basename) = $self->splitpath($self->make); | |
return $maketype2true{$type} = 1 | |
if $make_basename =~ /\b$type\b/i; # executable's filename | |
return $maketype2true{$type} = 0 | |
if $make_basename =~ /\b[gdn]make\b/i; # Never fall through for dmake/nmake/gmake | |
# now have to run with "-v" and guess | |
my $redirect = $self->can_redirect_error ? '2>&1' : ''; | |
my $make = $self->make || $self->{MAKE}; | |
my $minus_v = `"$make" -v $redirect`; | |
return $maketype2true{$type} = 1 | |
if $type eq 'gmake' and $minus_v =~ /GNU make/i; | |
return $maketype2true{$type} = 1 | |
if $type eq 'bsdmake' | |
and $minus_v =~ /^usage: make \[-BeikNnqrstWwX\]/im; | |
$maketype2true{$type} = 0; # it wasn't whatever you asked | |
} | |
=head3 can_dep_space | |
my $can_dep_space = $self->can_dep_space; | |
Returns true if C<make> can handle (probably by quoting) | |
dependencies that contain a space. Currently known true for GNU make, | |
false for BSD pmake derivative. | |
=cut | |
my $cached_dep_space; | |
sub can_dep_space { | |
my $self = shift; | |
return $cached_dep_space if defined $cached_dep_space; | |
return $cached_dep_space = 1 if $self->is_make_type('gmake'); | |
return $cached_dep_space = 0 if $self->is_make_type('dmake'); # only on W32 | |
return $cached_dep_space = 0 if $self->is_make_type('bsdmake'); | |
return $cached_dep_space = 0; # assume no | |
} | |
=head3 quote_dep | |
$text = $mm->quote_dep($text); | |
Method that protects Makefile single-value constants (mainly filenames), | |
so that make will still treat them as single values even if they | |
inconveniently have spaces in. If the make program being used cannot | |
achieve such protection and the given text would need it, throws an | |
exception. | |
=cut | |
sub quote_dep { | |
my ($self, $arg) = @_; | |
die <<EOF if $arg =~ / / and not $self->can_dep_space; | |
Tried to use make dependency with space for make that can't: | |
'$arg' | |
EOF | |
$arg =~ s/( )/\\$1/g; # how GNU make does it | |
return $arg; | |
} | |
=head3 split_command | |
my @cmds = $MM->split_command($cmd, @args); | |
Most OS have a maximum command length they can execute at once. Large | |
modules can easily generate commands well past that limit. Its | |
necessary to split long commands up into a series of shorter commands. | |
C<split_command> will return a series of @cmds each processing part of | |
the args. Collectively they will process all the arguments. Each | |
individual line in @cmds will not be longer than the | |
$self->max_exec_len being careful to take into account macro expansion. | |
$cmd should include any switches and repeated initial arguments. | |
If no @args are given, no @cmds will be returned. | |
Pairs of arguments will always be preserved in a single command, this | |
is a heuristic for things like pm_to_blib and pod2man which work on | |
pairs of arguments. This makes things like this safe: | |
$self->split_command($cmd, %pod2man); | |
=cut | |
sub split_command { | |
my($self, $cmd, @args) = @_; | |
my @cmds = (); | |
return(@cmds) unless @args; | |
# If the command was given as a here-doc, there's probably a trailing | |
# newline. | |
chomp $cmd; | |
# set aside 30% for macro expansion. | |
my $len_left = int($self->max_exec_len * 0.70); | |
$len_left -= length $self->_expand_macros($cmd); | |
do { | |
my $arg_str = ''; | |
my @next_args; | |
while( @next_args = splice(@args, 0, 2) ) { | |
# Two at a time to preserve pairs. | |
my $next_arg_str = "\t ". join ' ', @next_args, "\n"; | |
if( !length $arg_str ) { | |
$arg_str .= $next_arg_str | |
} | |
elsif( length($arg_str) + length($next_arg_str) > $len_left ) { | |
unshift @args, @next_args; | |
last; | |
} | |
else { | |
$arg_str .= $next_arg_str; | |
} | |
} | |
chop $arg_str; | |
push @cmds, $self->escape_newlines("$cmd \n$arg_str"); | |
} while @args; | |
return @cmds; | |
} | |
sub _expand_macros { | |
my($self, $cmd) = @_; | |
$cmd =~ s{\$\((\w+)\)}{ | |
defined $self->{$1} ? $self->{$1} : "\$($1)" | |
}e; | |
return $cmd; | |
} | |
=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); | |
my @commands = $MM->echo($text, $file); | |
my @commands = $MM->echo($text, $file, \%opts); | |
Generates a set of @commands which print the $text to a $file. | |
If $file is not given, output goes to STDOUT. | |
If $opts{append} is true the $file will be appended to rather than | |
overwritten. Default is to overwrite. | |
If $opts{allow_variables} is true, make variables of the form | |
C<$(...)> will not be escaped. Other C<$> will. Default is to escape | |
all C<$>. | |
Example of use: | |
my $make = join '', map "\t$_\n", $MM->echo($text, $file); | |
=cut | |
sub echo { | |
my($self, $text, $file, $opts) = @_; | |
# Compatibility with old options | |
if( !ref $opts ) { | |
my $append = $opts; | |
$opts = { append => $append || 0 }; | |
} | |
$opts->{allow_variables} = 0 unless defined $opts->{allow_variables}; | |
my $ql_opts = { allow_variables => $opts->{allow_variables} }; | |
my @cmds = map { '$(NOECHO) $(ECHO) '.$self->quote_literal($_, $ql_opts) } | |
split /\n/, $text; | |
if( $file ) { | |
my $redirect = $opts->{append} ? '>>' : '>'; | |
$cmds[0] .= " $redirect $file"; | |
$_ .= " >> $file" foreach @cmds[1..$#cmds]; | |
} | |
return @cmds; | |
} | |
=head3 wraplist | |
my $args = $mm->wraplist(@list); | |
Takes an array of items and turns them into a well-formatted list of | |
arguments. In most cases this is simply something like: | |
FOO \ | |
BAR \ | |
BAZ | |
=cut | |
sub wraplist { | |
my $self = shift; | |
return join " \\\n\t", @_; | |
} | |
=head3 maketext_filter | |
my $filter_make_text = $mm->maketext_filter($make_text); | |
The text of the Makefile is run through this method before writing to | |
disk. It allows systems a chance to make portability fixes to the | |
Makefile. | |
By default it does nothing. | |
This method is protected and not intended to be called outside of | |
MakeMaker. | |
=cut | |
sub maketext_filter { return $_[1] } | |
=head3 cd I<Abstract> | |
my $subdir_cmd = $MM->cd($subdir, @cmds); | |
This will generate a make fragment which runs the @cmds in the given | |
$dir. The rough equivalent to this, except cross platform. | |
cd $subdir && $cmd | |
Currently $dir can only go down one level. "foo" is fine. "foo/bar" is | |
not. "../foo" is right out. | |
The resulting $subdir_cmd has no leading tab nor trailing newline. This | |
makes it easier to embed in a make string. For example. | |
my $make = sprintf <<'CODE', $subdir_cmd; | |
foo : | |
$(ECHO) what | |
%s | |
$(ECHO) mouche | |
CODE | |
=head3 oneliner I<Abstract> | |
my $oneliner = $MM->oneliner($perl_code); | |
my $oneliner = $MM->oneliner($perl_code, \@switches); | |
This will generate a perl one-liner safe for the particular platform | |
you're on based on the given $perl_code and @switches (a -e is | |
assumed) suitable for using in a make target. It will use the proper | |
shell quoting and escapes. | |
$(PERLRUN) will be used as perl. | |
Any newlines in $perl_code will be escaped. Leading and trailing | |
newlines will be stripped. Makes this idiom much easier: | |
my $code = $MM->oneliner(<<'CODE', [...switches...]); | |
some code here | |
another line here | |
CODE | |
Usage might be something like: | |
# an echo emulation | |
$oneliner = $MM->oneliner('print "Foo\n"'); | |
$make = '$oneliner > somefile'; | |
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)"'); | |
Its currently very simple and may be expanded sometime in the figure | |
to include more flexible code and switches. | |
=head3 quote_literal I<Abstract> | |
my $safe_text = $MM->quote_literal($text); | |
my $safe_text = $MM->quote_literal($text, \%options); | |
This will quote $text so it is interpreted literally in the shell. | |
For example, on Unix this would escape any single-quotes in $text and | |
put single-quotes around the whole thing. | |
If $options{allow_variables} is true it will leave C<'$(FOO)'> make | |
variables untouched. If false they will be escaped like any other | |
C<$>. Defaults to true. | |
=head3 escape_dollarsigns | |
my $escaped_text = $MM->escape_dollarsigns($text); | |
Escapes stray C<$> so they are not interpreted as make variables. | |
It lets by C<$(...)>. | |
=cut | |
sub escape_dollarsigns { | |
my($self, $text) = @_; | |
# Escape dollar signs which are not starting a variable | |
$text =~ s{\$ (?!\() }{\$\$}gx; | |
return $text; | |
} | |
=head3 escape_all_dollarsigns | |
my $escaped_text = $MM->escape_all_dollarsigns($text); | |
Escapes all C<$> so they are not interpreted as make variables. | |
=cut | |
sub escape_all_dollarsigns { | |
my($self, $text) = @_; | |
# Escape dollar signs | |
$text =~ s{\$}{\$\$}gx; | |
return $text; | |
} | |
=head3 escape_newlines I<Abstract> | |
my $escaped_text = $MM->escape_newlines($text); | |
Shell escapes newlines in $text. | |
=head3 max_exec_len I<Abstract> | |
my $max_exec_len = $MM->max_exec_len; | |
Calculates the maximum command size the OS can exec. Effectively, | |
this is the max size of a shell command line. | |
=for _private | |
$self->{_MAX_EXEC_LEN} is set by this method, but only for testing purposes. | |
=head3 make | |
my $make = $MM->make; | |
Returns the make variant we're generating the Makefile for. This attempts | |
to do some normalization on the information from %Config or the user. | |
=cut | |
sub make { | |
my $self = shift; | |
my $make = lc $self->{MAKE}; | |
# Truncate anything like foomake6 to just foomake. | |
$make =~ s/^(\w+make).*/$1/; | |
# Turn gnumake into gmake. | |
$make =~ s/^gnu/g/; | |
return $make; | |
} | |
=head2 Targets | |
These are methods which produce make targets. | |
=head3 all_target | |
Generate the default target 'all'. | |
=cut | |
sub all_target { | |
my $self = shift; | |
return <<'MAKE_EXT'; | |
all :: pure_all | |
$(NOECHO) $(NOOP) | |
MAKE_EXT | |
} | |
=head3 blibdirs_target | |
my $make_frag = $mm->blibdirs_target; | |
Creates the blibdirs target which creates all the directories we use | |
in blib/. | |
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; | |
my @dirs = map { uc "\$(INST_$_)" } qw(libdir archlib | |
autodir archautodir | |
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; | |
my $make = sprintf <<'MAKE', join(' ', @exists); | |
blibdirs : %s | |
$(NOECHO) $(NOOP) | |
# Backwards compat with 6.18 through 6.25 | |
blibdirs.ts : blibdirs | |
$(NOECHO) $(NOOP) | |
MAKE | |
$make .= $self->dir_target(@dirs); | |
return $make; | |
} | |
=head3 clean (o) | |
Defines the clean target. | |
=cut | |
sub clean { | |
# --- Cleanup and Distribution Sections --- | |
my($self, %attribs) = @_; | |
my @m; | |
push(@m, ' | |
# Delete temporary files but do not touch installed files. We don\'t delete | |
# the Makefile here so a later make realclean still has a makefile to use. | |
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 | |
# redefined. | |
# XXX normally this would be a good idea, but the Perl core sets | |
# INST_LIB = ../../lib rather than actually installing the files. | |
# So a "make clean" in an ext/ directory would blow away lib. | |
# Until the core is adjusted let's leave this out. | |
# push @dirs, qw($(INST_ARCHLIB) $(INST_LIB) | |
# $(INST_BIN) $(INST_SCRIPT) | |
# $(INST_MAN1DIR) $(INST_MAN3DIR) | |
# $(INST_LIBDIR) $(INST_ARCHLIBDIR) $(INST_AUTODIR) | |
# $(INST_STATIC) $(INST_DYNAMIC) | |
# ); | |
if( $attribs{FILES} ) { | |
# Use @dirs because we don't know what's in here. | |
push @dirs, ref $attribs{FILES} ? | |
@{$attribs{FILES}} : | |
split /\s+/, $attribs{FILES} ; | |
} | |
push(@files, qw[$(MAKE_APERL_FILE) | |
MYMETA.json MYMETA.yml perlmain.c tmon.out mon.out so_locations | |
blibdirs.ts pm_to_blib pm_to_blib.ts | |
*$(OBJ_EXT) *$(LIB_EXT) perl.exe perl perl$(EXE_EXT) | |
$(BOOTSTRAP) $(BASEEXT).bso | |
$(BASEEXT).def lib$(BASEEXT).def | |
$(BASEEXT).exp $(BASEEXT).x | |
]); | |
push(@files, $self->catfile('$(INST_ARCHAUTODIR)','extralibs.all')); | |
push(@files, $self->catfile('$(INST_ARCHAUTODIR)','extralibs.ld')); | |
# core files | |
if ($^O eq 'vos') { | |
push(@files, qw[perl*.kp]); | |
} | |
else { | |
push(@files, qw[core core.*perl.*.? *perl.core]); | |
} | |
push(@files, map { "core." . "[0-9]"x$_ } (1..5)); | |
# OS specific things to clean up. Use @dirs since we don't know | |
# what might be in here. | |
push @dirs, $self->extra_clean_files; | |
# Occasionally files are repeated several times from different sources | |
{ my(%f) = map { ($_ => 1) } @files; @files = sort keys %f; } | |
{ my(%d) = map { ($_ => 1) } @dirs; @dirs = sort keys %d; } | |
push @m, map "\t$_\n", $self->split_command('- $(RM_F)', @files); | |
push @m, map "\t$_\n", $self->split_command('- $(RM_RF)', @dirs); | |
# Leave Makefile.old around for realclean | |
push @m, <<'MAKE'; | |
$(NOECHO) $(RM_F) $(MAKEFILE_OLD) | |
- $(MV) $(FIRST_MAKEFILE) $(MAKEFILE_OLD) $(DEV_NULL) | |
MAKE | |
push(@m, "\t$attribs{POSTOP}\n") if $attribs{POSTOP}; | |
join("", @m); | |
} | |
=head3 clean_subdirs_target | |
my $make_frag = $MM->clean_subdirs_target; | |
Returns the clean_subdirs target. This is used by the clean target to | |
call clean on any subdirectories which contain Makefiles. | |
=cut | |
sub clean_subdirs_target { | |
my($self) = shift; | |
# No subdirectories, no cleaning. | |
return <<'NOOP_FRAG' unless @{$self->{DIR}}; | |
clean_subdirs : | |
$(NOECHO) $(NOOP) | |
NOOP_FRAG | |
my $clean = "clean_subdirs :\n"; | |
for my $dir (@{$self->{DIR}}) { | |
my $subclean = $self->oneliner(sprintf <<'CODE', $dir); | |
exit 0 unless chdir '%s'; system '$(MAKE) clean' if -f '$(FIRST_MAKEFILE)'; | |
CODE | |
$clean .= "\t$subclean\n"; | |
} | |
return $clean; | |
} | |
=head3 dir_target | |
my $make_frag = $mm->dir_target(@directories); | |
Generates targets to create the specified directories and set its | |
permission to PERM_DIR. | |
Because depending on a directory to just ensure it exists doesn't work | |
too well (the modified time changes too often) dir_target() creates a | |
.exists file in the created directory. It is this you should depend on. | |
For portability purposes you should use the $(DIRFILESEP) macro rather | |
than a '/' to separate the directory from the file. | |
yourdirectory$(DIRFILESEP).exists | |
=cut | |
sub dir_target { | |
my($self, @dirs) = @_; | |
my $make = ''; | |
foreach my $dir (@dirs) { | |
$make .= sprintf <<'MAKE', ($dir) x 4; | |
%s$(DFSEP).exists :: Makefile.PL | |
$(NOECHO) $(MKPATH) %s | |
$(NOECHO) $(CHMOD) $(PERM_DIR) %s | |
$(NOECHO) $(TOUCH) %s$(DFSEP).exists | |
MAKE | |
} | |
return $make; | |
} | |
=head3 distdir | |
Defines the scratch directory target that will hold the distribution | |
before tar-ing (or shar-ing). | |
=cut | |
# For backwards compatibility. | |
*dist_dir = *distdir; | |
sub distdir { | |
my($self) = shift; | |
my $meta_target = $self->{NO_META} ? '' : 'distmeta'; | |
my $sign_target = !$self->{SIGN} ? '' : 'distsignature'; | |
return sprintf <<'MAKE_FRAG', $meta_target, $sign_target; | |
create_distdir : | |
$(RM_RF) $(DISTVNAME) | |
$(PERLRUN) "-MExtUtils::Manifest=manicopy,maniread" \ | |
-e "manicopy(maniread(),'$(DISTVNAME)', '$(DIST_CP)');" | |
distdir : create_distdir %s %s | |
$(NOECHO) $(NOOP) | |
MAKE_FRAG | |
} | |
=head3 dist_test | |
Defines a target that produces the distribution in the | |
scratch directory, and runs 'perl Makefile.PL; make ;make test' in that | |
subdirectory. | |
=cut | |
sub dist_test { | |
my($self) = shift; | |
my $mpl_args = join " ", map qq["$_"], @ARGV; | |
my $test = $self->cd('$(DISTVNAME)', | |
'$(ABSPERLRUN) Makefile.PL '.$mpl_args, | |
'$(MAKE) $(PASTHRU)', | |
'$(MAKE) test $(PASTHRU)' | |
); | |
return sprintf <<'MAKE_FRAG', $test; | |
disttest : distdir | |
%s | |
MAKE_FRAG | |
} | |
=head3 xs_dlsyms_arg | |
Returns command-line arg(s) to linker for file listing dlsyms to export. | |
Defaults to returning empty string, can be overridden by e.g. AIX. | |
=cut | |
sub xs_dlsyms_arg { | |
return ''; | |
} | |
=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. | |
=cut | |
sub dynamic { | |
# --- Dynamic Loading Sections --- | |
my($self) = shift; | |
' | |
dynamic :: $(FIRST_MAKEFILE) config $(INST_BOOT) $(INST_DYNAMIC) | |
$(NOECHO) $(NOOP) | |
'; | |
} | |
=head3 makemakerdflt_target | |
my $make_frag = $mm->makemakerdflt_target | |
Returns a make fragment with the makemakerdeflt_target specified. | |
This target is the first target in the Makefile, is the default target | |
and simply points off to 'all' just in case any make variant gets | |
confused or something gets snuck in before the real 'all' target. | |
=cut | |
sub makemakerdflt_target { | |
return <<'MAKE_FRAG'; | |
makemakerdflt : all | |
$(NOECHO) $(NOOP) | |
MAKE_FRAG | |
} | |
=head3 manifypods_target | |
my $manifypods_target = $self->manifypods_target; | |
Generates the manifypods target. This target generates man pages from | |
all POD files in MAN1PODS and MAN3PODS. | |
=cut | |
sub manifypods_target { | |
my($self) = shift; | |
my $man1pods = ''; | |
my $man3pods = ''; | |
my $dependencies = ''; | |
# populate manXpods & dependencies: | |
foreach my $name (sort keys %{$self->{MAN1PODS}}, sort keys %{$self->{MAN3PODS}}) { | |
$dependencies .= " \\\n\t$name"; | |
} | |
my $manify = <<END; | |
manifypods : pure_all config $dependencies | |
END | |
my @man_cmds; | |
foreach my $num (qw(1 3)) { | |
my $pods = $self->{"MAN${num}PODS"}; | |
my $p2m = sprintf <<'CMD', "\$(MAN${num}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); | |
} | |
$manify .= "\t\$(NOECHO) \$(NOOP)\n" unless @man_cmds; | |
$manify .= join '', map { "$_\n" } @man_cmds; | |
return $manify; | |
} | |
{ | |
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 | |
my $target = $mm->metafile_target; | |
Generate the metafile target. | |
Writes the file META.yml (YAML encoded meta-data) and META.json | |
(JSON encoded meta-data) about the module in the distdir. | |
The format follows Module::Build's as closely as possible. | |
=cut | |
sub metafile_target { | |
my $self = shift; | |
return <<'MAKE_FRAG' if $self->{NO_META} or ! _has_cpan_meta(); | |
metafile : | |
$(NOECHO) $(NOOP) | |
MAKE_FRAG | |
my $metadata = $self->metafile_data( | |
$self->{META_ADD} || {}, | |
$self->{META_MERGE} || {}, | |
); | |
my $meta = $self->_fix_metadata_before_conversion( $metadata ); | |
my @write_metayml = $self->stashmeta( | |
$meta->as_string({version => "1.4"}), 'META_new.yml' | |
); | |
my @write_metajson = $self->stashmeta( | |
$meta->as_string({version => "2.0"}), 'META_new.json' | |
); | |
my $metayml = join("\n\t", @write_metayml); | |
my $metajson = join("\n\t", @write_metajson); | |
return sprintf <<'MAKE_FRAG', $metayml, $metajson; | |
metafile : create_distdir | |
$(NOECHO) $(ECHO) Generating META.yml | |
%s | |
-$(NOECHO) $(MV) META_new.yml $(DISTVNAME)/META.yml | |
$(NOECHO) $(ECHO) Generating META.json | |
%s | |
-$(NOECHO) $(MV) META_new.json $(DISTVNAME)/META.json | |
MAKE_FRAG | |
} | |
=begin private | |
=head3 _fix_metadata_before_conversion | |
$mm->_fix_metadata_before_conversion( \%metadata ); | |
Fixes errors in the metadata before it's handed off to L<CPAN::Meta> for | |
conversion. This hopefully results in something that can be used further | |
on, no guarantee is made though. | |
=end private | |
=cut | |
sub _fix_metadata_before_conversion { | |
my ( $self, $metadata ) = @_; | |
# we should never be called unless this already passed but | |
# prefer to be defensive in case somebody else calls this | |
return unless _has_cpan_meta; | |
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 $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 ( @errors ) { | |
my ( $key ) = ( $error =~ /Custom resource '(.*)' must be in CamelCase./ ); | |
next if !$key; | |
# first try to remove all non-alphabetic chars | |
( my $new_key = $key ) =~ s/[^_a-zA-Z]//g; | |
# if that doesn't work, uppercase first one | |
$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 $validator14->custom_1( $new_key ); | |
# and delete old one in any case | |
delete $metadata->{resources}{$key}; | |
} | |
# 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; | |
} | |
=begin private | |
=head3 _sort_pairs | |
my @pairs = _sort_pairs($sort_sub, \%hash); | |
Sorts the pairs of a hash based on keys ordered according | |
to C<$sort_sub>. | |
=end private | |
=cut | |
sub _sort_pairs { | |
my $sort = shift; | |
my $pairs = shift; | |
return map { $_ => $pairs->{$_} } | |
sort $sort | |
keys %$pairs; | |
} | |
# Taken from Module::Build::Base | |
sub _hash_merge { | |
my ($self, $h, $k, $v) = @_; | |
if (ref $h->{$k} eq 'ARRAY') { | |
push @{$h->{$k}}, ref $v ? @$v : $v; | |
} elsif (ref $h->{$k} eq 'HASH') { | |
$self->_hash_merge($h->{$k}, $_, $v->{$_}) foreach keys %$v; | |
} else { | |
$h->{$k} = $v; | |
} | |
} | |
=head3 metafile_data | |
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. 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. | |
=cut | |
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 | |
abstract => $self->{ABSTRACT} || 'unknown', | |
author => defined($self->{AUTHOR}) ? $self->{AUTHOR} : ['unknown'], | |
dynamic_config => 1, | |
generated_by => "ExtUtils::MakeMaker version $ExtUtils::MakeMaker::VERSION", | |
license => [ $self->{LICENSE} || 'unknown' ], | |
'meta-spec' => { | |
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); | |
if (!eval { require JSON::PP; require CPAN::Meta::Converter; CPAN::Meta::Converter->VERSION(2.141170) }) { | |
return \%meta; | |
} | |
# needs to be based on the original version | |
my $v1_add = _metaspec_version($meta_add) !~ /^2/; | |
my ($add_v, $merge_v) = map _metaspec_version($_), $meta_add, $meta_merge; | |
for my $frag ($meta_add, $meta_merge) { | |
my $def_v = $frag == $meta_add ? $merge_v : $add_v; | |
$frag = CPAN::Meta::Converter->new($frag, default_version => $def_v)->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 ) { | |
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; | |
} | |
=begin private | |
=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 ) = @_; | |
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 ) = @_; | |
# 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}; | |
} else { | |
$meta->{configure_requires} = { | |
'ExtUtils::MakeMaker' => 0, | |
}; | |
} | |
if( $self->{ARGS}{BUILD_REQUIRES} ) { | |
$meta->{build_requires} = $self->{BUILD_REQUIRES}; | |
} else { | |
$meta->{build_requires} = { | |
'ExtUtils::MakeMaker' => 0, | |
}; | |
} | |
if( $self->{ARGS}{TEST_REQUIRES} ) { | |
$meta->{build_requires} = { | |
%{ $meta->{build_requires} }, | |
%{ $self->{TEST_REQUIRES} }, | |
}; | |
} | |
$meta->{requires} = $self->{PREREQ_PM} | |
if defined $self->{PREREQ_PM}; | |
$meta->{requires}{perl} = _normalize_version($self->{MIN_PERL_VERSION}) | |
if $self->{MIN_PERL_VERSION}; | |
} | |
# Adapted from Module::Build::Base | |
sub _normalize_version { | |
my ($version) = @_; | |
$version = 0 unless defined $version; | |
if ( ref $version eq 'version' ) { # version objects | |
$version = $version->stringify; | |
} | |
elsif ( $version =~ /^[^v][^.]*\.[^.]+\./ ) { # no leading v, multiple dots | |
# normalize string tuples without "v": "1.2.3" -> "v1.2.3" | |
$version = "v$version"; | |
} | |
else { | |
# leave alone | |
} | |
return $version; | |
} | |
=head3 _dump_hash | |
$yaml = _dump_hash(\%options, %hash); | |
Implements a fake YAML dumper for a hash given | |
as a list of pairs. No quoting/escaping is done. Keys | |
are supposed to be strings. Values are undef, strings, | |
hash refs or array refs of strings. | |
Supported options are: | |
delta => STR - indentation delta | |
use_header => BOOL - whether to include a YAML header | |
indent => STR - a string of spaces | |
default: '' | |
max_key_length => INT - maximum key length used to align | |
keys and values of the same hash | |
default: 20 | |
key_sort => CODE - a sort sub | |
It may be undef, which means no sorting by keys | |
default: sub { lc $a cmp lc $b } | |
customs => HASH - special options for certain keys | |
(whose values are hashes themselves) | |
may contain: max_key_length, key_sort, customs | |
=end private | |
=cut | |
sub _dump_hash { | |
croak "first argument should be a hash ref" unless ref $_[0] eq 'HASH'; | |
my $options = shift; | |
my %hash = @_; | |
# Use a list to preserve order. | |
my @pairs; | |
my $k_sort | |
= exists $options->{key_sort} ? $options->{key_sort} | |
: sub { lc $a cmp lc $b }; | |
if ($k_sort) { | |
croak "'key_sort' should be a coderef" unless ref $k_sort eq 'CODE'; | |
@pairs = _sort_pairs($k_sort, \%hash); | |
} else { # list of pairs, no sorting | |
@pairs = @_; | |
} | |
my $yaml = $options->{use_header} ? "--- #YAML:1.0\n" : ''; | |
my $indent = $options->{indent} || ''; | |
my $k_length = min( | |
($options->{max_key_length} || 20), | |
max(map { length($_) + 1 } grep { !ref $hash{$_} } keys %hash) | |
); | |
my $customs = $options->{customs} || {}; | |
# printf format for key | |
my $k_format = "%-${k_length}s"; | |
while( @pairs ) { | |
my($key, $val) = splice @pairs, 0, 2; | |
$val = '~' unless defined $val; | |
if(ref $val eq 'HASH') { | |
if ( keys %$val ) { | |
my %k_options = ( # options for recursive call | |
delta => $options->{delta}, | |
use_header => 0, | |
indent => $indent . $options->{delta}, | |
); | |
if (exists $customs->{$key}) { | |
my %k_custom = %{$customs->{$key}}; | |
foreach my $k (qw(key_sort max_key_length customs)) { | |
$k_options{$k} = $k_custom{$k} if exists $k_custom{$k}; | |
} | |
} | |
$yaml .= $indent . "$key:\n" | |
. _dump_hash(\%k_options, %$val); | |
} | |
else { | |
$yaml .= $indent . "$key: {}\n"; | |
} | |
} | |
elsif (ref $val eq 'ARRAY') { | |
if( @$val ) { | |
$yaml .= $indent . "$key:\n"; | |
for (@$val) { | |
croak "only nested arrays of non-refs are supported" if ref $_; | |
$yaml .= $indent . $options->{delta} . "- $_\n"; | |
} | |
} | |
else { | |
$yaml .= $indent . "$key: []\n"; | |
} | |
} | |
elsif( ref $val and !blessed($val) ) { | |
croak "only nested hashes, arrays and objects are supported"; | |
} | |
else { # if it's an object, just stringify it | |
$yaml .= $indent . sprintf "$k_format %s\n", "$key:", $val; | |
} | |
}; | |
return $yaml; | |
} | |
sub blessed { | |
return eval { $_[0]->isa("UNIVERSAL"); }; | |
} | |
sub max { | |
return (sort { $b <=> $a } @_)[0]; | |
} | |
sub min { | |
return (sort { $a <=> $b } @_)[0]; | |
} | |
=head3 metafile_file | |
my $meta_yml = $mm->metafile_file(@metadata_pairs); | |
Turns the @metadata_pairs into YAML. | |
This method does not implement a complete YAML dumper, being limited | |
to dump a hash with values which are strings, undef's or nested hashes | |
and arrays of strings. No quoting/escaping is done. | |
=cut | |
sub metafile_file { | |
my $self = shift; | |
my %dump_options = ( | |
use_header => 1, | |
delta => ' ' x 4, | |
key_sort => undef, | |
); | |
return _dump_hash(\%dump_options, @_); | |
} | |
=head3 distmeta_target | |
my $make_frag = $mm->distmeta_target; | |
Generates the distmeta target to add META.yml and META.json to the MANIFEST | |
in the distdir. | |
=cut | |
sub distmeta_target { | |
my $self = shift; | |
my @add_meta = ( | |
$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 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 die "Could not add META.json to MANIFEST: ${'@'}" | |
CODE | |
); | |
my @add_meta_to_distdir = map { $self->cd('$(DISTVNAME)', $_) } @add_meta; | |
return sprintf <<'MAKE', @add_meta_to_distdir; | |
distmeta : create_distdir metafile | |
$(NOECHO) %s | |
$(NOECHO) %s | |
MAKE | |
} | |
=head3 mymeta | |
my $mymeta = $mm->mymeta; | |
Generate MYMETA information as a hash either from an existing CPAN Meta file | |
(META.json or META.yml) or from internal data. | |
=cut | |
sub mymeta { | |
my $self = shift; | |
my $file = shift || ''; # for testing | |
my $mymeta = $self->_mymeta_from_meta($file); | |
my $v2 = 1; | |
unless ( $mymeta ) { | |
$mymeta = $self->metafile_data( | |
$self->{META_ADD} || {}, | |
$self->{META_MERGE} || {}, | |
); | |
$v2 = 0; | |
} | |
# Overwrite the non-configure dependency hashes | |
$self->_add_requirements_to_meta($mymeta); | |
$mymeta->{dynamic_config} = 0; | |
return $mymeta; | |
} | |
sub _mymeta_from_meta { | |
my $self = shift; | |
my $metafile = shift || ''; # for testing | |
return unless _has_cpan_meta(); | |
my $meta; | |
for my $file ( $metafile, "META.json", "META.yml" ) { | |
next unless -e $file; | |
eval { | |
$meta = CPAN::Meta->load_file($file)->as_struct( { version => 2 } ); | |
}; | |
last if $meta; | |
} | |
return unless $meta; | |
# META.yml before 6.25_01 cannot be trusted. META.yml lived in the source directory. | |
# There was a good chance the author accidentally uploaded a stale META.yml if they | |
# rolled their own tarball rather than using "make dist". | |
if ($meta->{generated_by} && | |
$meta->{generated_by} =~ /ExtUtils::MakeMaker version ([\d\._]+)/) { | |
my $eummv = do { no warnings; $1+0; }; | |
if ($eummv < 6.2501) { | |
return; | |
} | |
} | |
return $meta; | |
} | |
=head3 write_mymeta | |
$self->write_mymeta( $mymeta ); | |
Write MYMETA information to MYMETA.json and MYMETA.yml. | |
=cut | |
sub write_mymeta { | |
my $self = shift; | |
my $mymeta = shift; | |
return unless _has_cpan_meta(); | |
my $meta_obj = $self->_fix_metadata_before_conversion( $mymeta ); | |
$meta_obj->save( 'MYMETA.json', { version => "2.0" } ); | |
$meta_obj->save( 'MYMETA.yml', { version => "1.4" } ); | |
return 1; | |
} | |
=head3 realclean (o) | |
Defines the realclean target. | |
=cut | |
sub realclean { | |
my($self, %attribs) = @_; | |
my @dirs = qw($(DISTVNAME)); | |
my @files = qw($(FIRST_MAKEFILE) $(MAKEFILE_OLD)); | |
# Special exception for the perl core where INST_* is not in blib. | |
# This cleans up the files built from the ext/ directory (all XS). | |
if( $self->{PERL_CORE} ) { | |
push @dirs, qw($(INST_AUTODIR) $(INST_ARCHAUTODIR)); | |
push @files, values %{$self->{PM}}; | |
} | |
if( $self->has_link_code ){ | |
push @files, qw($(OBJECT)); | |
} | |
if( $attribs{FILES} ) { | |
if( ref $attribs{FILES} ) { | |
push @dirs, @{ $attribs{FILES} }; | |
} | |
else { | |
push @dirs, split /\s+/, $attribs{FILES}; | |
} | |
} | |
# Occasionally files are repeated several times from different sources | |
{ 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); | |
my $rmf_cmd = join "\n\t", map { "$_" } | |
$self->split_command('- $(RM_RF)', @dirs); | |
my $m = sprintf <<'MAKE', $rm_cmd, $rmf_cmd; | |
# Delete temporary files (via clean) and also delete dist files | |
realclean purge :: realclean_subdirs | |
%s | |
%s | |
MAKE | |
$m .= "\t$attribs{POSTOP}\n" if $attribs{POSTOP}; | |
return $m; | |
} | |
=head3 realclean_subdirs_target | |
my $make_frag = $MM->realclean_subdirs_target; | |
Returns the realclean_subdirs target. This is used by the realclean | |
target to call realclean on any subdirectories which contain Makefiles. | |
=cut | |
sub realclean_subdirs_target { | |
my $self = shift; | |
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(_sprintf562 <<'CODE', $dir, $makefile); | |
chdir '%1$s'; system '$(MAKE) $(USEMAKEFILE) %2$s realclean' if -f '%2$s'; | |
CODE | |
push @m, "\t- $subrclean\n"; | |
} | |
} | |
return join '', @m; | |
} | |
=head3 signature_target | |
my $target = $mm->signature_target; | |
Generate the signature target. | |
Writes the file SIGNATURE with "cpansign -s". | |
=cut | |
sub signature_target { | |
my $self = shift; | |
return <<'MAKE_FRAG'; | |
signature : | |
cpansign -s | |
MAKE_FRAG | |
} | |
=head3 distsignature_target | |
my $make_frag = $mm->distsignature_target; | |
Generates the distsignature target to add SIGNATURE to the MANIFEST in the | |
distdir. | |
=cut | |
sub distsignature_target { | |
my $self = shift; | |
my $add_sign = $self->oneliner(<<'CODE', ['-MExtUtils::Manifest=maniadd']); | |
eval { maniadd({q{SIGNATURE} => q{Public-key signature (added by MakeMaker)}}) } | |
or die "Could not add SIGNATURE to MANIFEST: ${'@'}" | |
CODE | |
my $sign_dist = $self->cd('$(DISTVNAME)' => 'cpansign -s'); | |
# cpansign -s complains if SIGNATURE is in the MANIFEST yet does not | |
# exist | |
my $touch_sig = $self->cd('$(DISTVNAME)' => '$(TOUCH) SIGNATURE'); | |
my $add_sign_to_dist = $self->cd('$(DISTVNAME)' => $add_sign ); | |
return sprintf <<'MAKE', $add_sign_to_dist, $touch_sig, $sign_dist | |
distsignature : distmeta | |
$(NOECHO) %s | |
$(NOECHO) %s | |
%s | |
MAKE | |
} | |
=head3 special_targets | |
my $make_frag = $mm->special_targets | |
Returns a make fragment containing any targets which have special | |
meaning to make. For example, .SUFFIXES and .PHONY. | |
=cut | |
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 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 | |
$make_frag .= <<'MAKE_FRAG' if $ENV{CLEARCASE_ROOT}; | |
.NO_CONFIG_REC: Makefile | |
MAKE_FRAG | |
return $make_frag; | |
} | |
=head2 Init methods | |
Methods which help initialize the MakeMaker object and macros. | |
=head3 init_ABSTRACT | |
$mm->init_ABSTRACT | |
=cut | |
sub init_ABSTRACT { | |
my $self = shift; | |
if( $self->{ABSTRACT_FROM} and $self->{ABSTRACT} ) { | |
warn "Both ABSTRACT_FROM and ABSTRACT are set. ". | |
"Ignoring ABSTRACT_FROM.\n"; | |
return; | |
} | |
if ($self->{ABSTRACT_FROM}){ | |
$self->{ABSTRACT} = $self->parse_abstract($self->{ABSTRACT_FROM}) or | |
carp "WARNING: Setting ABSTRACT via file ". | |
"'$self->{ABSTRACT_FROM}' failed\n"; | |
} | |
if ($self->{ABSTRACT} && $self->{ABSTRACT} =~ m![[:cntrl:]]+!) { | |
warn "WARNING: ABSTRACT contains control character(s),". | |
" they will be removed\n"; | |
$self->{ABSTRACT} =~ s![[:cntrl:]]+!!g; | |
return; | |
} | |
} | |
=head3 init_INST | |
$mm->init_INST; | |
Called by init_main. Sets up all INST_* variables except those related | |
to XS code. Those are handled in init_xs. | |
=cut | |
sub init_INST { | |
my($self) = shift; | |
$self->{INST_ARCHLIB} ||= $self->catdir($Curdir,"blib","arch"); | |
$self->{INST_BIN} ||= $self->catdir($Curdir,'blib','bin'); | |
# INST_LIB typically pre-set if building an extension after | |
# perl has been built and installed. Setting INST_LIB allows | |
# you to build directly into, say $Config{privlibexp}. | |
unless ($self->{INST_LIB}){ | |
if ($self->{PERL_CORE}) { | |
$self->{INST_LIB} = $self->{INST_ARCHLIB} = $self->{PERL_LIB}; | |
} else { | |
$self->{INST_LIB} = $self->catdir($Curdir,"blib","lib"); | |
} | |
} | |
my @parentdir = split(/::/, $self->{PARENT_NAME}); | |
$self->{INST_LIBDIR} = $self->catdir('$(INST_LIB)', @parentdir); | |
$self->{INST_ARCHLIBDIR} = $self->catdir('$(INST_ARCHLIB)', @parentdir); | |
$self->{INST_AUTODIR} = $self->catdir('$(INST_LIB)', 'auto', | |
'$(FULLEXT)'); | |
$self->{INST_ARCHAUTODIR} = $self->catdir('$(INST_ARCHLIB)', 'auto', | |
'$(FULLEXT)'); | |
$self->{INST_SCRIPT} ||= $self->catdir($Curdir,'blib','script'); | |
$self->{INST_MAN1DIR} ||= $self->catdir($Curdir,'blib','man1'); | |
$self->{INST_MAN3DIR} ||= $self->catdir($Curdir,'blib','man3'); | |
return 1; | |
} | |
=head3 init_INSTALL | |
$mm->init_INSTALL; | |
Called by init_main. Sets up all INSTALL_* variables (except | |
INSTALLDIRS) and *PREFIX. | |
=cut | |
sub init_INSTALL { | |
my($self) = shift; | |
if( $self->{ARGS}{INSTALL_BASE} and $self->{ARGS}{PREFIX} ) { | |
die "Only one of PREFIX or INSTALL_BASE can be given. Not both.\n"; | |
} | |
if( $self->{ARGS}{INSTALL_BASE} ) { | |
$self->init_INSTALL_from_INSTALL_BASE; | |
} | |
else { | |
$self->init_INSTALL_from_PREFIX; | |
} | |
} | |
=head3 init_INSTALL_from_PREFIX | |
$mm->init_INSTALL_from_PREFIX; | |
=cut | |
sub init_INSTALL_from_PREFIX { | |
my $self = shift; | |
$self->init_lib2arch; | |
# There are often no Config.pm defaults for these new man variables so | |
# we fall back to the old behavior which is to use installman*dir | |
foreach my $num (1, 3) { | |
my $k = 'installsiteman'.$num.'dir'; | |
$self->{uc $k} ||= uc "\$(installman${num}dir)" | |
unless $Config{$k}; | |
} | |
foreach my $num (1, 3) { | |
my $k = 'installvendorman'.$num.'dir'; | |
unless( $Config{$k} ) { | |
$self->{uc $k} ||= $Config{usevendorprefix} | |
? uc "\$(installman${num}dir)" | |
: ''; | |
} | |
} | |
$self->{INSTALLSITEBIN} ||= '$(INSTALLBIN)' | |
unless $Config{installsitebin}; | |
$self->{INSTALLSITESCRIPT} ||= '$(INSTALLSCRIPT)' | |
unless $Config{installsitescript}; | |
unless( $Config{installvendorbin} ) { | |
$self->{INSTALLVENDORBIN} ||= $Config{usevendorprefix} | |
? $Config{installbin} | |
: ''; | |
} | |
unless( $Config{installvendorscript} ) { | |
$self->{INSTALLVENDORSCRIPT} ||= $Config{usevendorprefix} | |
? $Config{installscript} | |
: ''; | |
} | |
my $iprefix = $Config{installprefixexp} || $Config{installprefix} || | |
$Config{prefixexp} || $Config{prefix} || ''; | |
my $vprefix = $Config{usevendorprefix} ? $Config{vendorprefixexp} : ''; | |
my $sprefix = $Config{siteprefixexp} || ''; | |
# 5.005_03 doesn't have a siteprefix. | |
$sprefix = $iprefix unless $sprefix; | |
$self->{PREFIX} ||= ''; | |
if( $self->{PREFIX} ) { | |
@{$self}{qw(PERLPREFIX SITEPREFIX VENDORPREFIX)} = | |
('$(PREFIX)') x 3; | |
} | |
else { | |
$self->{PERLPREFIX} ||= $iprefix; | |
$self->{SITEPREFIX} ||= $sprefix; | |
$self->{VENDORPREFIX} ||= $vprefix; | |
# Lots of MM extension authors like to use $(PREFIX) so we | |
# put something sensible in there no matter what. | |
$self->{PREFIX} = '$('.uc $self->{INSTALLDIRS}.'PREFIX)'; | |
} | |
my $arch = $Config{archname}; | |
my $version = $Config{version}; | |
# default style | |
my $libstyle = $Config{installstyle} || 'lib/perl5'; | |
my $manstyle = ''; | |
if( $self->{LIBSTYLE} ) { | |
$libstyle = $self->{LIBSTYLE}; | |
$manstyle = $self->{LIBSTYLE} eq 'lib/perl5' ? 'lib/perl5' : ''; | |
} | |
# Some systems, like VOS, set installman*dir to '' if they can't | |
# read man pages. | |
for my $num (1, 3) { | |
$self->{'INSTALLMAN'.$num.'DIR'} ||= 'none' | |
unless $Config{'installman'.$num.'dir'}; | |
} | |
my %bin_layouts = | |
( | |
bin => { s => $iprefix, | |
t => 'perl', | |
d => 'bin' }, | |
vendorbin => { s => $vprefix, | |
t => 'vendor', | |
d => 'bin' }, | |
sitebin => { s => $sprefix, | |
t => 'site', | |
d => 'bin' }, | |
script => { s => $iprefix, | |
t => 'perl', | |
d => 'bin' }, | |
vendorscript=> { s => $vprefix, | |
t => 'vendor', | |
d => 'bin' }, | |
sitescript => { s => $sprefix, | |
t => 'site', | |
d => 'bin' }, | |
); | |
my %man_layouts = | |
( | |
man1dir => { s => $iprefix, | |
t => 'perl', | |
d => 'man/man1', | |
style => $manstyle, }, | |
siteman1dir => { s => $sprefix, | |
t => 'site', | |
d => 'man/man1', | |
style => $manstyle, }, | |
vendorman1dir => { s => $vprefix, | |
t => 'vendor', | |
d => 'man/man1', | |
style => $manstyle, }, | |
man3dir => { s => $iprefix, | |
t => 'perl', | |
d => 'man/man3', | |
style => $manstyle, }, | |
siteman3dir => { s => $sprefix, | |
t => 'site', | |
d => 'man/man3', | |
style => $manstyle, }, | |
vendorman3dir => { s => $vprefix, | |
t => 'vendor', | |
d => 'man/man3', | |
style => $manstyle, }, | |
); | |
my %lib_layouts = | |
( | |
privlib => { s => $iprefix, | |
t => 'perl', | |
d => '', | |
style => $libstyle, }, | |
vendorlib => { s => $vprefix, | |
t => 'vendor', | |
d => '', | |
style => $libstyle, }, | |
sitelib => { s => $sprefix, | |
t => 'site', | |
d => 'site_perl', | |
style => $libstyle, }, | |
archlib => { s => $iprefix, | |
t => 'perl', | |
d => "$version/$arch", | |
style => $libstyle }, | |
vendorarch => { s => $vprefix, | |
t => 'vendor', | |
d => "$version/$arch", | |
style => $libstyle }, | |
sitearch => { s => $sprefix, | |
t => 'site', | |
d => "site_perl/$version/$arch", | |
style => $libstyle }, | |
); | |
# Special case for LIB. | |
if( $self->{LIB} ) { | |
foreach my $var (keys %lib_layouts) { | |
my $Installvar = uc "install$var"; | |
if( $var =~ /arch/ ) { | |
$self->{$Installvar} ||= | |
$self->catdir($self->{LIB}, $Config{archname}); | |
} | |
else { | |
$self->{$Installvar} ||= $self->{LIB}; | |
} | |
} | |
} | |
my %type2prefix = ( perl => 'PERLPREFIX', | |
site => 'SITEPREFIX', | |
vendor => 'VENDORPREFIX' | |
); | |
my %layouts = (%bin_layouts, %man_layouts, %lib_layouts); | |
while( my($var, $layout) = each(%layouts) ) { | |
my($s, $t, $d, $style) = @{$layout}{qw(s t d style)}; | |
my $r = '$('.$type2prefix{$t}.')'; | |
warn "Prefixing $var\n" if $Verbose >= 2; | |
my $installvar = "install$var"; | |
my $Installvar = uc $installvar; | |
next if $self->{$Installvar}; | |
$d = "$style/$d" if $style; | |
$self->prefixify($installvar, $s, $r, $d); | |
warn " $Installvar == $self->{$Installvar}\n" | |
if $Verbose >= 2; | |
} | |
# Generate these if they weren't figured out. | |
$self->{VENDORARCHEXP} ||= $self->{INSTALLVENDORARCH}; | |
$self->{VENDORLIBEXP} ||= $self->{INSTALLVENDORLIB}; | |
return 1; | |
} | |
=head3 init_from_INSTALL_BASE | |
$mm->init_from_INSTALL_BASE | |
=cut | |
my %map = ( | |
lib => [qw(lib perl5)], | |
arch => [('lib', 'perl5', $Config{archname})], | |
bin => [qw(bin)], | |
man1dir => [qw(man man1)], | |
man3dir => [qw(man man3)] | |
); | |
$map{script} = $map{bin}; | |
sub init_INSTALL_from_INSTALL_BASE { | |
my $self = shift; | |
@{$self}{qw(PREFIX VENDORPREFIX SITEPREFIX PERLPREFIX)} = | |
'$(INSTALL_BASE)'; | |
my %install; | |
foreach my $thing (keys %map) { | |
foreach my $dir (('', 'SITE', 'VENDOR')) { | |
my $uc_thing = uc $thing; | |
my $key = "INSTALL".$dir.$uc_thing; | |
$install{$key} ||= | |
($thing =~ /^man.dir$/ and not $Config{lc $key}) | |
? 'none' | |
: $self->catdir('$(INSTALL_BASE)', @{$map{$thing}}); | |
} | |
} | |
# Adjust for variable quirks. | |
$install{INSTALLARCHLIB} ||= delete $install{INSTALLARCH}; | |
$install{INSTALLPRIVLIB} ||= delete $install{INSTALLLIB}; | |
foreach my $key (keys %install) { | |
$self->{$key} ||= $install{$key}; | |
} | |
return 1; | |
} | |
=head3 init_VERSION I<Abstract> | |
$mm->init_VERSION | |
Initialize macros representing versions of MakeMaker and other tools | |
MAKEMAKER: path to the MakeMaker module. | |
MM_VERSION: ExtUtils::MakeMaker Version | |
MM_REVISION: ExtUtils::MakeMaker version control revision (for backwards | |
compat) | |
VERSION: version of your module | |
VERSION_MACRO: which macro represents the version (usually 'VERSION') | |
VERSION_SYM: like version but safe for use as an RCS revision number | |
DEFINE_VERSION: -D line to set the module version when compiling | |
XS_VERSION: version in your .xs file. Defaults to $(VERSION) | |
XS_VERSION_MACRO: which macro represents the XS version. | |
XS_DEFINE_VERSION: -D line to set the xs version when compiling. | |
Called by init_main. | |
=cut | |
sub init_VERSION { | |
my($self) = shift; | |
$self->{MAKEMAKER} = $ExtUtils::MakeMaker::Filename; | |
$self->{MM_VERSION} = $ExtUtils::MakeMaker::VERSION; | |
$self->{MM_REVISION}= $ExtUtils::MakeMaker::Revision; | |
$self->{VERSION_FROM} ||= ''; | |
if ($self->{VERSION_FROM}){ | |
$self->{VERSION} = $self->parse_version($self->{VERSION_FROM}); | |
if( $self->{VERSION} eq 'undef' ) { | |
carp("WARNING: Setting VERSION via file ". | |
"'$self->{VERSION_FROM}' failed\n"); | |
} | |
} | |
if (defined $self->{VERSION}) { | |
if ( $self->{VERSION} !~ /^\s*v?[\d_\.]+\s*$/ ) { | |
require version; | |
my $normal = eval { version->new( $self->{VERSION} ) }; | |
$self->{VERSION} = $normal if defined $normal; | |
} | |
$self->{VERSION} =~ s/^\s+//; | |
$self->{VERSION} =~ s/\s+$//; | |
} | |
else { | |
$self->{VERSION} = ''; | |
} | |
$self->{VERSION_MACRO} = 'VERSION'; | |
($self->{VERSION_SYM} = $self->{VERSION}) =~ s/\W/_/g; | |
$self->{DEFINE_VERSION} = '-D$(VERSION_MACRO)=\"$(VERSION)\"'; | |
# Graham Barr and Paul Marquess had some ideas how to ensure | |
# version compatibility between the *.pm file and the | |
# corresponding *.xs file. The bottom line was, that we need an | |
# XS_VERSION macro that defaults to VERSION: | |
$self->{XS_VERSION} ||= $self->{VERSION}; | |
$self->{XS_VERSION_MACRO} = 'XS_VERSION'; | |
$self->{XS_DEFINE_VERSION} = '-D$(XS_VERSION_MACRO)=\"$(XS_VERSION)\"'; | |
} | |
=head3 init_tools | |
$MM->init_tools(); | |
Initializes the simple macro definitions used by tools_other() and | |
places them in the $MM object. These use conservative cross platform | |
versions and should be overridden with platform specific versions for | |
performance. | |
Defines at least these macros. | |
Macro Description | |
NOOP Do nothing | |
NOECHO Tell make not to display the command itself | |
SHELL Program used to run shell commands | |
ECHO Print text adding a newline on the end | |
RM_F Remove a file | |
RM_RF Remove a directory | |
TOUCH Update a file's timestamp | |
TEST_F Test for a file's existence | |
TEST_S Test the size of a file | |
CP Copy a file | |
CP_NONEMPTY Copy a file if it is not empty | |
MV Move a file | |
CHMOD Change permissions on a file | |
FALSE Exit with non-zero | |
TRUE Exit with zero | |
UMASK_NULL Nullify umask | |
DEV_NULL Suppress all command output | |
=cut | |
sub init_tools { | |
my $self = shift; | |
$self->{ECHO} ||= $self->oneliner('binmode STDOUT, qq{:raw}; print qq{@ARGV}', ['-l']); | |
$self->{ECHO_N} ||= $self->oneliner('print qq{@ARGV}'); | |
$self->{TOUCH} ||= $self->oneliner('touch', ["-MExtUtils::Command"]); | |
$self->{CHMOD} ||= $self->oneliner('chmod', ["-MExtUtils::Command"]); | |
$self->{RM_F} ||= $self->oneliner('rm_f', ["-MExtUtils::Command"]); | |
$self->{RM_RF} ||= $self->oneliner('rm_rf', ["-MExtUtils::Command"]); | |
$self->{TEST_F} ||= $self->oneliner('test_f', ["-MExtUtils::Command"]); | |
$self->{TEST_S} ||= $self->oneliner('test_s', ["-MExtUtils::Command::MM"]); | |
$self->{CP_NONEMPTY} ||= $self->oneliner('cp_nonempty', ["-MExtUtils::Command::MM"]); | |
$self->{FALSE} ||= $self->oneliner('exit 1'); | |
$self->{TRUE} ||= $self->oneliner('exit 0'); | |
$self->{MKPATH} ||= $self->oneliner('mkpath', ["-MExtUtils::Command"]); | |
$self->{CP} ||= $self->oneliner('cp', ["-MExtUtils::Command"]); | |
$self->{MV} ||= $self->oneliner('mv', ["-MExtUtils::Command"]); | |
$self->{MOD_INSTALL} ||= | |
$self->oneliner(<<'CODE', ['-MExtUtils::Install']); | |
install([ from_to => {@ARGV}, verbose => '$(VERBINST)', uninstall_shadows => '$(UNINST)', dir_mode => '$(PERM_DIR)' ]); | |
CODE | |
$self->{DOC_INSTALL} ||= $self->oneliner('perllocal_install', ["-MExtUtils::Command::MM"]); | |
$self->{UNINSTALL} ||= $self->oneliner('uninstall', ["-MExtUtils::Command::MM"]); | |
$self->{WARN_IF_OLD_PACKLIST} ||= | |
$self->oneliner('warn_if_old_packlist', ["-MExtUtils::Command::MM"]); | |
$self->{FIXIN} ||= $self->oneliner('MY->fixin(shift)', ["-MExtUtils::MY"]); | |
$self->{EQUALIZE_TIMESTAMP} ||= $self->oneliner('eqtime', ["-MExtUtils::Command"]); | |
$self->{UNINST} ||= 0; | |
$self->{VERBINST} ||= 0; | |
$self->{SHELL} ||= $Config{sh}; | |
# UMASK_NULL is not used by MakeMaker but some CPAN modules | |
# make use of it. | |
$self->{UMASK_NULL} ||= "umask 0"; | |
# Not the greatest default, but its something. | |
$self->{DEV_NULL} ||= "> /dev/null 2>&1"; | |
$self->{NOOP} ||= '$(TRUE)'; | |
$self->{NOECHO} = '@' unless defined $self->{NOECHO}; | |
$self->{FIRST_MAKEFILE} ||= $self->{MAKEFILE} || 'Makefile'; | |
$self->{MAKEFILE} ||= $self->{FIRST_MAKEFILE}; | |
$self->{MAKEFILE_OLD} ||= $self->{MAKEFILE}.'.old'; | |
$self->{MAKE_APERL_FILE} ||= $self->{MAKEFILE}.'.aperl'; | |
# Not everybody uses -f to indicate "use this Makefile instead" | |
$self->{USEMAKEFILE} ||= '-f'; | |
# Some makes require a wrapper around macros passed in on the command | |
# line. | |
$self->{MACROSTART} ||= ''; | |
$self->{MACROEND} ||= ''; | |
return; | |
} | |
=head3 init_others | |
$MM->init_others(); | |
Initializes the macro definitions having to do with compiling and | |
linking used by tools_other() and places them in the $MM object. | |
If there is no description, its the same as the parameter to | |
WriteMakefile() documented in L<ExtUtils::MakeMaker>. | |
=cut | |
sub init_others { | |
my $self = shift; | |
$self->{LD_RUN_PATH} = ""; | |
$self->{LIBS} = $self->_fix_libs($self->{LIBS}); | |
# Compute EXTRALIBS, BSLOADLIBS and LDLOADLIBS from $self->{LIBS} | |
foreach my $libs ( @{$self->{LIBS}} ){ | |
$libs =~ s/^\s*(.*\S)\s*$/$1/; # remove leading and trailing whitespace | |
my(@libs) = $self->extliblist($libs); | |
if ($libs[0] or $libs[1] or $libs[2]){ | |
# LD_RUN_PATH now computed by ExtUtils::Liblist | |
($self->{EXTRALIBS}, $self->{BSLOADLIBS}, | |
$self->{LDLOADLIBS}, $self->{LD_RUN_PATH}) = @libs; | |
last; | |
} | |
} | |
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->{XSMULTI}) && @{$self->{O_FILES}||[]} ) { | |
$self->{OBJECT} = join(" ", @{$self->{O_FILES}}); | |
$self->{OBJECT} =~ s!\.o(bj)?\b!\$(OBJ_EXT)!g; | |
} else { | |
# init_dirscan should have found out, if we have C files | |
$self->{OBJECT} = ""; | |
$self->{OBJECT} = '$(BASEEXT)$(OBJ_EXT)' if @{$self->{C}||[]}; | |
} | |
$self->{OBJECT} =~ s/\n+/ \\\n\t/g; | |
$self->{BOOTDEP} = (-f "$self->{BASEEXT}_BS") ? "$self->{BASEEXT}_BS" : ""; | |
$self->{PERLMAINCC} ||= '$(CC)'; | |
$self->{LDFROM} = '$(OBJECT)' unless $self->{LDFROM}; | |
# Sanity check: don't define LINKTYPE = dynamic if we're skipping | |
# the 'dynamic' section of MM. We don't have this problem with | |
# 'static', since we either must use it (%Config says we can't | |
# use dynamic loading) or the caller asked for it explicitly. | |
if (!$self->{LINKTYPE}) { | |
$self->{LINKTYPE} = $self->{SKIPHASH}{'dynamic'} | |
? 'static' | |
: ($Config{usedl} ? 'dynamic' : 'static'); | |
} | |
return; | |
} | |
# Lets look at $self->{LIBS} carefully: It may be an anon array, a string or | |
# undefined. In any case we turn it into an anon array | |
sub _fix_libs { | |
my($self, $libs) = @_; | |
return !defined $libs ? [''] : | |
!ref $libs ? [$libs] : | |
!defined $libs->[0] ? [''] : | |
$libs ; | |
} | |
=head3 tools_other | |
my $make_frag = $MM->tools_other; | |
Returns a make fragment containing definitions for the macros init_others() | |
initializes. | |
=cut | |
sub tools_other { | |
my($self) = shift; | |
my @m; | |
# We set PM_FILTER as late as possible so it can see all the earlier | |
# on macro-order sensitive makes such as nmake. | |
for my $tool (qw{ SHELL CHMOD CP MV NOOP NOECHO RM_F RM_RF TEST_F TOUCH | |
UMASK_NULL DEV_NULL MKPATH EQUALIZE_TIMESTAMP | |
FALSE TRUE | |
ECHO ECHO_N | |
UNINST VERBINST | |
MOD_INSTALL DOC_INSTALL UNINSTALL | |
WARN_IF_OLD_PACKLIST | |
MACROSTART MACROEND | |
USEMAKEFILE | |
PM_FILTER | |
FIXIN | |
CP_NONEMPTY | |
} ) | |
{ | |
next unless defined $self->{$tool}; | |
push @m, "$tool = $self->{$tool}\n"; | |
} | |
return join "", @m; | |
} | |
=head3 init_DIRFILESEP I<Abstract> | |
$MM->init_DIRFILESEP; | |
my $dirfilesep = $MM->{DIRFILESEP}; | |
Initializes the DIRFILESEP macro which is the separator between the | |
directory and filename in a filepath. ie. / on Unix, \ on Win32 and | |
nothing on VMS. | |
For example: | |
# instead of $(INST_ARCHAUTODIR)/extralibs.ld | |
$(INST_ARCHAUTODIR)$(DIRFILESEP)extralibs.ld | |
Something of a hack but it prevents a lot of code duplication between | |
MM_* variants. | |
Do not use this as a separator between directories. Some operating | |
systems use different separators between subdirectories as between | |
directories and filenames (for example: VOLUME:[dir1.dir2]file on VMS). | |
=head3 init_linker I<Abstract> | |
$mm->init_linker; | |
Initialize macros which have to do with linking. | |
PERL_ARCHIVE: path to libperl.a equivalent to be linked to dynamic | |
extensions. | |
PERL_ARCHIVE_AFTER: path to a library which should be put on the | |
linker command line I<after> the external libraries to be linked to | |
dynamic extensions. This may be needed if the linker is one-pass, and | |
Perl includes some overrides for C RTL functions, such as malloc(). | |
EXPORT_LIST: name of a file that is passed to linker to define symbols | |
to be exported. | |
Some OSes do not need these in which case leave it blank. | |
=head3 init_platform | |
$mm->init_platform | |
Initialize any macros which are for platform specific use only. | |
A typical one is the version number of your OS specific module. | |
(ie. MM_Unix_VERSION or MM_VMS_VERSION). | |
=cut | |
sub init_platform { | |
return ''; | |
} | |
=head3 init_MAKE | |
$mm->init_MAKE | |
Initialize MAKE from either a MAKE environment variable or $Config{make}. | |
=cut | |
sub init_MAKE { | |
my $self = shift; | |
$self->{MAKE} ||= $ENV{MAKE} || $Config{make}; | |
} | |
=head2 Tools | |
A grab bag of methods to generate specific macros and commands. | |
=head3 manifypods | |
Defines targets and routines to translate the pods into manpages and | |
put them into the INST_* directories. | |
=cut | |
sub manifypods { | |
my $self = shift; | |
my $POD2MAN_macro = $self->POD2MAN_macro(); | |
my $manifypods_target = $self->manifypods_target(); | |
return <<END_OF_TARGET; | |
$POD2MAN_macro | |
$manifypods_target | |
END_OF_TARGET | |
} | |
=head3 POD2MAN_macro | |
my $pod2man_macro = $self->POD2MAN_macro | |
Returns a definition for the POD2MAN macro. This is a program | |
which emulates the pod2man utility. You can add more switches to the | |
command by simply appending them on the macro. | |
Typical usage: | |
$(POD2MAN) --section=3 --perm_rw=$(PERM_RW) podfile1 man_page1 ... | |
=cut | |
sub POD2MAN_macro { | |
my $self = shift; | |
# Need the trailing '--' so perl stops gobbling arguments and - happens | |
# to be an alternative end of line separator on VMS so we quote it | |
return <<'END_OF_DEF'; | |
POD2MAN_EXE = $(PERLRUN) "-MExtUtils::Command::MM" -e pod2man "--" | |
POD2MAN = $(POD2MAN_EXE) | |
END_OF_DEF | |
} | |
=head3 test_via_harness | |
my $command = $mm->test_via_harness($perl, $tests); | |
Returns a $command line which runs the given set of $tests with | |
Test::Harness and the given $perl. | |
Used on the t/*.t files. | |
=cut | |
sub test_via_harness { | |
my($self, $perl, $tests) = @_; | |
return qq{\t$perl "-MExtUtils::Command::MM" "-MTest::Harness" }. | |
qq{"-e" "undef *Test::Harness::Switches; test_harness(\$(TEST_VERBOSE), '\$(INST_LIB)', '\$(INST_ARCHLIB)')" $tests\n}; | |
} | |
=head3 test_via_script | |
my $command = $mm->test_via_script($perl, $script); | |
Returns a $command line which just runs a single test without | |
Test::Harness. No checks are done on the results, they're just | |
printed. | |
Used for test.pl, since they don't always follow Test::Harness | |
formatting. | |
=cut | |
sub test_via_script { | |
my($self, $perl, $script) = @_; | |
return qq{\t$perl "-I\$(INST_LIB)" "-I\$(INST_ARCHLIB)" $script\n}; | |
} | |
=head3 tool_autosplit | |
Defines a simple perl call that runs autosplit. May be deprecated by | |
pm_to_blib soon. | |
=cut | |
sub tool_autosplit { | |
my($self, %attribs) = @_; | |
my $maxlen = $attribs{MAXLEN} ? '$$AutoSplit::Maxlen=$attribs{MAXLEN};' | |
: ''; | |
my $asplit = $self->oneliner(sprintf <<'PERL_CODE', $maxlen); | |
use AutoSplit; %s autosplit($$ARGV[0], $$ARGV[1], 0, 1, 1) | |
PERL_CODE | |
return sprintf <<'MAKE_FRAG', $asplit; | |
# Usage: $(AUTOSPLITFILE) FileToSplit AutoDirToSplitInto | |
AUTOSPLITFILE = %s | |
MAKE_FRAG | |
} | |
=head3 arch_check | |
my $arch_ok = $mm->arch_check( | |
$INC{"Config.pm"}, | |
File::Spec->catfile($Config{archlibexp}, "Config.pm") | |
); | |
A sanity check that what Perl thinks the architecture is and what | |
Config thinks the architecture is are the same. If they're not it | |
will return false and show a diagnostic message. | |
When building Perl it will always return true, as nothing is installed | |
yet. | |
The interface is a bit odd because this is the result of a | |
quick refactoring. Don't rely on it. | |
=cut | |
sub arch_check { | |
my $self = shift; | |
my($pconfig, $cconfig) = @_; | |
return 1 if $self->{PERL_SRC}; | |
my($pvol, $pthinks) = $self->splitpath($pconfig); | |
my($cvol, $cthinks) = $self->splitpath($cconfig); | |
$pthinks = $self->canonpath($pthinks); | |
$cthinks = $self->canonpath($cthinks); | |
my $ret = 1; | |
if ($pthinks ne $cthinks) { | |
print "Have $pthinks\n"; | |
print "Want $cthinks\n"; | |
$ret = 0; | |
my $arch = (grep length, $self->splitdir($pthinks))[-1]; | |
print <<END unless $self->{UNINSTALLED_PERL}; | |
Your perl and your Config.pm seem to have different ideas about the | |
architecture they are running on. | |
Perl thinks: [$arch] | |
Config says: [$Config{archname}] | |
This may or may not cause problems. Please check your installation of perl | |
if you have problems building this extension. | |
END | |
} | |
return $ret; | |
} | |
=head2 File::Spec wrappers | |
ExtUtils::MM_Any is a subclass of L<File::Spec>. The methods noted here | |
override File::Spec. | |
=head3 catfile | |
File::Spec <= 0.83 has a bug where the file part of catfile is not | |
canonicalized. This override fixes that bug. | |
=cut | |
sub catfile { | |
my $self = shift; | |
return $self->canonpath($self->SUPER::catfile(@_)); | |
} | |
=head2 Misc | |
Methods I can't really figure out where they should go yet. | |
=head3 find_tests | |
my $test = $mm->find_tests; | |
Returns a string suitable for feeding to the shell to return all | |
tests in t/*.t. | |
=cut | |
sub find_tests { | |
my($self) = shift; | |
return -d 't' ? 't/*.t' : ''; | |
} | |
=head3 find_tests_recursive | |
my $tests = $mm->find_tests_recursive; | |
Returns a string suitable for feeding to the shell to return all | |
tests in t/ but recursively. Equivalent to | |
my $tests = $mm->find_tests_recursive_in('t'); | |
=cut | |
sub find_tests_recursive { | |
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 $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 $depth = grep { $_ ne '' } File::Spec->splitdir( $directories ); | |
$depth -= $base_depth; | |
$depths{ $depth } = 1; | |
}; | |
File::Find::find( $wanted, $dir ); | |
return join ' ', | |
map { $dir . '/*' x $_ . '.t' } | |
sort { $a <=> $b } | |
keys %depths; | |
} | |
=head3 extra_clean_files | |
my @files_to_clean = $MM->extra_clean_files; | |
Returns a list of OS specific files to be removed in the clean target in | |
addition to the usual set. | |
=cut | |
# An empty method here tickled a perl 5.8.1 bug and would return its object. | |
sub extra_clean_files { | |
return; | |
} | |
=head3 installvars | |
my @installvars = $mm->installvars; | |
A list of all the INSTALL* variables without the INSTALL prefix. Useful | |
for iteration or building related variable sets. | |
=cut | |
sub installvars { | |
return qw(PRIVLIB SITELIB VENDORLIB | |
ARCHLIB SITEARCH VENDORARCH | |
BIN SITEBIN VENDORBIN | |
SCRIPT SITESCRIPT VENDORSCRIPT | |
MAN1DIR SITEMAN1DIR VENDORMAN1DIR | |
MAN3DIR SITEMAN3DIR VENDORMAN3DIR | |
); | |
} | |
=head3 libscan | |
my $wanted = $self->libscan($path); | |
Takes a path to a file or dir and returns an empty string if we don't | |
want to include this file in the library. Otherwise it returns the | |
the $path unchanged. | |
Mainly used to exclude version control administrative directories | |
and base-level F<README.pod> from installation. | |
=cut | |
sub libscan { | |
my($self,$path) = @_; | |
if ($path =~ m<^README\.pod$>i) { | |
warn "WARNING: Older versions of ExtUtils::MakeMaker may errantly install $path as part of this distribution. It is recommended to avoid using this path in CPAN modules.\n"; | |
return ''; | |
} | |
my($dirs,$file) = ($self->splitpath($path))[1,2]; | |
return '' if grep /^(?:RCS|CVS|SCCS|\.svn|_darcs)$/, | |
$self->splitdir($dirs), $file; | |
return $path; | |
} | |
=head3 platform_constants | |
my $make_frag = $mm->platform_constants | |
Returns a make fragment defining all the macros initialized in | |
init_platform() rather than put them in constants(). | |
=cut | |
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 | |
$self->_PREREQ_PRINT; | |
Implements PREREQ_PRINT. | |
Refactored out of MakeMaker->new(). | |
=end private | |
=cut | |
sub _PREREQ_PRINT { | |
my $self = shift; | |
require Data::Dumper; | |
my @what = ('PREREQ_PM'); | |
push @what, 'MIN_PERL_VERSION' if $self->{MIN_PERL_VERSION}; | |
push @what, 'BUILD_REQUIRES' if $self->{BUILD_REQUIRES}; | |
print Data::Dumper->Dump([@{$self}{@what}], \@what); | |
exit 0; | |
} | |
=begin private | |
=head3 _PRINT_PREREQ | |
$mm->_PRINT_PREREQ; | |
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 include them. | |
Refactored out of MakeMaker->new(). | |
=end private | |
=cut | |
sub _PRINT_PREREQ { | |
my $self = shift; | |
my $prereqs= $self->{PREREQ_PM}; | |
my @prereq = map { [$_, $prereqs->{$_}] } keys %$prereqs; | |
if ( $self->{MIN_PERL_VERSION} ) { | |
push @prereq, ['perl' => $self->{MIN_PERL_VERSION}]; | |
} | |
print join(" ", map { "perl($_->[0])>=$_->[1] " } | |
sort { $a->[0] cmp $b->[0] } @prereq), "\n"; | |
exit 0; | |
} | |
=begin private | |
=head3 _perl_header_files | |
my $perl_header_files= $self->_perl_header_files; | |
returns a sorted list of header files as found in PERL_SRC or $archlibexp/CORE. | |
Used by perldepend() in MM_Unix and MM_VMS via _perl_header_files_fragment() | |
=end private | |
=cut | |
sub _perl_header_files { | |
my $self = shift; | |
my $header_dir = $self->{PERL_SRC} || $ENV{PERL_SRC} || $self->catdir($Config{archlibexp}, 'CORE'); | |
opendir my $dh, $header_dir | |
or die "Failed to opendir '$header_dir' to find header files: $!"; | |
# we need to use a temporary here as the sort in scalar context would have undefined results. | |
my @perl_headers= sort grep { /\.h\z/ } readdir($dh); | |
closedir $dh; | |
return @perl_headers; | |
} | |
=begin private | |
=head3 _perl_header_files_fragment ($o, $separator) | |
my $perl_header_files_fragment= $self->_perl_header_files_fragment("/"); | |
return a Makefile fragment which holds the list of perl header files which | |
XS code depends on $(PERL_INC), and sets up the dependency for the $(OBJECT) file. | |
The $separator argument defaults to "". MM_VMS will set it to "" and MM_UNIX to "/" | |
in perldepend(). This reason child subclasses need to control this is that in | |
VMS the $(PERL_INC) directory will already have delimiters in it, but in | |
UNIX $(PERL_INC) will need a slash between it an the filename. Hypothetically | |
win32 could use "\\" (but it doesn't need to). | |
=end private | |
=cut | |
sub _perl_header_files_fragment { | |
my ($self, $separator)= @_; | |
$separator ||= ""; | |
return join("\\\n", | |
"PERL_HDRS = ", | |
map { | |
sprintf( " \$(PERL_INCDEP)%s%s ", $separator, $_ ) | |
} $self->_perl_header_files() | |
) . "\n\n" | |
. "\$(OBJECT) : \$(PERL_HDRS)\n"; | |
} | |
=head1 AUTHOR | |
Michael G Schwern <[email protected]> and the denizens of | |
[email protected] with code from ExtUtils::MM_Unix and | |
ExtUtils::MM_Win32. | |
=cut | |
1; | |