Alien-Base-ModuleBuild
view release on metacpan or search on metacpan
lib/Alien/Base/ModuleBuild.pm view on Meta::CPAN
$Force = 0;
$ForceSystem = 0;
}
}
elsif(defined $ENV{ALIEN_FORCE})
{
$Force = $ENV{ALIEN_FORCE};
}
}
################
# Parameters #
################
## Extra parameters in A::B::MB objects (all (toplevel) should start with 'alien_')
# alien_name: name of library (pkg-config)
__PACKAGE__->add_property('alien_name');
# alien_ffi_name: name of library (the "foo" in libfoo)
__PACKAGE__->add_property('alien_ffi_name');
# alien_temp_dir: folder name for download/build
__PACKAGE__->add_property( alien_temp_dir => '_alien' );
# alien_install_type: allow to override alien install type
__PACKAGE__->add_property( alien_install_type => undef );
# alien_share_dir: folder name for the "install" of the library
# this is added (unshifted) to the @{share_dir->{dist}}
# N.B. is reset during constructor to be full folder name
__PACKAGE__->add_property('alien_share_dir' => '_share' );
# alien_selection_method: name of method for selecting file: (todo: newest, manual)
# default is specified later, when this is undef (see alien_check_installed_version)
__PACKAGE__->add_property( alien_selection_method => 'newest' );
# alien_build_commands: arrayref of commands for building
__PACKAGE__->add_property(
alien_build_commands =>
default => [ '%c --prefix=%s', 'make' ],
);
# alien_test_commands: arrayref of commands for testing the library
# note that this might be better tacked onto the build-time commands
__PACKAGE__->add_property(
alien_test_commands =>
default => [ ],
);
# alien_build_commands: arrayref of commands for installing the library
__PACKAGE__->add_property(
alien_install_commands =>
default => [ 'make install' ],
);
# alien_version_check: command to execute to check if install/version
__PACKAGE__->add_property( alien_version_check => '%{pkg_config} --modversion %n' );
# pkgconfig-esque info, author provides these by hand for now, will parse .pc file eventually
__PACKAGE__->add_property( 'alien_provides_cflags' );
__PACKAGE__->add_property( 'alien_provides_libs' );
# alien_repository: hash (or arrayref of hashes) of information about source repo on ftp
# |-- protocol: ftp or http
# |-- protocol_class: holder for class type (defaults to 'Net::FTP' or 'HTTP::Tiny')
# |-- host: ftp server for source
# |-- location: ftp folder containing source, http addr to page with links
# |-- pattern: qr regex matching acceptable files, if has capture group those are version numbers
# |-- platform: src or platform, matching os_type M::B method
# |
# |-- (non-api) connection: holder for Net::FTP-like object (needs cwd, ls, and get methods)
__PACKAGE__->add_property( 'alien_repository' => [] );
__PACKAGE__->add_property( 'alien_repository_default' => {} );
__PACKAGE__->add_property( 'alien_repository_class' => {} );
# alien_isolate_dynamic
__PACKAGE__->add_property( 'alien_isolate_dynamic' => 0 );
__PACKAGE__->add_property( 'alien_autoconf_with_pic' => 1 );
# alien_inline_auto_include
__PACKAGE__->add_property( 'alien_inline_auto_include' => [] );
# use MSYS even if %c isn't found
__PACKAGE__->add_property( 'alien_msys' => 0 );
# Alien packages that provide build dependencies
__PACKAGE__->add_property( 'alien_bin_requires' => {} );
# Do a staged install to blib instead of trying to install to the final location.
__PACKAGE__->add_property( 'alien_stage_install' => 1 );
# Should modules be installed into arch specific directory?
# Most alien dists will have arch specific files in their share so it makes sense to install
# the module in the arch specific location. If you are alienizing something that isn't arch
# specific, like javascript source or java byte code, then you'd want to set this to 0.
# For now this will default to off. See gh#119 for a discussion.
__PACKAGE__->add_property( 'alien_arch' => defined $ENV{ALIEN_ARCH} ? $ENV{ALIEN_ARCH} : 0 );
__PACKAGE__->add_property( 'alien_helper' => {} );
__PACKAGE__->add_property( 'alien_env' => {} );
# Extra enviroment variable to effect to "configure"
__PACKAGE__->add_property( 'alien_extra_site_config' => {} );
################
# ConfigData #
################
# working_directory: full path to the extracted source or binary of the library
# pkgconfig: hashref of A::B::PkgConfig objects created from .pc file found in working_directory
# install_type: either system or share
# version: version number installed or available
# Cflags: holder for cflags if manually specified
# Libs: same but libs
# name: holder for name as needed by pkg-config
# finished_installing: set to true once ACTION_install is finished, this helps testing now and real checks later
############################
# Initialization Methods #
############################
sub new {
my $class = shift;
my %args = @_;
# merge default and user-defined repository classes
$args{alien_repository_class}{$_} ||= $default_repository_class{$_}
for keys %default_repository_class;
my $self = $class->SUPER::new(%args);
## Recheck Force System
if(!defined($ENV{ALIEN_INSTALL_TYPE}) && !defined($ENV{ALIEN_FORCE}) && defined($self->alien_install_type)) {
if ($self->alien_install_type eq 'share' ) { $Force = 1; $ForceSystem = 0; }
elsif($self->alien_install_type eq 'system') { $Force = 0; $ForceSystem = 1; }
}
$self->config_data("Force" => $Force);
$self->config_data("ForceSystem" => $ForceSystem);
$self->alien_helper->{pkg_config} = 'Alien::Base::PkgConfig->pkg_config_command'
unless defined $self->alien_helper->{pkg_config};
my $ab_version = eval {
require Alien::Base;
Alien::Base->VERSION;
};
$ab_version ||= 0;
# setup additional temporary directories, and yes we have to add File::ShareDir manually
if($ab_version < 0.77) {
$self->_add_prereq( 'requires', 'File::ShareDir', '1.00' );
}
# this just gets passed from the Build.PL to the config so that it can
# be used by the auto_include method
$self->config_data( 'inline_auto_include' => $self->alien_inline_auto_include );
if($Force || !$self->alien_check_installed_version) {
if (any { /(?<!\%)\%c/ } map { ref($_) ? @{$_} : $_ } @{ $self->alien_build_commands }) {
$self->config_data( 'autoconf' => 1 );
}
if ($^O eq 'MSWin32' && ($self->config_data( 'autoconf') || $self->alien_msys)) {
$self->_add_prereq( 'build_requires', 'Alien::MSYS', '0' );
$self->config_data( 'msys' => 1 );
} else {
$self->config_data( 'msys' => 0 );
}
foreach my $tool (keys %{ $self->alien_bin_requires }) {
my $version = $self->alien_bin_requires->{$tool};
if($tool eq 'Alien::CMake' && $version < 0.07) {
lib/Alien/Base/ModuleBuild.pm view on Meta::CPAN
sub Inline { shift; $module->Inline(\@_) }
1;
=begin Pod::Coverage
Inline
=end Pod::Coverage
=cut
EOF
close $fh;
}
if($self->alien_arch) {
my @parts = split /::/, $module;
my $arch_dir = File::Spec->catdir($self->blib, 'arch', 'auto', @parts);
File::Path::mkpath($arch_dir, 0, oct(777)) unless -d $arch_dir;
open my $fh, '>', File::Spec->catfile($arch_dir, $parts[-1].".txt");
print $fh "Alien based distribution with architecture specific file in share\n";
close $fh;
}
$self->depends_on('alien_install') if $self->alien_stage_install;
}
sub process_share_dir_files {
my $self = shift;
$self->SUPER::process_share_dir_files(@_);
# copy the compiled files into blib if running under blib scheme
$self->depends_on('alien_install') if $self->notes('alien_blib_scheme') || $self->alien_stage_install;
}
sub alien_extract_archive {
my ($self, $archive) = @_;
print "Extracting Archive ... ";
my $ae = Archive::Extract->new( archive => $archive );
$ae->extract or croak "Archive extraction failed!";
print "Done\n";
return $ae->extract_path;
}
sub ACTION_alien_code {
my $self = shift;
local $| = 1; # don't buffer stdout
$self->alien_init_temp_dir;
$self->config_data( name => $self->alien_name );
$self->config_data( ffi_name => $self->alien_ffi_name );
my $version;
$version = $self->alien_check_installed_version
unless $self->config_data('Force');
if ($version) {
$self->config_data( install_type => 'system' );
$self->config_data( version => $version );
my %system_provides;
$system_provides{Cflags} = $self->alien_provides_cflags
if defined $self->alien_provides_cflags;
$system_provides{Libs} = $self->alien_provides_libs
if defined $self->alien_provides_libs;
$self->config_data( system_provides => \%system_provides );
return;
}
if ($self->config_data('ForceSystem')) {
die "Requested system install, but system package not detected."
}
my @repos = $self->alien_create_repositories;
my $cabinet = Alien::Base::ModuleBuild::Cabinet->new;
foreach my $repo (@repos) {
$cabinet->add_files( $repo->probe );
}
$cabinet->sort_files;
{
local $CWD = $self->alien_temp_dir;
my $file = $cabinet->files->[0];
unless (defined $file) {
die "no files found in repository";
}
$version = $file->version;
$self->config_data( alien_version => $version ); # Temporary setting, may be overridden later
print "Downloading File: " . $file->filename . " ... ";
my $filename = $file->get;
croak "Error downloading file" unless $filename;
print "Done\n";
my $extract_path = _catdir(File::Spec->rel2abs($self->alien_extract_archive($filename)));
$self->config_data( working_directory => $extract_path );
$CWD = $extract_path;
if ( $file->platform eq 'src' ) {
print "Building library ... ";
unless ($self->alien_do_commands('build')) {
print "Failed\n";
croak "Build not completed";
}
}
print "Done\n";
}
$self->config_data( install_type => 'share' );
$self->config_data( original_prefix => $self->alien_library_destination );
my $pc = $self->alien_load_pkgconfig;
my $pc_version = (
$pc->{$self->alien_name} || $pc->{_manual}
lib/Alien/Base/ModuleBuild.pm view on Meta::CPAN
sub _alien_bin_require {
my($self, $mod) = @_;
my $version = $self->alien_bin_requires->{$mod};
unless(eval { $mod->can('new') })
{
my $pm = "$mod.pm";
$pm =~ s/::/\//g;
require $pm;
$mod->VERSION($version) if $version;
}
if($mod->can('alien_helper')) {
my $helpers = $mod->alien_helper;
foreach my $k (keys %$helpers) {
my $v = $helpers->{$k};
next if defined $self->alien_helper->{$k};
$self->alien_helper->{$k} = $v;
}
}
}
sub alien_do_system {
my $self = shift;
my $command = shift;
local %ENV = %ENV;
if ($self->config_data( 'msys' )) {
$self->alien_bin_requires->{'Alien::MSYS'} ||= 0
}
my $config;
foreach my $mod (keys %{ $self->alien_bin_requires }) {
$self->_alien_bin_require($mod);
my %path;
if ($mod eq 'Alien::MSYS') {
$path{Alien::MSYS->msys_path} = 1;
} elsif ($mod eq 'Alien::TinyCC') {
$path{Alien::TinyCC->path_to_tcc} = 1;
} elsif ($mod eq 'Alien::Autotools') {
$path{$_} = 1 for map { Alien::Autotools->$_ } qw( autoconf_dir automake_dir libtool_dir );
} elsif (eval { $mod->can('bin_dir') }) {
$path{$_} = 1 for $mod->bin_dir;
}
# remove anything already in PATH
delete $path{$_} for grep { defined $_ } @PATH;
# add anything else to start of PATH
unshift @PATH, sort keys %path;
$config ||= _shell_config_generate();
$config->prepend_path( PATH => sort keys %path );
}
# If we are using autoconf, then create a site.config file
# that specifies the same compiler and compiler linker flags
# as were used for building Perl. This is helpful for
# mixed 32/64bit platforms where 32bit is the default but
# Perl is 64bit.
if($self->config_data('autoconf') && !defined $ENV{CONFIG_SITE}) {
local $CWD;
pop @CWD;
my $ldflags = $Config{ldflags};
$ldflags .= " -Wl,-headerpad_max_install_names"
if $^O eq 'darwin';
my %extra_site_config = %{ $self->alien_extra_site_config };
open my $fh, '>', 'config.site';
print $fh "CC='$Config{cc}'\n";
# -D define flags should be stripped because they are Perl
# specific.
print $fh "CFLAGS='" . join(" ", _filter_defines($Config{ccflags}), (delete($extra_site_config{CFLAGS}) ||"")) . "'\n";
print $fh "CPPFLAGS='" . join(" ", _filter_defines($Config{cppflags}), (delete($extra_site_config{CPPFLAGS}) ||"")) . "'\n";
print $fh "CXXFLAGS='" . join(" ", _filter_defines($Config{ccflags}), (delete($extra_site_config{CXXFLAGS}) ||"")) . "'\n";
print $fh "LDFLAGS='" . join(" ", $ldflags, (delete($extra_site_config{LDFLAGS}) ||"") ) . "'\n";
for (keys %extra_site_config) {
print $fh "$_='$extra_site_config{$_}'\n";
}
close $fh;
my $config ||= _shell_config_generate();
my $config_site = File::Spec->catfile($CWD, 'config.site');
$config_site =~ s{\\}{/}g if $^O eq 'MSWin32';
$config->set( CONFIG_SITE => $config_site );
$ENV{CONFIG_SITE} = $config_site;
}
foreach my $key (sort keys %{ $self->alien_env })
{
my $value = $self->alien_interpolate($self->alien_env->{$key});
defined $value ? $ENV{$key} = $value : delete $ENV{$key};
$config ||= _shell_config_generate();
$config->set( $key => $value );
}
if($config) {
if($^O eq 'MSWin32') {
local $CWD;
pop @CWD;
$config->generate_file( Shell::Guess->command_shell, 'env.bat' );
$config->generate_file( Shell::Guess->cmd_shell, 'env.cmd' );
$config->generate_file( Shell::Guess->power_shell, 'env.ps1' );
} else {
local $CWD;
pop @CWD;
$config->generate_file( Shell::Guess->bourne_shell, 'env.sh' );
$config->generate_file( Shell::Guess->c_shell, 'env.csh' );
}
}
$self->do_system( ref($command) ? @$command : $command );
}
# alias for backwards compatibility
*_env_do_system = \&alien_do_system;
sub alien_check_built_version {
return;
}
sub alien_do_commands {
my $self = shift;
my $phase = shift;
my $attr = "alien_${phase}_commands";
my $commands = $self->$attr();
print "\n+ cd $CWD\n";
foreach my $command (@$commands) {
my %result = $self->alien_do_system( $command );
unless ($result{success}) {
carp "External command ($result{command}) failed! Error: $?\n";
return 0;
lib/Alien/Base/ModuleBuild.pm view on Meta::CPAN
########################
sub alien_load_pkgconfig {
my $self = shift;
my $dir = _catdir($self->config_data( 'working_directory' ));
my $pc_files = $self->rscan_dir( $dir, qr/\.pc$/ );
my %pc_objects = map {
my $pc = Alien::Base::PkgConfig->new($_);
$pc->make_abstract( pcfiledir => $dir );
($pc->{package}, $pc)
} @$pc_files;
$pc_objects{_manual} = $self->alien_generate_manual_pkgconfig($dir)
or croak "Could not autogenerate pkgconfig information";
$self->config_data( pkgconfig => \%pc_objects );
return \%pc_objects;
}
sub alien_refresh_manual_pkgconfig {
my $self = shift;
my ($dir) = @_;
my $pc_objects = $self->config_data( 'pkgconfig' );
$pc_objects->{_manual} = $self->alien_generate_manual_pkgconfig($dir)
or croak "Could not autogenerate pkgconfig information";
$self->config_data( pkgconfig => $pc_objects );
return 1;
}
sub alien_generate_manual_pkgconfig {
my $self = shift;
my ($dir) = _catdir(shift);
my $paths = $self->alien_find_lib_paths($dir);
my @L =
map { "-L$_" }
map { _catdir( '${pcfiledir}', $_ ) }
@{$paths->{lib}};
my $provides_libs = $self->alien_provides_libs;
#if no provides_libs then generate -l list from found files
unless ($provides_libs) {
my @files = map { "-l$_" } @{$paths->{lib_files}};
$provides_libs = join( ' ', @files );
}
my $libs = join( ' ', @L, $provides_libs );
my @I =
map { "-I$_" }
map { _catdir( '${pcfiledir}', $_ ) }
@{$paths->{inc}};
my $provides_cflags = $self->alien_provides_cflags;
push @I, $provides_cflags if $provides_cflags;
my $cflags = join( ' ', @I );
my $manual_pc = Alien::Base::PkgConfig->new({
package => $self->alien_name,
vars => {
pcfiledir => $dir,
},
keywords => {
Cflags => $cflags || '',
Libs => $libs || '',
Version => '',
},
});
return $manual_pc;
}
sub _alien_file_pattern_dynamic {
my $self = shift;
my $ext = $self->config('so'); #platform specific .so extension
return qr/\.[\d.]*(?<=\.)$ext[\d.]*(?<!\.)|(\.h|$ext)$/;
};
sub _alien_file_pattern_static {
my $self = shift;
my $ext = quotemeta $self->config('lib_ext');
return qr/(\.h|$ext)$/;
}
sub alien_find_lib_paths {
my $self = shift;
my ($dir) = @_;
my $libs = $self->alien_provides_libs;
my @libs;
@libs = map { my $f = $_; $f =~ s/^-l//; $f } grep { /^-l/ } split /\s+/, $libs if $libs;
my (@lib_files, @lib_paths, @inc_paths);
foreach my $file_pattern ($self->_alien_file_pattern_static, $self->_alien_file_pattern_dynamic) {
my @files =
map { File::Spec->abs2rel( $_, $dir ) } # make relative to $dir
grep { ! -d }
@{ $self->_rscan_destdir( $dir, $file_pattern ) };
for (@files) {
my ($file, $path, $ext) = fileparse( $_, $file_pattern );
next unless $ext; # just in case
$path = File::Spec->catdir($path); # remove trailing /
if ($ext eq '.h') {
push @inc_paths, $path;
next;
}
$file =~ s/^lib//;
if (@libs) {
next unless any { $file eq $_ } @libs;
}
next if any { $file eq $_ } @lib_files;
push @lib_files, $file;
push @lib_paths, $path;
}
( run in 2.037 seconds using v1.01-cache-2.11-cpan-97f6503c9c8 )