Initial Commit

This commit is contained in:
Riley Schneider
2025-12-03 16:38:10 +01:00
parent c5e26bf594
commit b732d8d4b5
17680 changed files with 5977495 additions and 2 deletions

View File

@@ -0,0 +1,114 @@
package ExtUtils::Config;
$ExtUtils::Config::VERSION = '0.008';
use strict;
use warnings;
use Config;
use Data::Dumper ();
sub new {
my ($pack, $args) = @_;
return bless {
values => ($args ? { %$args } : {}),
}, $pack;
}
sub get {
my ($self, $key) = @_;
return exists $self->{values}{$key} ? $self->{values}{$key} : $Config{$key};
}
sub exists {
my ($self, $key) = @_;
return exists $self->{values}{$key} || exists $Config{$key};
}
sub values_set {
my $self = shift;
return { %{$self->{values}} };
}
sub all_config {
my $self = shift;
return { %Config, %{ $self->{values}} };
}
sub serialize {
my $self = shift;
return $self->{serialized} ||= Data::Dumper->new([$self->values_set])->Terse(1)->Sortkeys(1)->Dump;
}
1;
# ABSTRACT: A wrapper for perl's configuration
__END__
=pod
=encoding UTF-8
=head1 NAME
ExtUtils::Config - A wrapper for perl's configuration
=head1 VERSION
version 0.008
=head1 SYNOPSIS
my $config = ExtUtils::Config->new();
$config->get('installsitelib');
=head1 DESCRIPTION
ExtUtils::Config is an abstraction around the %Config hash. By itself it is not a particularly interesting module by any measure, however it ties together a family of modern toolchain modules.
=head1 METHODS
=head2 new(\%config)
Create a new ExtUtils::Config object. The values in C<\%config> are used to initialize the object.
=head2 get($key)
Get the value of C<$key>. If not overridden it will return the value in %Config.
=head2 exists($key)
Tests for the existence of $key.
=head2 values_set()
Get a hashref of all overridden values.
=head2 all_config()
Get a hashref of the complete configuration, including overrides.
=head2 serialize()
This method serializes the object to some kind of string.
=head1 AUTHORS
=over 4
=item *
Ken Williams <kwilliams@cpan.org>
=item *
Leon Timmermans <leont@cpan.org>
=back
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2006 by Ken Williams, Leon Timmermans.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut

View File

@@ -0,0 +1,701 @@
package ExtUtils::Depends;
use strict;
use warnings;
use Carp;
use Config;
use File::Find;
use File::Spec;
use Data::Dumper;
our $VERSION = '0.8000';
sub import {
my $class = shift;
return unless @_;
die "$class version $_[0] is required--this is only version $VERSION"
if $VERSION < $_[0];
}
sub new {
my ($class, $name, @deps) = @_;
my $self = bless {
name => $name,
deps => {},
inc => [],
libs => '',
pm => {},
typemaps => [],
xs => [],
c => [],
}, $class;
$self->add_deps (@deps);
# attempt to load these now, so we'll find out as soon as possible
# whether the dependencies are valid. we'll load them again in
# get_makefile_vars to catch any added between now and then.
$self->load_deps;
return $self;
}
sub add_deps {
my $self = shift;
foreach my $d (@_) {
$self->{deps}{$d} = undef
unless $self->{deps}{$d};
}
}
sub get_deps {
my $self = shift;
$self->load_deps; # just in case
return %{$self->{deps}};
}
sub set_inc {
my $self = shift;
push @{ $self->{inc} }, @_;
}
sub set_libs {
my ($self, $newlibs) = @_;
$self->{libs} = $newlibs;
}
sub add_pm {
my ($self, %pm) = @_;
while (my ($key, $value) = each %pm) {
$self->{pm}{$key} = $value;
}
}
sub _listkey_add_list {
my ($self, $key, @list) = @_;
$self->{$key} = [] unless $self->{$key};
push @{ $self->{$key} }, @list;
}
sub add_xs { shift->_listkey_add_list ('xs', @_) }
sub add_c { shift->_listkey_add_list ('c', @_) }
sub add_typemaps {
my $self = shift;
$self->_listkey_add_list ('typemaps', @_);
$self->install (@_);
}
# no-op, only used for source back-compat
sub add_headers { carp "add_headers() is a no-op" }
####### PRIVATE
sub basename { (File::Spec->splitdir ($_[0]))[-1] }
# get the name in Makefile syntax.
sub installed_filename {
my $self = shift;
return '$(INST_ARCHLIB)/$(FULLEXT)/Install/'.basename ($_[0]);
}
sub install {
# install things by adding them to the hash of pm files that gets
# passed through WriteMakefile's PM key.
my $self = shift;
foreach my $f (@_) {
$self->add_pm ($f, $self->installed_filename ($f));
}
}
sub save_config {
use Data::Dumper;
local $Data::Dumper::Terse = 0;
local $Data::Dumper::Sortkeys = 1;
use IO::File;
my ($self, $filename) = @_;
my $file = IO::File->new (">".$filename)
or croak "can't open '$filename' for writing: $!\n";
print $file "package $self->{name}\::Install::Files;\n\n";
print $file "".Data::Dumper->Dump([{
inc => join (" ", @{ $self->{inc} }),
libs => $self->{libs},
typemaps => [ map { basename $_ } @{ $self->{typemaps} } ],
deps => [sort keys %{ $self->{deps} }],
}], ['self']);
print $file <<'EOF';
@deps = @{ $self->{deps} };
@typemaps = @{ $self->{typemaps} };
$libs = $self->{libs};
$inc = $self->{inc};
EOF
# this is ridiculous, but old versions of ExtUtils::Depends take
# first $loadedmodule::CORE and then $INC{$file} --- the fallback
# includes the Filename.pm, which is not useful. so we must add
# this crappy code. we don't worry about portable pathnames,
# as the old code didn't either.
(my $mdir = $self->{name}) =~ s{::}{/}g;
print $file <<"EOT";
\$CORE = undef;
foreach (\@INC) {
if ( -f \$_ . "/$mdir/Install/Files.pm") {
\$CORE = \$_ . "/$mdir/Install/";
last;
}
}
sub deps { \@{ \$self->{deps} }; }
sub Inline {
my (\$class, \$lang) = \@_;
if (\$lang ne 'C') {
warn "Warning: Inline hints not available for \$lang language\n";
return;
}
+{ map { (uc(\$_) => \$self->{\$_}) } qw(inc libs typemaps) };
}
EOT
print $file "\n1;\n";
close $file;
# we need to ensure that the file we just created gets put into
# the install dir with everything else.
#$self->install ($filename);
$self->add_pm ($filename, $self->installed_filename ('Files.pm'));
}
sub load {
my $dep = shift;
my @pieces = split /::/, $dep;
my @suffix = qw/ Install Files /;
# not File::Spec - see perldoc -f require
my $relpath = join('/', @pieces, @suffix) . '.pm';
my $depinstallfiles = join "::", @pieces, @suffix;
eval {
require $relpath
} or die " *** Can't load dependency information for $dep:\n $@\n";
#print Dumper(\%INC);
# effectively $instpath = dirname($INC{$relpath})
@pieces = File::Spec->splitdir ($INC{$relpath});
pop @pieces;
my $instpath = File::Spec->catdir (@pieces);
no strict;
croak "No dependency information found for $dep"
unless $instpath;
if (not File::Spec->file_name_is_absolute ($instpath)) {
$instpath = File::Spec->rel2abs ($instpath);
}
my (@typemaps, $inc, $libs, @deps);
# this will not exist when loading files from old versions
# of ExtUtils::Depends.
@deps = eval { $depinstallfiles->deps };
@deps = @{"$depinstallfiles\::deps"}
if $@ and exists ${"$depinstallfiles\::"}{deps};
my $inline = eval { $depinstallfiles->Inline('C') };
if (!$@) {
$inc = $inline->{INC} || '';
$libs = $inline->{LIBS} || '';
@typemaps = @{ $inline->{TYPEMAPS} || [] };
} else {
$inc = ${"$depinstallfiles\::inc"} || '';
$libs = ${"$depinstallfiles\::libs"} || '';
@typemaps = @{"$depinstallfiles\::typemaps"};
}
@typemaps = map { File::Spec->rel2abs ($_, $instpath) } @typemaps;
{
instpath => $instpath,
typemaps => \@typemaps,
inc => "-I". _quote_if_space($instpath) ." $inc",
libs => $libs,
deps => \@deps,
}
}
sub _quote_if_space { $_[0] =~ / / ? qq{"$_[0]"} : $_[0] }
sub load_deps {
my $self = shift;
my @load = grep { not $self->{deps}{$_} } keys %{ $self->{deps} };
foreach my $d (@load) {
my $dep = load ($d);
$self->{deps}{$d} = $dep;
if ($dep->{deps}) {
foreach my $childdep (@{ $dep->{deps} }) {
push @load, $childdep
unless
$self->{deps}{$childdep}
or
grep {$_ eq $childdep} @load;
}
}
}
}
sub uniquify {
my %seen;
# we use a seen hash, but also keep indices to preserve
# first-seen order.
my $i = 0;
foreach (@_) {
$seen{$_} = ++$i
unless exists $seen{$_};
}
#warn "stripped ".(@_ - (keys %seen))." redundant elements\n";
sort { $seen{$a} <=> $seen{$b} } keys %seen;
}
sub get_makefile_vars {
my $self = shift;
# collect and uniquify things from the dependencies.
# first, ensure they are completely loaded.
$self->load_deps;
##my @defbits = map { split } @{ $self->{defines} };
my @incbits = map { split } @{ $self->{inc} };
my @libsbits = split /\s+/, $self->{libs};
my @typemaps = @{ $self->{typemaps} };
foreach my $d (sort keys %{ $self->{deps} }) {
my $dep = $self->{deps}{$d};
#push @defbits, @{ $dep->{defines} };
push @incbits, @{ $dep->{defines} } if $dep->{defines};
push @incbits, split /\s+/, $dep->{inc} if $dep->{inc};
push @libsbits, split /\s+/, $dep->{libs} if $dep->{libs};
push @typemaps, @{ $dep->{typemaps} } if $dep->{typemaps};
}
# we have a fair bit of work to do for the xs files...
my @clean = ();
my @OBJECT = ();
my %XS = ();
foreach my $xs (@{ $self->{xs} }) {
(my $c = $xs) =~ s/\.xs$/\.c/i;
(my $o = $xs) =~ s/\.xs$/\$(OBJ_EXT)/i;
$XS{$xs} = $c;
push @OBJECT, $o;
# according to the MakeMaker manpage, the C files listed in
# XS will be added automatically to the list of cleanfiles.
push @clean, $o;
}
# we may have C files, as well:
foreach my $c (@{ $self->{c} }) {
(my $o = $c) =~ s/\.c$/\$(OBJ_EXT)/i;
push @OBJECT, $o;
push @clean, $o;
}
my %vars = (
INC => join (' ', uniquify @incbits),
LIBS => join (' ', uniquify $self->find_extra_libs, @libsbits),
TYPEMAPS => [@typemaps],
);
$self->build_dll_lib(\%vars) if $^O =~ /MSWin32/;
# we don't want to provide these if there is no data in them;
# that way, the caller can still get default behavior out of
# MakeMaker when INC, LIBS and TYPEMAPS are all that are required.
$vars{PM} = $self->{pm}
if %{ $self->{pm} };
$vars{clean} = { FILES => join (" ", @clean), }
if @clean;
$vars{OBJECT} = join (" ", @OBJECT)
if @OBJECT;
$vars{XS} = \%XS
if %XS;
%vars;
}
sub build_dll_lib {
my ($self, $vars) = @_;
$vars->{macro} ||= {};
$vars->{macro}{'INST_DYNAMIC_LIB'} =
'$(INST_ARCHAUTODIR)/$(DLBASE)$(LIB_EXT)';
}
# Search for extra library files to link against on Windows (either native
# Windows library # files, or Cygwin library files)
# NOTE: not meant to be called publicly, so no POD documentation
sub find_extra_libs {
my $self = shift;
my %mappers = (
MSWin32 => sub { $_[0] . '\.(?:lib|a)' },
cygwin => sub { $_[0] . '\.dll'},
android => sub { $_[0] . '\.' . $Config{dlext} },
);
my $mapper = $mappers{$^O};
return () unless defined $mapper;
my @found_libs = ();
foreach my $name (keys %{ $self->{deps} }) {
(my $stem = $name) =~ s/^.*:://;
if ( defined &DynaLoader::mod2fname ) {
my @parts = split /::/, $name;
$stem = DynaLoader::mod2fname([@parts]);
}
my $lib = $mapper->($stem);
my $pattern = qr/$lib$/;
my $matching_dir;
my $matching_file;
find (sub {
if ((not $matching_file) && /$pattern/) {;
$matching_dir = $File::Find::dir;
$matching_file = $File::Find::name;
}
}, map { -d $_ ? ($_) : () } @INC); # only extant dirs
if ($matching_file && -f $matching_file) {
push @found_libs,
'-L' . _quote_if_space($matching_dir),
'-l' . $stem;
# Android's linker ignores the RTLD_GLOBAL flag
# and loads everything as if under RTLD_LOCAL.
# What this means in practice is that modules need
# to explicitly link to their dependencies,
# because otherwise they won't be able to locate any
# functions they define.
# We use the -l:foo.so flag to indicate that the
# actual library name to look for is foo.so, not
# libfoo.so
if ( $^O eq 'android' ) {
$found_libs[-1] = "-l:$stem.$Config{dlext}";
}
next;
}
}
return @found_libs;
}
# Hook into ExtUtils::MakeMaker to create an import library on MSWin32 when gcc
# is used. FIXME: Ideally, this should be done in EU::MM itself.
package # wrap to fool the CPAN indexer
ExtUtils::MM;
use Config;
sub static_lib {
my $base = shift->SUPER::static_lib(@_);
return $base unless $^O =~ /MSWin32/ && $Config{cc} =~ /\bgcc\b/i;
my $DLLTOOL = $Config{'dlltool'} || 'dlltool';
return <<"__EOM__"
# This isn't actually a static lib, it just has the same name on Win32.
\$(INST_DYNAMIC_LIB): \$(INST_DYNAMIC)
$DLLTOOL --def \$(EXPORT_LIST) --output-lib \$\@ --dllname \$(DLBASE).\$(DLEXT) \$(INST_DYNAMIC)
dynamic:: \$(INST_DYNAMIC_LIB)
__EOM__
}
1;
__END__
=head1 NAME
ExtUtils::Depends - Easily build XS extensions that depend on XS extensions
=head1 SYNOPSIS
use ExtUtils::Depends;
$package = new ExtUtils::Depends ('pkg::name', 'base::package')
# set the flags and libraries to compile and link the module
$package->set_inc("-I/opt/blahblah");
$package->set_libs("-lmylib");
# add a .c and an .xs file to compile
$package->add_c('code.c');
$package->add_xs('module-code.xs');
# add the typemaps to use
$package->add_typemaps("typemap");
# install some extra data files and headers
$package->install (qw/foo.h data.txt/);
# save the info
$package->save_config('Files.pm');
WriteMakefile(
'NAME' => 'Mymodule',
$package->get_makefile_vars()
);
=head1 DESCRIPTION
This module tries to make it easy to build Perl extensions that use
functions and typemaps provided by other perl extensions. This means
that a perl extension is treated like a shared library that provides
also a C and an XS interface besides the perl one.
This works as long as the base extension is loaded with the RTLD_GLOBAL
flag (usually done with a
sub dl_load_flags {0x01}
in the main .pm file) if you need to use functions defined in the module.
The basic scheme of operation is to collect information about a module
in the instance, and then store that data in the Perl library where it
may be retrieved later. The object can also reformat this information
into the data structures required by ExtUtils::MakeMaker's WriteMakefile
function.
For information on how to make your module fit into this scheme, see
L</"hashref = ExtUtils::Depends::load (name)">.
When creating a new Depends object, you give it a name, which is the name
of the module you are building. You can also specify the names of modules
on which this module depends. These dependencies will be loaded
automatically, and their typemaps, header files, etc merged with your new
object's stuff. When you store the data for your object, the list of
dependencies are stored with it, so that another module depending on your
needn't know on exactly which modules yours depends.
For example:
Gtk2 depends on Glib
Gnome2::Canvas depends on Gtk2
ExtUtils::Depends->new ('Gnome2::Canvas', 'Gtk2');
this command automatically brings in all the stuff needed
for Glib, since Gtk2 depends on it.
When the configuration information is saved, it also includes a class
method called C<Inline>, inheritable by your module. This allows you in
your module to simply say at the top:
package Mymod;
use parent 'Mymod::Install::Files'; # to inherit 'Inline' method
And users of C<Mymod> who want to write inline code (using L<Inline>)
will simply be able to write:
use Inline with => 'Mymod';
And all the necessary header files, defines, and libraries will be added
for them.
The C<Mymod::Install::Files> will also implement a C<deps> method,
which will return a list of any modules that C<Mymod> depends on -
you will not normally need to use this:
require Mymod::Install::Files;
@deps = Mymod::Install::Files->deps;
=head1 METHODS
=over
=item $object = ExtUtils::Depends->new($name, @deps)
Create a new depends object named I<$name>. Any modules listed in I<@deps>
(which may be empty) are added as dependencies and their dependency
information is loaded. An exception is raised if any dependency information
cannot be loaded.
=item $depends->add_deps (@deps)
Add modules listed in I<@deps> as dependencies.
=item (hashes) = $depends->get_deps
Fetch information on the dependencies of I<$depends> as a hash of hashes,
which are dependency information indexed by module name. See C<load>.
=item $depends->set_inc (@newinc)
Add strings to the includes or cflags variables.
=item $depends->set_libs (@newlibs)
Add strings to the libs (linker flags) variable.
=item $depends->add_pm (%pm_files)
Add files to the hash to be passed through ExtUtils::WriteMakefile's
PM key.
=item $depends->add_xs (@xs_files)
Add xs files to be compiled.
=item $depends->add_c (@c_files)
Add C files to be compiled.
=item $depends->add_typemaps (@typemaps)
Add typemap files to be used and installed.
=item $depends->add_headers (list)
No-op, for backward compatibility.
=item $depends->install (@files)
Install I<@files> to the data directory for I<$depends>.
This actually works by adding them to the hash of pm files that gets
passed through WriteMakefile's PM key.
=item $depends->save_config ($filename)
Save the important information from I<$depends> to I<$filename>, and
set it up to be installed as I<name>::Install::Files.
Note: the actual value of I<$filename> is unimportant so long as it
doesn't clash with any other local files. It will be installed as
I<name>::Install::Files.
=item hash = $depends->get_makefile_vars
Return the information in I<$depends> in a format digestible by
WriteMakefile.
This sets at least the following keys:
INC
LIBS
TYPEMAPS
PM
And these if there is data to fill them:
clean
OBJECT
XS
=item hashref = ExtUtils::Depends::load (name)
Load and return dependency information for I<name>. Croaks if no such
information can be found. The information is returned as an anonymous
hash containing these keys:
=over
=item instpath
The absolute path to the data install directory for this module.
=item typemaps
List of absolute pathnames for this module's typemap files.
=item inc
CFLAGS string for this module.
=item libs
LIBS string for this module.
=item deps
List of modules on which this one depends. This key will not exist when
loading files created by old versions of ExtUtils::Depends.
=back
If you want to make module I<name> support this, you must provide
a module I<name>::Install::Files, which on loading will implement the
following class methods:
$hashref = name::Install::Files->Inline('C');
# hash to contain any necessary TYPEMAPS (array-ref), LIBS, INC
@deps = name::Install::Files->deps;
# any modules on which "name" depends
An easy way to achieve this is to use the method
L</"$depends-E<gt>save_config ($filename)">, but your package may have
different facilities already.
=item $depends->load_deps
Load I<$depends> dependencies, by calling C<load> on each dependency module.
This is usually done for you, and should only be needed if you want to call
C<get_deps> after calling C<add_deps> manually.
=back
=head1 SUPPORT
=head2 Bugs/Feature Requests
Version 0.2 discards some of the more esoteric features provided by the
older versions. As they were completely undocumented, and this module
has yet to reach 1.0, this may not exactly be a bug.
This module is tightly coupled to the ExtUtils::MakeMaker architecture.
You can submit new bugs/feature requests by using one of two bug trackers
(below).
=over
=item CPAN Request Tracker
You can submit bugs/feature requests via the web by going to
L<https://rt.cpan.org/Public/Bug/Report.html?Queue=ExtUtils-Depends> (requires
PAUSE ID or Bitcard), or by sending an e-mail to
L<bug-ExtUtils-Depends at rt.cpan.org>.
=item Gnome.org Bugzilla
Report bugs/feature requests to the 'gnome-perl' product (requires login)
L<http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-perl>
=back
Patches that implement new features with test cases, and/or test cases that
exercise existing bugs are always welcome.
The Gtk-Perl mailing list is at L<gtk-perl-list at gnome dot org>.
=head2 Source Code
The source code to L<ExtUtils::Depends> is available at the Gnome.org Git repo
(L<https://git.gnome.org/browse/perl-ExtUtils-Depends/>). Create your own
copy of the Git repo with:
git clone git://git.gnome.org/perl-ExtUtils-Depends (Git protocol)
git clone https://git.gnome.org/browse/perl-ExtUtils-Depends/ (HTTPS)
=head1 SEE ALSO
ExtUtils::MakeMaker.
=head1 AUTHOR
Paolo Molaro <lupus at debian dot org> wrote the original version for
Gtk-Perl. muppet <scott at asofyet dot org> rewrote the innards for
version 0.2, borrowing liberally from Paolo's code.
=head1 MAINTAINER
The Gtk2 project, L<http://gtk2-perl.sf.net>/L<gtk-perl-list at gnome dot org>.
=head1 LICENSE
This library is free software; you may redistribute it and/or modify it
under the same terms as Perl itself.
=cut

749
database/perl/vendor/lib/ExtUtils/F77.pm vendored Normal file
View File

@@ -0,0 +1,749 @@
package ExtUtils::F77;
use strict;
use warnings;
use Config;
use File::Spec;
use Text::ParseWords;
use File::Which qw(which);
use List::Util qw(first);
our $VERSION = "1.24";
our $DEBUG;
sub debug { return if !$DEBUG; warn @_ }
print "Loaded ExtUtils::F77 version $VERSION\n";
my %F77config=();
my $Runtime = "-LSNAFU -lwontwork";
my $RuntimeOK = 0;
my $Trail_ = 1;
my $Pkg = "";
my $Compiler = "";
my $Cflags = "";
my ($gcc, $gfortran, $fallback_compiler);
# all the compilers and their libraries
my %COMPLIBS = (
g77 => [qw/ g2c f2c /],
f77 => [qw/ g2c f2c /],
fort77 => [qw/ g2c f2c /],
gfortran => [qw/ gfortran /],
g95 => [qw/ f95 /],
);
########## Win32 Specific ##############
if ($^O =~ /MSWin/i) {
my @version;
if ($Config{cc} =~ /x86_64\-w64\-mingw32\-gcc/) {
# This must be gcc-4.x.x
$gcc = 'x86_64-w64-mingw32-gcc';
$gfortran = 'x86_64-w64-mingw32-gfortran';
$fallback_compiler = 'GFortran';
}
elsif ($Config{gccversion}) {
# Different fortran compiler for gcc-4.x.x (and later) versus gcc-3.x.x
$gcc = 'gcc';
@version = split /\./, $Config{gccversion};
$fallback_compiler = $version[0] >= 4 ? 'GFortran' : 'G77';
$gfortran = 'gfortran';
}
else {
$gcc = 'gcc';
$gfortran = 'gfortran';
$fallback_compiler = 'G77';
}
}
else {
# No change from version 1.16.
$gcc = 'gcc';
$gfortran = 'gfortran';
$fallback_compiler = 'G77';
}
############## End of Win32 Specific ##############
# Database starts here. Basically we have a large hash specifying
# entries for each os/compiler combination. Entries can be code refs
# in which case they are executed and the returned value used. This
# allows us to be quite smart.
# Hash key convention is uppercase first letter of
# hash keys. First key is usually the name of the architecture as
# returned by Config (modulo ucfirst()).
# Format is: OS, then compiler-family, then specific keys:
# DEFAULT: as a compiler-family, gives name of default compiler-family - corresponds to one of the keys
# Link: Code to figure out and return link-string for this architecture
# Returns false if it can't find anything sensible.
# Trail_: Whether symbols (subroutine names etc.) have trailing underscores
# (true/false)
# Compiler: Program to run to actually compile stuff
# Cflags: Associated compiler flags
sub gfortran_make_linkline {
my ($dir, $lib, $defaultdir, $defaultlib, $append) = @_;
$dir ||= $defaultdir;
$lib ||= $defaultlib;
$append ||= '';
return( qq{"-L$dir" -L/usr/lib -l$lib $append -lm} );
}
sub gfortran_find_libdir {
my ($compiler, $lib) = @_;
for my $suffix (qw(a so)) {
my $filename = "lib$lib.$suffix";
my $dir = `$compiler -print-file-name=$filename`;
chomp $dir;
# Note that -print-file-name returns just the library name
# if it cant be found - make sure that we only accept the
# directory if it returns a proper path (or matches a /)
next if !defined $dir or $dir eq $lib;
$dir =~ s,/$filename$,,;
return $dir;
}
}
$F77config{MinGW}{G77}{Link} = sub {
my @libs = ('g2c', 'f2c');
my ($dir, $lib, $test);
foreach $test (@libs) {
$dir = gfortran_find_libdir('g77', $test);
$lib = $test, last if defined $dir;
}
gfortran_make_linkline($dir, $lib, "/usr/local/lib", "f2c");
};
$F77config{MinGW}{G77}{Trail_} = 1;
$F77config{MinGW}{G77}{Compiler} = find_in_path('g77','f77','fort77');
$F77config{MinGW}{G77}{Cflags} = '-O';
$F77config{MinGW}{GFortran}{Link} = sub {
my $dir = gfortran_find_libdir($gfortran, 'gfortran');
gfortran_make_linkline($dir, "gfortran", "/usr/local/lib", "", '-lquadmath');
};
$F77config{MinGW}{GFortran}{Trail_} = 1;
$F77config{MinGW}{GFortran}{Compiler} = "$gfortran";
$F77config{MinGW}{GFortran}{Cflags} = '-O';
### SunOS (use this as a template for new entries) ###
$F77config{Sunos}{F77}{Link} = sub {
my $dir = find_highest_SC("/usr/lang/SC*");
return "" unless $dir; # Failure
debug "$Pkg: Found Fortran latest version lib dir $dir\n";
return qq{"-L$dir" -lF77 -lm};
};
$F77config{Sunos}{F77}{Trail_} = 1;
$F77config{Sunos}{F77}{Compiler} = 'f77';
$F77config{Sunos}{F77}{Cflags} = '-O';
$F77config{Sunos}{DEFAULT} = 'F77';
############ Rest of database is here ############
### Solaris ###
$F77config{Solaris}{F77}{Link} = sub {
my $NSPATH;
my $dir;
#find the SUNWspro entry of nonstandard inst. in LD_LIBRARY_PATH
if ( defined $ENV{'LD_LIBRARY_PATH'} &&
$ENV{'LD_LIBRARY_PATH'} =~ m{([^:]*SUNWspro[^/]*)} )
{
$NSPATH = $1;
}
elsif ( defined $ENV{'PATH'} ) {
foreach ( split (/:/,$ENV{PATH}) ) {
if ( m{(.*SUNWspro[^/]*)} ) {
$NSPATH = $1;
last;
}
}
}
if (defined $NSPATH) {
debug "$Pkg: Found F77 path:--->$NSPATH\n";
$dir = find_highest_SC("$NSPATH/WS*/lib") ||
find_highest_SC("$NSPATH/SC*/lib") ||
find_highest_SC("$NSPATH/sunwspro*/SUNWspro/SC*/lib");
# that failed. try $NSPATH/lib. use glob to
# match for libF77.*, as libF77.a isn't there anymore?
unless ( $dir )
{
debug "$Pkg: Trying $NSPATH/lib\n";
$dir = "$NSPATH/lib" if glob("$NSPATH/lib/libF77*");
}
}
return "" unless $dir; # Failure
debug "$Pkg: Found Fortran latest version lib dir $dir\n";
my @libs;
# determine libraries. F77 and M77 aren't available in the latest
# compilers
my $vcruft = qx/$F77config{Solaris}{F77}{Compiler} -V 2>&1/;
if ( $vcruft =~ /Forte Developer 7/
|| $vcruft =~ /f90:/
)
{
push @libs, qw/
-lf77compat
-lfui
-lfai
-lfai2
-lfsumai
-lfprodai
-lfminlai
-lfmaxlai
-lfminvai
-lfmaxvai
-lfsu
-lsunmath
-lm
/;
}
else
{
push @libs, qw/
-lF77
-lM77
-lsunmath
-lm
/;
}
join( ' ', qq{"-L$dir"}, @libs );
};
$F77config{Solaris}{F77}{Trail_} = 1;
$F77config{Solaris}{F77}{Compiler} = 'f77';
$F77config{Solaris}{F77}{Cflags} = '-O';
$F77config{Solaris}{DEFAULT} = 'F77';
### Generic GNU-77 or F2C system ###
$F77config{Generic}{GNU}{Trail_} = 1;
$F77config{Generic}{GNU}{Cflags} = ' '; # <---need this space!
$F77config{Generic}{GNU}{Link} = link_gnufortran_compiler('gfortran', 'g77', 'g95', 'fort77');
$F77config{Generic}{GNU}{Compiler} = find_in_path("$gfortran", 'g77', 'g95','fort77');
$F77config{Generic}{DEFAULT} = 'GNU';
### cygwin ###
$F77config{Cygwin}{GNU}{Trail_} = 1;
$F77config{Cygwin}{GNU}{Cflags} = '-O'; # <---need this space!
$F77config{Cygwin}{GNU}{Link} = link_gnufortran_compiler('g77', 'gfortran', 'g95', 'fort77');
$F77config{Cygwin}{GNU}{Compiler} = find_in_path('g77', "$gfortran", 'g95','fort77');
$F77config{Cygwin}{DEFAULT} = 'GNU';
### Linux ###
$F77config{Linux}{GNU} = $F77config{Generic}{GNU};
$F77config{Linux}{DEFAULT} = 'GNU';
### DEC OSF/1 ###
$F77config{Dec_osf}{F77}{Link} = "-L/usr/lib -lUfor -lfor -lFutil -lm -lots -lc";
$F77config{Dec_osf}{F77}{Trail_} = 1;
$F77config{Dec_osf}{F77}{Compiler} = 'f77';
$F77config{Dec_osf}{F77}{Cflags} = '-O';
$F77config{Dec_osf}{DEFAULT} = 'F77';
### HP/UX ###
$F77config{Hpux}{F77}{Link} = "-L/usr/lib -lcl -lm";
$F77config{Hpux}{F77}{Trail_} = 0;
$F77config{Hpux}{F77}{Compiler} = 'f77';
$F77config{Hpux}{F77}{Cflags} = '-O';
$F77config{Hpux}{DEFAULT} = 'F77';
### IRIX ###
# From: Ovidiu Toader <ovi@physics.utoronto.ca>
# For an SGI running IRIX 6.4 or higher (probably lower than 6.4 also)
# there is a new abi, -64, which produces 64 bit executables. This is no
# longer an experimental feature and I am using it exclusively without any
# problem. The code below is what I use instead of original IRIX section
# in the ExtUtils::F77 package. It adds the -64 flag and it is supposed to
# provide the same functionality as the old code for a non -64 abi.
if (ucfirst($Config{'osname'}) eq "Irix")
{
my ($cflags,$mips,$default_abi,$abi,$mips_dir,$libs);
$cflags = $Config{cc};
($mips) = ($cflags =~ /(-mips\d)/g);
$mips = "" if ! defined($mips);
$mips_dir = $mips;$mips_dir =~ s/-//g;
$default_abi = $Config{osvers} >= 6.4 ? "-n32" : "-o32";
GET_ABI:
{
# -32 seems to be synonymous for -o32 (CS)
$abi = "-o32",last GET_ABI if $cflags =~ /-o?32/;
$abi = "-n32",last GET_ABI if $cflags =~ /-n32/;
$abi = "-64",last GET_ABI if $cflags =~ /-64/;
$abi = $default_abi;
}
if ( $abi eq "-64" ){
$libs = ( (-r "/usr/lib64/$mips_dir") && (-d _) && (-x _) ) ?
"-L/usr/lib64/$mips_dir" : "";
$libs .= " -L/usr/lib64 -lfortran -lm";
}
if ( $abi eq "-n32" ){
$libs = ( (-r "/usr/lib32/$mips_dir") && (-d _) && (-x _) ) ?
"-L/usr/lib32/$mips_dir" : "";
$libs .= " -L/usr/lib32 -lfortran -lm";
}
if ( $abi eq "-o32" ){
$libs = "-L/usr/lib -lF77 -lI77 -lU77 -lisam -lm";
}
$F77config{Irix}{F77}{Cflags} = "$abi $mips";
$F77config{Irix}{F77}{Link} = "$libs";
$F77config{Irix}{F77}{Trail_} = 1;
$F77config{Irix}{F77}{Compiler} = "f77 $abi";
$F77config{Irix}{DEFAULT} = 'F77';
}
### AIX ###
$F77config{Aix}{F77}{Link} = "-L/usr/lib -lxlf90 -lxlf -lc -lm";
$F77config{Aix}{F77}{Trail_} = 0;
$F77config{Aix}{DEFAULT} = 'F77';
### FreeBSD ###
if($^O =~ /Freebsd/i) {
$gfortran = 'gfortran48'; # requires rewrite
$fallback_compiler = 'G77';
}
$F77config{Freebsd}{G77}{Link} = sub {
my $dir = gfortran_find_libdir('g77-34', 'g2c');
gfortran_make_linkline($dir, 'g2c', "/usr/local/lib", '');
};
$F77config{Freebsd}{G77}{Trail_} = 1;
$F77config{Freebsd}{G77}{Compiler} = 'g77-34';
$F77config{Freebsd}{G77}{Cflags} = '-O2';
$F77config{Freebsd}{GFortran}{Link} = sub {
my $dir = gfortran_find_libdir($gfortran, 'gfortran');
gfortran_make_linkline($dir, "gfortran", "/usr/local/lib", "");
};
$F77config{Freebsd}{GFortran}{Trail_} = 1;
$F77config{Freebsd}{GFortran}{Compiler} = "$gfortran";
$F77config{Freebsd}{GFortran}{Cflags} = '-O2';
$F77config{Freebsd}{DEFAULT} = 'GFortran';
### VMS ###
$F77config{VMS}{Fortran}{Link} = ' '; # <---need this space!
$F77config{VMS}{Fortran}{Trail_} = 0;
$F77config{VMS}{Fortran}{Compiler} = 'Fortran';
$F77config{VMS}{DEFAULT} = 'Fortran';
### Darwin (Mac OS X) ###
$F77config{Darwin}{GNU} = $F77config{Generic}{GNU};
$F77config{Darwin}{DEFAULT} = 'GNU';
############ End of database is here ############
sub get; # See below
# All the figuring out occurs during import - this is because
# a lot of the answers depend on a lot of the guesswork.
sub import {
no warnings; # Shuts up complaints on Win32 when running PDL tests
$Pkg = shift;
my $system = ucfirst(shift); # Set package variables
my $compiler = ucfirst(shift);
$Runtime = "-LSNAFU -lwontwork";
# Guesses if system/compiler not specified.
$system = ucfirst $Config{'osname'} unless $system;
$system = 'Cygwin' if $system =~ /Cygwin/;
$compiler = get $F77config{$system}{DEFAULT} unless $compiler;
debug "$Pkg: Using system=$system compiler=" .
(defined $compiler ? $compiler : "<undefined>") . "\n";
if (defined($ENV{F77LIBS})) {
debug "Overriding Fortran libs from value of enviroment variable F77LIBS = $ENV{F77LIBS}\n";
$Runtime = $ENV{F77LIBS};
}
else {
# Try this combination
my $ok;
if ( defined( $compiler ) and defined( $F77config{$system} )){
my $flibs = get ($F77config{$system}{$compiler}{Link});
if ($flibs ne "") {
$Runtime = $flibs;# . gcclibs();
# We don't want to append gcc libs if we are using
# non gnu compilers. Initially, explicitly check for
# use of sun compiler
#$Runtime .= gcclibs($flibs) unless $flibs =~ /sunmath/;
#(Note appending gcclibs seems to be no longer required)
$Runtime =~ s|L([a-z,A-Z]):|L//$1|g if $^O =~ /cygwin/i;
$Runtime = ' ' if $^O eq 'VMS'; # <-- need this space!
debug "Runtime: $Runtime\n";
$ok = 1;
if ($compiler eq 'GNU') { # Special gfortran case since it seems to have lots of random libs
debug "Found compiler=$compiler - skipping validation of $Runtime \n";
} else {
$ok = validate_libs($Runtime) if $flibs ne "" ;
}
}
} else {
$Runtime = $ok = "";
}
# If it doesn't work try Generic + GNU77
unless (("$Runtime" ne "-LSNAFU -lwontwork") && $ok) {
$system =
$Config{cc} =~ /\bgcc/ && $^O =~ /MSWin32/i ? "MinGW"
: $^O =~ /Freebsd/i ? "Freebsd"
:"Generic";
$compiler = $fallback_compiler;
warn <<"EOD";
$Pkg: Unable to guess and/or validate system/compiler configuration
$Pkg: Will try system=$system Compiler=$compiler
EOD
my $flibs = get ($F77config{$system}{$compiler}{Link});
$Runtime = $flibs ; #. gcclibs($flibs); # Note gcclibs appears to be no longer required.
$ok = validate_libs($Runtime) if $flibs ne "";
warn "$Pkg: Well that didn't appear to validate. Well I will try it anyway.\n"
unless $Runtime && $ok;
}
$RuntimeOK = $ok;
} # Not overriding
# Now get the misc info for the methods.
if (defined( $F77config{$system}{$compiler}{Trail_} )){
$Trail_ = get $F77config{$system}{$compiler}{Trail_};
} else {
warn << "EOD";
$Pkg: There does not appear to be any configuration info about
$Pkg: names with trailing underscores for system $system. Will assume
$Pkg: F77 names have trailing underscores.
EOD
$Trail_ = 1;
}
if (defined( $F77config{$system}{$compiler}{Compiler} )) {
$Compiler = get $F77config{$system}{$compiler}{Compiler};
} else {
warn << "EOD";
$Pkg: There does not appear to be any configuration info about
$Pkg: the F77 compiler name. Will assume 'f77'.
EOD
$Compiler = 'f77';
}
debug "$Pkg: Compiler: $Compiler\n";
if (defined( $F77config{$system}{$compiler}{Cflags} )) {
$Cflags = get $F77config{$system}{$compiler}{Cflags} ;
} else {
warn << "EOD";
$Pkg: There does not appear to be any configuration info about
$Pkg: the options for the F77 compiler. Will assume none
$Pkg: necessary.
EOD
$Cflags = '';
}
debug "$Pkg: Cflags: $Cflags\n";
} # End of import ()
sub runtime { return $Runtime; }
sub runtimeok { return $RuntimeOK; }
sub trail_ { return $Trail_; }
sub compiler { return $Compiler; }
sub cflags { return $Cflags; }
### Minor internal utility routines ###
# Get hash entry, evaluating code references
sub get { ref($_[0]) eq "CODE" ? &{$_[0]} : $_[0] };
# Test if any files exist matching glob
sub any_exists {
my @glob = glob(shift);
return scalar(@glob);
}
# Find highest version number of SCN.N(.N) directories
# (Nasty SunOS/Solaris naming scheme for F77 libs]
sub find_highest_SC {
debug "$Pkg: Scanning for $_[0]\n";
my @glob = glob(shift);
my %n=();
for (@glob) {
#debug "Found $_\n";
if ( m|/SC(\d)\.(\d)/?.*$| ) {
$n{$_} = $1 *100 + $2 * 10;
}
if ( m|/SC(\d)\.(\d)\.(\d)/?.*$| ) {
$n{$_} = $1 *100 + $2 * 10 + $3;
}
}
my @sorted_dirs = grep {-f "$_/libF77.a"} sort {$n{$a} <=> $n{$b}} @glob;
return pop @sorted_dirs; # Highest N
}
# Validate a string of form "-Ldir -lfoo -lbar"
sub validate_libs {
debug "$Pkg: Validating $_[0] ";
my @args = shellwords(shift());
my $pat;
my $ret = 1;
# Create list of directories to search (with common defaults)
my @path = ();
for (@args, "/usr/lib", "/lib") {
push @path, $1 if /^-L(.+)$/ && -d $1;
}
# Search directories
for (@args) {
next if /^-L/;
next if $_ eq "-lm"; # Ignore this common guy
if (/^-l(.+)$/) {
$pat = join(" ", map {$_."/lib".$1.".*"} @path); # Join dirs + file
#debug "Checking for $pat\n";
unless (any_exists($pat)) {
debug "\n$Pkg: Unable to find library $_" ;
$ret = 0;
}
}
}
debug $ret ? "[ok]\n" : "\n";
return $ret;
}
sub testcompiler {
my $file = File::Spec->tmpdir . "/testf77$$";
$file =~ s/\\/\//g; # For Win32
my $ret;
open(OUT,">$file.f");
print OUT " write(*,*) 'Hello World'\n";
print OUT " end\n";
close(OUT);
debug "Compiling the test Fortran program...\n";
system "$Compiler $Cflags $file.f -o ${file}_exe";
debug "Executing the test program...\n";
if (`${file}_exe` ne " Hello World\n") {
warn "Test of Fortran Compiler FAILED. \n";
warn "Do not know how to compile Fortran on your system\n";
$ret=0;
}
else{
debug "Congratulations you seem to have a working f77!\n";
$ret=1;
}
unlink("${file}_exe"); unlink("$file.f"); unlink("$file.o") if -e "$file.o";
return $ret;
};
# gcclibs() routine
# Return gcc link libs (e.g. -L/usr/local/lib/gcc-lib/sparc-sun-sunos4.1.3_U1/2.7.0 -lgcc)
# Note this routine appears to be no longer required - gcc3 or 4 change? - and is
# NO LONGER CALLED from anywhere in the code. Use of this routine in the future
# is DEPRECATED. Retain here just in case this logic is ever needed again,
# - Karl Glazebrook Dec/2010
sub gcclibs {
my $flibs = shift; # Fortran libs
my $isgcc = $Config{'cc'} eq "$gcc";
if (!$isgcc && $^O ne 'VMS') {
debug "Checking for gcc in disguise:\n";
$isgcc = 1 if $Config{gccversion};
my $string;
if ($isgcc) {
$string = "Compiler is gcc version $Config{gccversion}";
$string .= "\n" unless $string =~ /\n$/;
} else {
$string = "Not gcc\n";
}
debug $string;
}
if ($isgcc or ($flibs =~ /-lg2c/) or ($flibs =~ /-lf2c/) ) {
# Don't link to libgcc on MS Windows iff we're using gfortran.
unless ($fallback_compiler eq 'GFortran' && $^O =~ /MSWin/i) {
my $gccdir = `$gcc -m32 -print-libgcc-file-name`; chomp $gccdir;
$gccdir =~ s/\/libgcc.a//;
return qq{ "-L$gccdir" -lgcc};
} else {
return "";
}
}else{
return "";
}
}
# Try and find a program in the users PATH
sub find_in_path {
my $found = first { which $_ } @_;
return ($^O eq 'VMS' ? '' : undef) if !$found;
debug "Found compiler $found\n";
return $found;
}
# Based on code from Tim Jeness, tries to figure out the correct GNU
# fortran compiler libs
sub link_gnufortran_compiler {
return () if $^O =~ /MSWin32/i; # Unneeded for MinGW, emits warnings if allowed to proceed.
my @try = @_;
my $compiler = find_in_path( @try );
return () unless defined $compiler;
# Get compiler version number
my @t =`$compiler --version`; $t[0] =~ /(\d+).(\d)+.(\d+)/;
my $version = "$1.$2"; # Major version number
debug "ExtUtils::F77: $compiler version $version.$3\n";
# Sigh special case random extra gfortran libs to avoid PERL_DL_NONLAZY meltdowns. KG 25/10/2015
my $append = "";
if ( $Config{osname} =~ /darwin/ && $Config{osvers} >= 14
&& $compiler eq 'gfortran' && $version >= 4.9 ) {
# Add extra libs for gfortran versions >= 4.9 and OS X
$append = "-lgcc_ext.10.5 -lgcc_s.10.5 -lquadmath";
}
my @libs = @{$COMPLIBS{$compiler}};
my ($dir, $lib, $test);
foreach $test (@libs) {
$dir = gfortran_find_libdir($compiler, $test);
$lib = $test, last if defined $dir;
}
gfortran_make_linkline($dir, $lib, "/usr/local/lib", "f2c", $append);
}
1; # Return true
__END__
=head1 NAME
ExtUtils::F77 - Simple interface to F77 libs
=head1 DESCRIPTION
This module tries to figure out how to link C programs with
Fortran subroutines on your system. Basically one must add a list
of Fortran runtime libraries. The problem is their location
and name varies with each OS/compiler combination! It was originally
developed to make building and installation of the L<PGPLOT> module easier,
which links to the pgplot Fortran graphics library. It is now used by a numnber
of perl modules.
This module tries to implement a simple
'rule-of-thumb' database for various flavours of UNIX systems.
A simple self-documenting Perl database of knowledge/code
for figuring out how to link for various combinations of OS and
compiler is embedded in the modules Perl code. Please help
save the world by submitted patches for new database entries for
your system at L<https://github.com/PDLPorters/extutils-f77>
Note the default on most systems is now to search for a generic 'GNU' compiler
which can be gfortran, g77, g95 or fort77 (in that order based on usage) and then find
the appropriate link libraries automatically. (This is the 'Generic' 'GNU' database entry
in the code.)
The library list which the module returns
can be explicitly overridden by setting the environment
variable F77LIBS, e.g.
% setenv F77LIBS "-lfoo -lbar"
% perl -MExtUtils::F77 -e 'print ExtUtils::F77->compiler, "\n"'
...
=head1 SYNOPSIS
use ExtUtils::F77; # Automatic guess
use ExtUtils::F77 qw(sunos); # Specify system
use ExtUtils::F77 qw(linux g77); # Specify system and compiler
$fortranlibs = ExtUtils::F77->runtime;
=head1 METHODS
The following are all class methods.
=head2 runtime
Returns a list of F77 runtime libraries.
$fortranlibs = ExtUtils::F77->runtime;
=head2 runtimeok
Returns TRUE only if runtime libraries have been found successfully.
=head2 trail_
Returns true if F77 names have trailing underscores.
=head2 compiler
Returns command to execute the compiler (e.g. 'f77').
=head2 cflags
Returns compiler flags.
=head2 testcompiler
Test to see if compiler actually works.
=head1 DEBUGGING
To debug this module, and/or get more information about its workings,
set C<$ExtUtils::F77::DEBUG> to a true value. If set, it will C<warn>
various information about its operations.
As of version 1.22, this module will no longer print or warn if it is
working normally.
=head1 SEE ALSO
L<PDL> (PDL::Minuit and PDL::Slatec), L<PGPLOT>
=head1 AUTHOR
Karl Glazebrook, with many other contributions (see git repository at https://github.com/PDLPorters/extutils-f77)

View File

@@ -0,0 +1,131 @@
package ExtUtils::Helpers;
$ExtUtils::Helpers::VERSION = '0.026';
use strict;
use warnings FATAL => 'all';
use Exporter 5.57 'import';
use Config;
use File::Basename qw/basename/;
use File::Spec::Functions qw/splitpath canonpath abs2rel splitdir/;
use Text::ParseWords 3.24 ();
our @EXPORT_OK = qw/make_executable split_like_shell man1_pagename man3_pagename detildefy/;
BEGIN {
my %impl_for = ( MSWin32 => 'Windows', VMS => 'VMS');
my $package = 'ExtUtils::Helpers::' . ($impl_for{$^O} || 'Unix');
my $impl = $impl_for{$^O} || 'Unix';
require "ExtUtils/Helpers/$impl.pm";
"ExtUtils::Helpers::$impl"->import();
}
sub split_like_shell {
my ($string) = @_;
return if not defined $string;
$string =~ s/^\s+|\s+$//g;
return if not length $string;
return Text::ParseWords::shellwords($string);
}
sub man1_pagename {
my $filename = shift;
return basename($filename).".$Config{man1ext}";
}
my %separator = (
MSWin32 => '.',
VMS => '__',
os2 => '.',
cygwin => '.',
);
my $separator = $separator{$^O} || '::';
sub man3_pagename {
my ($filename, $base) = @_;
$base ||= 'lib';
my ($vols, $dirs, $file) = splitpath(canonpath(abs2rel($filename, $base)));
$file = basename($file, qw/.pm .pod/);
my @dirs = grep { length } splitdir($dirs);
return join $separator, @dirs, "$file.$Config{man3ext}";
}
1;
# ABSTRACT: Various portability utilities for module builders
__END__
=pod
=encoding utf-8
=head1 NAME
ExtUtils::Helpers - Various portability utilities for module builders
=head1 VERSION
version 0.026
=head1 SYNOPSIS
use ExtUtils::Helpers qw/make_executable split_like_shell/;
unshift @ARGV, split_like_shell($ENV{PROGRAM_OPTS});
write_script_to('Build');
make_executable('Build');
=head1 DESCRIPTION
This module provides various portable helper functions for module building modules.
=head1 FUNCTIONS
=head2 make_executable($filename)
This makes a perl script executable.
=head2 split_like_shell($string)
This function splits a string the same way as the local platform does.
=head2 detildefy($path)
This function substitutes a tilde at the start of a path with the users homedir in an appropriate manner.
=head2 man1_pagename($filename)
Returns the man page filename for a script.
=head2 man3_pagename($filename, $basedir)
Returns the man page filename for a Perl library.
=head1 ACKNOWLEDGEMENTS
Olivier Mengué and Christian Walde made C<make_executable> work on Windows.
=head1 AUTHORS
=over 4
=item *
Ken Williams <kwilliams@cpan.org>
=item *
Leon Timmermans <leont@cpan.org>
=back
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2004 by Ken Williams, Leon Timmermans.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut

View File

@@ -0,0 +1,86 @@
package ExtUtils::Helpers::Unix;
$ExtUtils::Helpers::Unix::VERSION = '0.026';
use strict;
use warnings FATAL => 'all';
use Exporter 5.57 'import';
our @EXPORT = qw/make_executable detildefy/;
use Carp qw/croak/;
use Config;
my $layer = $] >= 5.008001 ? ":raw" : "";
sub make_executable {
my $filename = shift;
my $current_mode = (stat $filename)[2] + 0;
if (-T $filename) {
open my $fh, "<$layer", $filename;
my @lines = <$fh>;
if (@lines and $lines[0] =~ s{ \A \#! \s* (?:/\S+/)? perl \b (.*) \z }{$Config{startperl}$1}xms) {
open my $out, ">$layer", "$filename.new" or croak "Couldn't open $filename.new: $!";
print $out @lines;
close $out;
rename $filename, "$filename.bak" or croak "Couldn't rename $filename to $filename.bak";
rename "$filename.new", $filename or croak "Couldn't rename $filename.new to $filename";
unlink "$filename.bak";
}
}
chmod $current_mode | oct(111), $filename;
return;
}
sub detildefy {
my $value = shift;
# tilde with optional username
for ($value) {
s{ ^ ~ (?= /|$)} [ $ENV{HOME} || (getpwuid $>)[7] ]ex or # tilde without user name
s{ ^ ~ ([^/]+) (?= /|$) } { (getpwnam $1)[7] || "~$1" }ex; # tilde with user name
}
return $value;
}
1;
# ABSTRACT: Unix specific helper bits
__END__
=pod
=encoding UTF-8
=head1 NAME
ExtUtils::Helpers::Unix - Unix specific helper bits
=head1 VERSION
version 0.026
=for Pod::Coverage make_executable
split_like_shell
detildefy
=head1 AUTHORS
=over 4
=item *
Ken Williams <kwilliams@cpan.org>
=item *
Leon Timmermans <leont@cpan.org>
=back
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2004 by Ken Williams, Leon Timmermans.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut

View File

@@ -0,0 +1,117 @@
package ExtUtils::Helpers::VMS;
$ExtUtils::Helpers::VMS::VERSION = '0.026';
use strict;
use warnings FATAL => 'all';
use Exporter 5.57 'import';
our @EXPORT = qw/make_executable detildefy/;
use File::Copy qw/copy/;
sub make_executable {
my $filename = shift;
my $batchname = "$filename.com";
copy($filename, $batchname);
ExtUtils::Helpers::Unix::make_executable($batchname);
return;
}
sub detildefy {
my $arg = shift;
# Apparently double ~ are not translated.
return $arg if ($arg =~ /^~~/);
# Apparently ~ followed by whitespace are not translated.
return $arg if ($arg =~ /^~ /);
if ($arg =~ /^~/) {
my $spec = $arg;
# Remove the tilde
$spec =~ s/^~//;
# Remove any slash following the tilde if present.
$spec =~ s#^/##;
# break up the paths for the merge
my $home = VMS::Filespec::unixify($ENV{HOME});
# In the default VMS mode, the trailing slash is present.
# In Unix report mode it is not. The parsing logic assumes that
# it is present.
$home .= '/' unless $home =~ m#/$#;
# Trivial case of just ~ by it self
if ($spec eq '') {
$home =~ s#/$##;
return $home;
}
my ($hvol, $hdir, $hfile) = File::Spec::Unix->splitpath($home);
if ($hdir eq '') {
# Someone has tampered with $ENV{HOME}
# So hfile is probably the directory since this should be
# a path.
$hdir = $hfile;
}
my ($vol, $dir, $file) = File::Spec::Unix->splitpath($spec);
my @hdirs = File::Spec::Unix->splitdir($hdir);
my @dirs = File::Spec::Unix->splitdir($dir);
unless ($arg =~ m#^~/#) {
# There is a home directory after the tilde, but it will already
# be present in in @hdirs so we need to remove it by from @dirs.
shift @dirs;
}
my $newdirs = File::Spec::Unix->catdir(@hdirs, @dirs);
$arg = File::Spec::Unix->catpath($hvol, $newdirs, $file);
}
return $arg;
}
# ABSTRACT: VMS specific helper bits
__END__
=pod
=encoding UTF-8
=head1 NAME
ExtUtils::Helpers::VMS - VMS specific helper bits
=head1 VERSION
version 0.026
=for Pod::Coverage make_executable
detildefy
=head1 AUTHORS
=over 4
=item *
Ken Williams <kwilliams@cpan.org>
=item *
Leon Timmermans <leont@cpan.org>
=back
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2004 by Ken Williams, Leon Timmermans.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut

View File

@@ -0,0 +1,70 @@
package ExtUtils::Helpers::Windows;
$ExtUtils::Helpers::Windows::VERSION = '0.026';
use strict;
use warnings FATAL => 'all';
use Exporter 5.57 'import';
our @EXPORT = qw/make_executable detildefy/;
use Config;
use Carp qw/carp croak/;
use ExtUtils::PL2Bat 'pl2bat';
sub make_executable {
my $script = shift;
if (-T $script && $script !~ / \. (?:bat|cmd) $ /x) {
pl2bat(in => $script, update => 1);
}
return;
}
sub detildefy {
my $value = shift;
$value =~ s{ ^ ~ (?= [/\\] | $ ) }[$ENV{USERPROFILE}]x if $ENV{USERPROFILE};
return $value;
}
1;
# ABSTRACT: Windows specific helper bits
__END__
=pod
=encoding UTF-8
=head1 NAME
ExtUtils::Helpers::Windows - Windows specific helper bits
=head1 VERSION
version 0.026
=for Pod::Coverage make_executable
split_like_shell
detildefy
=head1 AUTHORS
=over 4
=item *
Ken Williams <kwilliams@cpan.org>
=item *
Leon Timmermans <leont@cpan.org>
=back
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2004 by Ken Williams, Leon Timmermans.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut

View File

@@ -0,0 +1,625 @@
package ExtUtils::InstallPaths;
$ExtUtils::InstallPaths::VERSION = '0.012';
use 5.006;
use strict;
use warnings;
use File::Spec ();
use Carp ();
use ExtUtils::Config 0.002;
my %complex_accessors = map { $_ => 1 } qw/prefix_relpaths install_sets/;
my %hash_accessors = map { $_ => 1 } qw/install_path install_base_relpaths original_prefix /;
my %defaults = (
installdirs => 'site',
install_base => undef,
prefix => undef,
verbose => 0,
create_packlist => 1,
dist_name => undef,
module_name => undef,
destdir => undef,
install_path => sub { {} },
install_sets => \&_default_install_sets,
original_prefix => \&_default_original_prefix,
install_base_relpaths => \&_default_base_relpaths,
prefix_relpaths => \&_default_prefix_relpaths,
);
sub _merge_shallow {
my ($name, $filter) = @_;
return sub {
my ($override, $config) = @_;
my $defaults = $defaults{$name}->($config);
$filter->($_) for grep $filter, values %$override;
return { %$defaults, %$override };
}
}
sub _merge_deep {
my ($name, $filter) = @_;
return sub {
my ($override, $config) = @_;
my $defaults = $defaults{$name}->($config);
my $pair_for = sub {
my $key = shift;
my %override = %{ $override->{$key} || {} };
$filter && $filter->($_) for values %override;
return $key => { %{ $defaults->{$key} }, %override };
};
return { map { $pair_for->($_) } keys %$defaults };
}
}
my %allowed_installdir = map { $_ => 1 } qw/core site vendor/;
my $must_be_relative = sub { Carp::croak('Value must be a relative path') if File::Spec->file_name_is_absolute($_[0]) };
my %deep_filter = map { $_ => $must_be_relative } qw/install_base_relpaths prefix_relpaths/;
my %filter = (
installdirs => sub {
my $value = shift;
$value = 'core', Carp::carp('Perhaps you meant installdirs to be "core" rather than "perl"?') if $value eq 'perl';
Carp::croak('installdirs must be one of "core", "site", or "vendor"') if not $allowed_installdir{$value};
return $value;
},
(map { $_ => _merge_shallow($_, $deep_filter{$_}) } qw/original_prefix install_base_relpaths/),
(map { $_ => _merge_deep($_, $deep_filter{$_}) } qw/install_sets prefix_relpaths/),
);
sub new {
my ($class, %args) = @_;
my $config = $args{config} || ExtUtils::Config->new;
my %self = (
config => $config,
map { $_ => exists $args{$_} ? $filter{$_} ? $filter{$_}->($args{$_}, $config) : $args{$_} : ref $defaults{$_} ? $defaults{$_}->($config) : $defaults{$_} } keys %defaults,
);
$self{module_name} ||= do { my $module_name = $self{dist_name}; $module_name =~ s/-/::/g; $module_name } if defined $self{dist_name};
return bless \%self, $class;
}
for my $attribute (keys %defaults) {
no strict qw/refs/;
*{$attribute} = $hash_accessors{$attribute} ?
sub {
my ($self, $key) = @_;
Carp::confess("$attribute needs key") if not defined $key;
return $self->{$attribute}{$key};
} :
$complex_accessors{$attribute} ?
sub {
my ($self, $installdirs, $key) = @_;
Carp::confess("$attribute needs installdir") if not defined $installdirs;
Carp::confess("$attribute needs key") if not defined $key;
return $self->{$attribute}{$installdirs}{$key};
} :
sub {
my $self = shift;
return $self->{$attribute};
};
}
my $script = $] > 5.008000 ? 'script' : 'bin';
my @install_sets_keys = qw/lib arch bin script bindoc libdoc binhtml libhtml/;
my @install_sets_tail = ('bin', $script, qw/man1dir man3dir html1dir html3dir/);
my %install_sets_values = (
core => [ qw/privlib archlib /, @install_sets_tail ],
site => [ map { "site$_" } qw/lib arch/, @install_sets_tail ],
vendor => [ map { "vendor$_" } qw/lib arch/, @install_sets_tail ],
);
sub _default_install_sets {
my $c = shift;
my %ret;
for my $installdir (qw/core site vendor/) {
@{$ret{$installdir}}{@install_sets_keys} = map { $c->get("install$_") } @{ $install_sets_values{$installdir} };
}
return \%ret;
}
sub _default_base_relpaths {
my $config = shift;
return {
lib => ['lib', 'perl5'],
arch => ['lib', 'perl5', $config->get('archname')],
bin => ['bin'],
script => ['bin'],
bindoc => ['man', 'man1'],
libdoc => ['man', 'man3'],
binhtml => ['html'],
libhtml => ['html'],
};
}
my %common_prefix_relpaths = (
bin => ['bin'],
script => ['bin'],
bindoc => ['man', 'man1'],
libdoc => ['man', 'man3'],
binhtml => ['html'],
libhtml => ['html'],
);
sub _default_prefix_relpaths {
my $c = shift;
my @libstyle = $c->get('installstyle') ? File::Spec->splitdir($c->get('installstyle')) : qw(lib perl5);
my $arch = $c->get('archname');
my $version = $c->get('version');
return {
core => {
lib => [@libstyle],
arch => [@libstyle, $version, $arch],
%common_prefix_relpaths,
},
vendor => {
lib => [@libstyle],
arch => [@libstyle, $version, $arch],
%common_prefix_relpaths,
},
site => {
lib => [@libstyle, 'site_perl'],
arch => [@libstyle, 'site_perl', $version, $arch],
%common_prefix_relpaths,
},
};
}
sub _default_original_prefix {
my $c = shift;
my %ret = (
core => $c->get('installprefixexp'),
site => $c->get('siteprefixexp'),
vendor => $c->get('usevendorprefix') ? $c->get('vendorprefixexp') : '',
);
return \%ret;
}
sub _log_verbose {
my $self = shift;
print @_ if $self->verbose;
return;
}
# Given a file type, will return true if the file type would normally
# be installed when neither install-base nor prefix has been set.
# I.e. it will be true only if the path is set from Config.pm or
# set explicitly by the user via install-path.
sub is_default_installable {
my $self = shift;
my $type = shift;
my $installable = $self->install_destination($type) && ( $self->install_path($type) || $self->install_sets($self->installdirs, $type));
return $installable ? 1 : 0;
}
sub _prefixify_default {
my $self = shift;
my $type = shift;
my $rprefix = shift;
my $default = $self->prefix_relpaths($self->installdirs, $type);
if( !$default ) {
$self->_log_verbose(" no default install location for type '$type', using prefix '$rprefix'.\n");
return $rprefix;
} else {
return File::Spec->catdir(@{$default});
}
}
# Translated from ExtUtils::MM_Unix::prefixify()
sub _prefixify_novms {
my($self, $path, $sprefix, $type) = @_;
my $rprefix = $self->prefix;
$rprefix .= '/' if $sprefix =~ m{/$};
$self->_log_verbose(" prefixify $path from $sprefix to $rprefix\n") if defined $path && length $path;
if (not defined $path or length $path == 0 ) {
$self->_log_verbose(" no path to prefixify, falling back to default.\n");
return $self->_prefixify_default( $type, $rprefix );
} elsif( !File::Spec->file_name_is_absolute($path) ) {
$self->_log_verbose(" path is relative, not prefixifying.\n");
} elsif( $path !~ s{^\Q$sprefix\E\b}{}s ) {
$self->_log_verbose(" cannot prefixify, falling back to default.\n");
return $self->_prefixify_default( $type, $rprefix );
}
$self->_log_verbose(" now $path in $rprefix\n");
return $path;
}
sub _catprefix_vms {
my ($self, $rprefix, $default) = @_;
my ($rvol, $rdirs) = File::Spec->splitpath($rprefix);
if ($rvol) {
return File::Spec->catpath($rvol, File::Spec->catdir($rdirs, $default), '');
}
else {
return File::Spec->catdir($rdirs, $default);
}
}
sub _prefixify_vms {
my($self, $path, $sprefix, $type) = @_;
my $rprefix = $self->prefix;
return '' unless defined $path;
$self->_log_verbose(" prefixify $path from $sprefix to $rprefix\n");
require VMS::Filespec;
# Translate $(PERLPREFIX) to a real path.
$rprefix = VMS::Filespec::vmspath($rprefix) if $rprefix;
$sprefix = VMS::Filespec::vmspath($sprefix) if $sprefix;
$self->_log_verbose(" rprefix translated to $rprefix\n sprefix translated to $sprefix\n");
if (length($path) == 0 ) {
$self->_log_verbose(" no path to prefixify.\n")
}
elsif (!File::Spec->file_name_is_absolute($path)) {
$self->_log_verbose(" path is relative, not prefixifying.\n");
}
elsif ($sprefix eq $rprefix) {
$self->_log_verbose(" no new prefix.\n");
}
else {
my ($path_vol, $path_dirs) = File::Spec->splitpath( $path );
my $vms_prefix = $self->config->get('vms_prefix');
if ($path_vol eq $vms_prefix.':') {
$self->_log_verbose(" $vms_prefix: seen\n");
$path_dirs =~ s{^\[}{\[.} unless $path_dirs =~ m{^\[\.};
$path = $self->_catprefix_vms($rprefix, $path_dirs);
}
else {
$self->_log_verbose(" cannot prefixify.\n");
return File::Spec->catdir($self->prefix_relpaths($self->installdirs, $type));
}
}
$self->_log_verbose(" now $path\n");
return $path;
}
BEGIN { *_prefixify = $^O eq 'VMS' ? \&_prefixify_vms : \&_prefixify_novms }
# Translated from ExtUtils::MM_Any::init_INSTALL_from_PREFIX
sub prefix_relative {
my ($self, $installdirs, $type) = @_;
my $relpath = $self->install_sets($installdirs, $type);
return $self->_prefixify($relpath, $self->original_prefix($installdirs), $type);
}
sub install_destination {
my ($self, $type) = @_;
return $self->install_path($type) if $self->install_path($type);
if ( $self->install_base ) {
my $relpath = $self->install_base_relpaths($type);
return $relpath ? File::Spec->catdir($self->install_base, @{$relpath}) : undef;
}
if ( $self->prefix ) {
my $relpath = $self->prefix_relative($self->installdirs, $type);
return $relpath ? File::Spec->catdir($self->prefix, $relpath) : undef;
}
return $self->install_sets($self->installdirs, $type);
}
sub install_types {
my $self = shift;
my %types = ( %{ $self->{install_path} },
$self->install_base ? %{ $self->{install_base_relpaths} }
: $self->prefix ? %{ $self->{prefix_relpaths}{ $self->installdirs } }
: %{ $self->{install_sets}{ $self->installdirs } });
return sort keys %types;
}
sub install_map {
my ($self, $dirs) = @_;
my %localdir_for;
if ($dirs && %$dirs) {
%localdir_for = %$dirs;
}
else {
foreach my $type ($self->install_types) {
$localdir_for{$type} = File::Spec->catdir('blib', $type);
}
}
my (%map, @skipping);
foreach my $type (keys %localdir_for) {
next if not -e $localdir_for{$type};
if (my $dest = $self->install_destination($type)) {
$map{$localdir_for{$type}} = $dest;
} else {
push @skipping, $type;
}
}
warn "WARNING: Can't figure out install path for types: @skipping\nFiles will not be installed.\n" if @skipping;
# Write the packlist into the same place as ExtUtils::MakeMaker.
if ($self->create_packlist and my $module_name = $self->module_name) {
my $archdir = $self->install_destination('arch');
my @ext = split /::/, $module_name;
$map{write} = File::Spec->catfile($archdir, 'auto', @ext, '.packlist');
}
# Handle destdir
if (length(my $destdir = $self->destdir || '')) {
foreach (keys %map) {
# Need to remove volume from $map{$_} using splitpath, or else
# we'll create something crazy like C:\Foo\Bar\E:\Baz\Quux
# VMS will always have the file separate than the path.
my ($volume, $path, $file) = File::Spec->splitpath( $map{$_}, 0 );
# catdir needs a list of directories, or it will create something
# crazy like volume:[Foo.Bar.volume.Baz.Quux]
my @dirs = File::Spec->splitdir($path);
# First merge the directories
$path = File::Spec->catdir($destdir, @dirs);
# Then put the file back on if there is one.
if ($file ne '') {
$map{$_} = File::Spec->catfile($path, $file)
} else {
$map{$_} = $path;
}
}
}
$map{read} = ''; # To keep ExtUtils::Install quiet
return \%map;
}
1;
# ABSTRACT: Build.PL install path logic made easy
__END__
=pod
=encoding UTF-8
=head1 NAME
ExtUtils::InstallPaths - Build.PL install path logic made easy
=head1 VERSION
version 0.012
=head1 SYNOPSIS
use ExtUtils::InstallPaths;
use ExtUtils::Install 'install';
GetOptions(\my %opt, 'install_base=s', 'install_path=s%', 'installdirs=s', 'destdir=s', 'prefix=s', 'uninst:1', 'verbose:1');
my $paths = ExtUtils::InstallPaths->new(%opt, dist_name => $dist_name);
install($paths->install_map, $opt{verbose}, 0, $opt{uninst});
=head1 DESCRIPTION
This module tries to make install path resolution as easy as possible.
When you want to install a module, it needs to figure out where to install things. The nutshell version of how this works is that default installation locations are determined from L<ExtUtils::Config>, and they may be individually overridden by using the C<install_path> attribute. An C<install_base> attribute lets you specify an alternative installation root like F</home/foo> and C<prefix> does something similar in a rather different (and more complicated) way. C<destdir> lets you specify a temporary installation directory like F</tmp/install> in case you want to create bundled-up installable packages.
The following types are supported by default.
=over 4
=item * lib
Usually pure-Perl module files ending in F<.pm> or F<.pod>.
=item * arch
"Architecture-dependent" module files, usually produced by compiling XS, L<Inline>, or similar code.
=item * script
Programs written in pure Perl. In order to improve reuse, you may want to make these as small as possible - put the code into modules whenever possible.
=item * bin
"Architecture-dependent" executable programs, i.e. compiled C code or something. Pretty rare to see this in a perl distribution, but it happens.
=item * bindoc
Documentation for the stuff in C<script> and C<bin>. Usually generated from the POD in those files. Under Unix, these are manual pages belonging to the 'man1' category. Unless explicitly set, this is only available on platforms supporting manpages.
=item * libdoc
Documentation for the stuff in C<lib> and C<arch>. This is usually generated from the POD in F<.pm> and F<.pod> files. Under Unix, these are manual pages belonging to the 'man3' category. Unless explicitly set, this is only available on platforms supporting manpages.
=item * binhtml
This is the same as C<bindoc> above, but applies to HTML documents. Unless explicitly set, this is only available when perl was configured to do so.
=item * libhtml
This is the same as C<libdoc> above, but applies to HTML documents. Unless explicitly set, this is only available when perl was configured to do so.
=back
=head1 ATTRIBUTES
=head2 installdirs
The default destinations for these installable things come from entries in your system's configuration. You can select from three different sets of default locations by setting the C<installdirs> parameter as follows:
'installdirs' set to:
core site vendor
uses the following defaults from ExtUtils::Config:
lib => installprivlib installsitelib installvendorlib
arch => installarchlib installsitearch installvendorarch
script => installscript installsitescript installvendorscript
bin => installbin installsitebin installvendorbin
bindoc => installman1dir installsiteman1dir installvendorman1dir
libdoc => installman3dir installsiteman3dir installvendorman3dir
binhtml => installhtml1dir installsitehtml1dir installvendorhtml1dir [*]
libhtml => installhtml3dir installsitehtml3dir installvendorhtml3dir [*]
* Under some OS (eg. MSWin32) the destination for HTML documents is determined by the C<Config.pm> entry C<installhtmldir>.
The default value of C<installdirs> is "site".
=head2 install_base
You can also set the whole bunch of installation paths by supplying the C<install_base> parameter to point to a directory on your system. For instance, if you set C<install_base> to "/home/ken" on a Linux system, you'll install as follows:
lib => /home/ken/lib/perl5
arch => /home/ken/lib/perl5/i386-linux
script => /home/ken/bin
bin => /home/ken/bin
bindoc => /home/ken/man/man1
libdoc => /home/ken/man/man3
binhtml => /home/ken/html
libhtml => /home/ken/html
=head2 prefix
This sets a prefix, identical to ExtUtils::MakeMaker's PREFIX option. This does something similar to C<install_base> in a much more complicated way.
=head2 config()
The L<ExtUtils::Config|ExtUtils::Config> object used for this object.
=head2 verbose
The verbosity of ExtUtils::InstallPaths. It defaults to 0
=head2 create_packlist
Together with C<module_name> this controls whether a packlist will be added; it defaults to 1.
=head2 dist_name
The name of the current module.
=head2 module_name
The name of the main module of the package. This is required for packlist creation, but in the future it may be replaced by dist_name. It defaults to C<dist_name =~ s/-/::/gr> if dist_name is set.
=head2 destdir
If you want to install everything into a temporary directory first (for instance, if you want to create a directory tree that a package manager like C<rpm> or C<dpkg> could create a package from), you can use the C<destdir> parameter. E.g. Setting C<destdir> to C<"/tmp/foo"> will effectively install to "/tmp/foo/$sitelib", "/tmp/foo/$sitearch", and the like, except that it will use C<File::Spec> to make the pathnames work correctly on whatever platform you're installing on.
=head1 METHODS
=head2 new
Create a new ExtUtils::InstallPaths object. B<All attributes are valid arguments> to the constructor, as well as this:
=over 4
=item * install_path
This must be a hashref with the type as keys and the destination as values.
=item * install_base_relpaths
This must be a hashref with types as keys and a path relative to the install_base as value.
=item * prefix_relpaths
This must be a hashref any of these three keys: core, vendor, site. Each of the values mush be a hashref with types as keys and a path relative to the prefix as value. You probably want to make these three hashrefs identical.
=item * original_prefix
This must be a hashref with the legal installdirs values as keys and the prefix directories as values.
=item * install_sets
This mush be a hashref with the legal installdirs are keys, and the values being hashrefs with types as keys and locations as values.
=back
=head2 install_map()
Return a map suitable for use with L<ExtUtils::Install>. B<In most cases, this is the only method you'll need>.
=head2 install_destination($type)
Returns the destination of a certain type.
=head2 install_types()
Return a list of all supported install types in the current configuration.
=head2 is_default_installable($type)
Given a file type, will return true if the file type would normally be installed when neither install-base nor prefix has been set. I.e. it will be true only if the path is set from the configuration object or set explicitly by the user via install_path.
=head2 install_path($type)
Gets the install path for a certain type.
=head2 install_sets($installdirs, $type)
Get the path for a certain C<$type> with a certain C<$installdirs>.
=head2 install_base_relpaths($type, $relpath)
Get the relative paths for use with install_base for a certain type.
=head2 prefix_relative($installdirs, $type)
Gets the path of a certain C<$type> and C<$installdirs> relative to the prefix.
=head2 prefix_relpaths($install_dirs, $type)
Get the default relative path to use in case the config install paths cannot be prefixified. You do not want to use this to get any relative path, but may require it to set it for custom types.
=head2 original_prefix($installdirs)
Get the original prefix for a certain type of $installdirs.
=head1 SEE ALSO
=over 4
=item * L<Build.PL spec|http://github.com/dagolden/cpan-api-buildpl/blob/master/lib/CPAN/API/BuildPL.pm>
=back
=head1 AUTHORS
=over 4
=item *
Ken Williams <kwilliams@cpan.org>
=item *
Leon Timmermans <leont@cpan.org>
=back
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2011 by Ken Williams, Leon Timmermans.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut

View File

@@ -0,0 +1,331 @@
# Copyright (c) 2003-2004, 2012-2013 by the gtk2-perl team (see the file
# AUTHORS)
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Library General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Library General Public License for more details.
#
# You should have received a copy of the GNU Library General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
package ExtUtils::PkgConfig;
use strict;
use Carp;
use English qw(-no_match_vars); # avoid regex performance penalty
use vars qw/ $VERSION $AUTOLOAD/;
$VERSION = '1.16';
sub import {
my $class = shift;
return unless @_;
die "$class version $_[0] is required--this is only version $VERSION"
if $VERSION < $_[0];
}
sub AUTOLOAD
{
my $class = shift;
my $modulename = shift;
my $function = $AUTOLOAD;
$function =~ s/.*://;
$function =~ s/_/-/g;
my $ans = undef;
my $arg = shift;
if (grep {$_ eq $function} qw/libs
modversion
cflags
cflags-only-I
cflags-only-other
libs-only-L
libs-only-l
libs-only-other/)
{
# simple
$ans = `pkg-config --$function \"$modulename\"`;
}
elsif ('static-libs' eq $function)
{
$ans = `pkg-config --libs --static \"$modulename\"`;
}
elsif ('variable' eq $function)
{
# variable
$ans = `pkg-config --${function}=$arg \"$modulename\"`;
}
elsif (grep {$_ eq $function} qw/atleast-version
exact-version
max-version/)
{
# boolean
$ans = not system (
"pkg-config --${function}=$arg \"$modulename\"");
}
else
{
croak "method '$function' not implemented";
$ans = '';
}
chomp($ans);
$ans = undef if $ans eq '';
return $ans;
}
sub exists {
my ($class, @pkg_candidates) = @_;
foreach my $candidate (@pkg_candidates)
{
my $output = qx/pkg-config --exists "$candidate" 2>&1/;
if (0 == $CHILD_ERROR) {
return 1;
}
}
return '';
}
sub find {
my ($class, @pkg_candidates) = @_;
my (@pkgs_found, @error_messages);
# try all package candidates and save all those that pkg-config
# recognizes
foreach my $candidate (@pkg_candidates)
{
my $output = qx/pkg-config --exists --print-errors "$candidate" 2>&1/;
if (0 == $CHILD_ERROR) {
push @pkgs_found, $candidate;
}
else
{
push @error_messages, $output;
}
}
if (0 == scalar @pkgs_found)
{
foreach my $message (@error_messages) {
carp $message;
}
if (@pkg_candidates > 1)
{
my $list = join ', ', @pkg_candidates;
croak "*** can not find package for any of ($list)\n"
. "*** check that one of them is properly installed and available in PKG_CONFIG_PATH\n";
}
else
{
croak "*** can not find package $pkg_candidates[0]\n"
. "*** check that it is properly installed and available in PKG_CONFIG_PATH\n";
}
}
# return the data of the package that was found first
my %data = ();
$data{pkg} = $pkgs_found[0];
foreach my $what (qw/modversion cflags libs/) {
$data{$what} = `pkg-config --$what \"$data{pkg}\"`;
$data{$what} =~ s/[\015\012]+$//;
croak "*** can't find $what for \"$data{pkg}\"\n"
. "*** is it properly installed and available in PKG_CONFIG_PATH?\n"
unless defined $data{$what};
}
return %data;
}
sub create_version_macros {
my ($class, $pkg, $stem) = @_;
if( $pkg && $stem ) {
my %data = ExtUtils::PkgConfig->find ($pkg);
if( %data ) {
my @modversion = split /\./, $data{modversion};
$modversion[1] = 0 unless defined $modversion[1];
$modversion[2] = 0 unless defined $modversion[2];
# If a version part contains non-numeric characters,
# see if it at least starts with numbers and use those.
# This is needed for versions like '2.0b2'.
# foreach ( @modversion ) {
# if (/\D/ && /^(\d+)/) {
# $_ = $1;
# }
# }
@modversion =
map { /\D/ && /^(\d+)/ ? $1 : $_ } @modversion;
return <<__EOD__;
#define $stem\_MAJOR_VERSION ($modversion[0])
#define $stem\_MINOR_VERSION ($modversion[1])
#define $stem\_MICRO_VERSION ($modversion[2])
#define $stem\_CHECK_VERSION(major,minor,micro) \\
($stem\_MAJOR_VERSION > (major) || \\
($stem\_MAJOR_VERSION == (major) && $stem\_MINOR_VERSION > (minor)) || \\
($stem\_MAJOR_VERSION == (major) && $stem\_MINOR_VERSION == (minor) && $stem\_MICRO_VERSION >= (micro)))
__EOD__
}
}
return undef;
}
sub write_version_macros {
my ($class, $file, @pkgs) = @_;
open FILE, ">$file" or croak "*** can not open file $file for writing\n";
for (my $i = 0; $i < @pkgs; $i += 2) {
my $macros = ExtUtils::PkgConfig->create_version_macros ($pkgs[$i], $pkgs[$i+1]);
if( defined $macros ) {
print FILE $macros;
}
}
close FILE or croak "*** can not close file $file\n";
}
1;
=head1 NAME
ExtUtils::PkgConfig - simplistic interface to pkg-config
=head1 SYNOPSIS
use ExtUtils::PkgConfig;
$package = 'gtk+-2.0';
%pkg_info = ExtUtils::PkgConfig->find ($package);
print "modversion: $pkg_info{modversion}\n";
print "cflags: $pkg_info{cflags}\n";
print "libs: $pkg_info{libs}\n";
$exists = ExtUtils::PkgConfig->exists($package);
$modversion = ExtUtils::PkgConfig->modversion($package);
$libs = ExtUtils::PkgConfig->libs($package);
$cflags = ExtUtils::PkgConfig->cflags($package);
$cflags_only_I = ExtUtils::PkgConfig->cflags_only_I($package);
$cflags_only_other = ExtUtils::PkgConfig->cflags_only_other($package);
$libs_only_L = ExtUtils::PkgConfig->libs_only_L($package);
$libs_only_l = ExtUtils::PkgConfig->libs_only_l($package);
$libs_only_other = ExtUtils::PkgConfig->libs_only_other($package);
$static_libs = ExtUtils::PkgConfig->static_libs($package);
$var_value = ExtUtils::PkgConfig->variable($package, $var);
if (ExtUtils::PkgConfig->atleast_version($package,$version)) {
...
}
if (ExtUtils::PkgConfig->exact_version($package,$version)) {
...
}
if (ExtUtils::PkgConfig->max_version($package,$version)) {
...
}
=head1 DESCRIPTION
The pkg-config program retrieves information about installed libraries,
usually for the purposes of compiling against and linking to them.
ExtUtils::PkgConfig is a very simplistic interface to this utility, intended
for use in the Makefile.PL of perl extensions which bind libraries that
pkg-config knows. It is really just boilerplate code that you would've
written yourself.
=head2 USAGE
=over
=item HASH = ExtUtils::PkgConfig->find (STRING, [STRING, ...])
Call pkg-config on the library specified by I<STRING> (you'll have to know what
to use here). The returned I<HASH> contains the modversion, cflags, and libs
values under keys with those names. If multiple STRINGS are passed they are
attempted in the order they are given till a working package is found.
If pkg-config fails to find a working I<STRING>, this function croaks with a
message intended to be helpful to whomever is attempting to compile your
package.
For example:
*** can not find package bad1
*** check that it is properly installed and available
*** in PKG_CONFIG_PATH
or
*** can't find cflags for gtk+-2.0
*** is it properly installed and available in PKG_CONFIG_PATH?
=item STRING = ExtUtils::PkgConfig->create_version_macros (PACKAGE, STEM)
Create a set of version macros with the prefix I<STEM> for the library
specified by I<PACKAGE>. The result is returned.
Example input would be "gtk+-2.0" for I<PACKAGE> and "GTK" for I<STEM>.
=item ExtUtils::PkgConfig->write_version_macros (FILE, PACKAGE, STEM, [PACKAGE, STEM, ...])
Create one or more sets of version macros for the libraries and prefixes
specified by the I<PACKAGE> and I<STEM> pairs and write them to the file
I<FILE>. If it doesn't exist, I<FILE> will be created. If it does exist, it
will be overwritten.
=back
=head1 SEE ALSO
ExtUtils::PkgConfig was designed to work with ExtUtils::Depends for compiling
the various modules of the gtk2-perl project.
L<ExtUtils::Depends>
L<http://gtk2-perl.sourceforge.net/>
This module is really just an interface to the pkg-config utility program.
http://www.freedesktop.org/Software/pkgconfig
=head1 AUTHORS
muppet E<lt>scott at asofyet dot orgE<gt>.
=head1 COPYRIGHT AND LICENSE
Copyright 2003-2004, 2012-2013 by muppet, Ross McFarland, and the gtk2-perl
team
This library is free software; you can redistribute it and/or modify
it under the terms of the Lesser General Public License (LGPL). For
more information, see http://www.fsf.org/licenses/lgpl.txt
=cut