Acme-Hidek
view release on metacpan or search on metacpan
inc/Module/Install/XSUtil.pm view on Meta::CPAN
#line 1
package Module::Install::XSUtil;
use 5.005_03;
$VERSION = '0.45';
use Module::Install::Base;
@ISA = qw(Module::Install::Base);
use strict;
use Config;
use File::Spec;
use File::Find;
use constant _VERBOSE => $ENV{MI_VERBOSE} ? 1 : 0;
my %ConfigureRequires = (
'ExtUtils::ParseXS' => 3.18, # shipped with Perl 5.18.0
);
my %BuildRequires = (
);
my %Requires = (
'XSLoader' => 0.02,
);
my %ToInstall;
my $UseC99 = 0;
my $UseCplusplus = 0;
sub _verbose{
print STDERR q{# }, @_, "\n";
}
sub _xs_debugging{
return $ENV{XS_DEBUG} || scalar( grep{ $_ eq '-g' } @ARGV );
}
sub _xs_initialize{
my($self) = @_;
unless($self->{xsu_initialized}){
$self->{xsu_initialized} = 1;
if(!$self->cc_available()){
warn "This distribution requires a C compiler, but it's not available, stopped.\n";
exit;
}
$self->configure_requires(%ConfigureRequires);
$self->build_requires(%BuildRequires);
$self->requires(%Requires);
$self->makemaker_args->{OBJECT} = '$(O_FILES)';
$self->clean_files('$(O_FILES)');
$self->clean_files('*.stackdump') if $^O eq 'cygwin';
if($self->_xs_debugging()){
# override $Config{optimize}
if(_is_msvc()){
$self->makemaker_args->{OPTIMIZE} = '-Zi';
}
else{
$self->makemaker_args->{OPTIMIZE} = '-g -ggdb -g3';
}
$self->cc_define('-DXS_ASSERT');
}
}
return;
}
# GNU C Compiler
sub _is_gcc{
return $Config{gccversion};
}
# Microsoft Visual C++ Compiler (cl.exe)
sub _is_msvc{
return $Config{cc} =~ /\A cl \b /xmsi;
}
{
my $cc_available;
sub cc_available {
return defined $cc_available ?
$cc_available :
($cc_available = shift->can_cc())
;
}
# cf. https://github.com/sjn/toolchain-site/blob/219db464af9b2f19b04fec05547ac10180a469f3/lancaster-consensus.md
my $want_xs;
sub want_xs {
my($self, $default) = @_;
return $want_xs if defined $want_xs;
# you're using this module, you must want XS by default
# unless PERL_ONLY is true.
$default = !$ENV{PERL_ONLY} if not defined $default;
foreach my $arg(@ARGV){
my ($k, $v) = split '=', $arg; # MM-style named args
if ($k eq 'PUREPERL_ONLY' && defined $v) {
return $want_xs = !$v;
}
elsif($arg eq '--pp'){ # old-style
return $want_xs = 0;
}
elsif($arg eq '--xs'){
return $want_xs = 1;
}
}
if ($ENV{PERL_MM_OPT}) {
my($v) = $ENV{PERL_MM_OPT} =~ /\b PUREPERL_ONLY = (\S+) /xms;
if (defined $v) {
return $want_xs = !$v;
}
}
return $want_xs = $default;
}
}
sub use_ppport{
my($self, $dppp_version) = @_;
return if $self->{_ppport_ok}++;
$self->_xs_initialize();
my $filename = 'ppport.h';
$dppp_version ||= 3.19; # the more, the better
$self->configure_requires('Devel::PPPort' => $dppp_version);
$self->build_requires('Devel::PPPort' => $dppp_version);
print "Writing $filename\n";
my $e = do{
local $@;
eval qq{
use Devel::PPPort;
Devel::PPPort::WriteFile(q{$filename});
};
$@;
};
if($e){
print "Cannot create $filename because: $@\n";
}
if(-e $filename){
$self->clean_files($filename);
$self->cc_define('-DUSE_PPPORT');
$self->cc_append_to_inc('.');
}
return;
}
sub use_xshelper {
my($self, $opt) = @_;
$self->_xs_initialize();
$self->use_ppport();
my $file = 'xshelper.h';
open my $fh, '>', $file or die "Cannot open $file for writing: $!";
print $fh $self->_xshelper_h();
close $fh or die "Cannot close $file: $!";
if(defined $opt) {
if($opt eq '-clean') {
$self->clean_files($file);
}
else {
$self->realclean_files($file);
}
}
return;
}
sub _gccversion {
my $res = `$Config{cc} --version`;
my ($version) = $res =~ /\(GCC\) ([0-9.]+)/;
no warnings 'numeric', 'uninitialized';
return sprintf '%g', $version;
}
sub cc_warnings{
my($self) = @_;
$self->_xs_initialize();
if(_is_gcc()){
$self->cc_append_to_ccflags(qw(-Wall));
my $gccversion = _gccversion();
inc/Module/Install/XSUtil.pm view on Meta::CPAN
sub cc_libs {
my ($self, @libs) = @_;
@libs = map{
my($name, $dir) = ref($_) eq 'ARRAY' ? @{$_} : ($_, undef);
my $lib;
if(defined $dir) {
$lib = ($dir =~ /^-/ ? qq{$dir } : qq{-L$dir });
}
else {
$lib = '';
}
$lib .= ($name =~ /^-/ ? qq{$name} : qq{-l$name});
_verbose "libs: $lib" if _VERBOSE;
$lib;
} @libs;
$self->cc_append_to_libs( @libs );
}
sub cc_append_to_libs{
my($self, @libs) = @_;
$self->_xs_initialize();
return unless @libs;
my $libs = join q{ }, @libs;
my $mm = $self->makemaker_args;
if ($mm->{LIBS}){
$mm->{LIBS} .= q{ } . $libs;
}
else{
$mm->{LIBS} = $libs;
}
return $libs;
}
sub cc_assert_lib {
my ($self, @dcl_args) = @_;
if ( ! $self->{xsu_loaded_checklib} ) {
my $loaded_lib = 0;
foreach my $checklib (qw(inc::Devel::CheckLib Devel::CheckLib)) {
eval "use $checklib 0.4";
if (!$@) {
$loaded_lib = 1;
last;
}
}
if (! $loaded_lib) {
warn "Devel::CheckLib not found in inc/ nor \@INC";
exit 0;
}
$self->{xsu_loaded_checklib}++;
$self->configure_requires( "Devel::CheckLib" => "0.4" );
$self->build_requires( "Devel::CheckLib" => "0.4" );
}
Devel::CheckLib::check_lib_or_exit(@dcl_args);
}
sub cc_append_to_ccflags{
my($self, @ccflags) = @_;
$self->_xs_initialize();
my $mm = $self->makemaker_args;
$mm->{CCFLAGS} ||= $Config{ccflags};
$mm->{CCFLAGS} .= q{ } . join q{ }, @ccflags;
return;
}
sub cc_define{
my($self, @defines) = @_;
$self->_xs_initialize();
my $mm = $self->makemaker_args;
if(exists $mm->{DEFINE}){
$mm->{DEFINE} .= q{ } . join q{ }, @defines;
}
else{
$mm->{DEFINE} = join q{ }, @defines;
}
return;
}
sub requires_xs_module {
my $self = shift;
return $self->requires() unless @_;
$self->_xs_initialize();
my %added = $self->requires(@_);
my(@inc, @libs);
my $rx_lib = qr{ \. (?: lib | a) \z}xmsi;
my $rx_dll = qr{ \. dll \z}xmsi; # for Cygwin
while(my $module = each %added){
my $mod_basedir = File::Spec->join(split /::/, $module);
my $rx_header = qr{\A ( .+ \Q$mod_basedir\E ) .+ \. h(?:pp)? \z}xmsi;
SCAN_INC: foreach my $inc_dir(@INC){
my @dirs = grep{ -e } File::Spec->join($inc_dir, 'auto', $mod_basedir), File::Spec->join($inc_dir, $mod_basedir);
next SCAN_INC unless @dirs;
my $n_inc = scalar @inc;
find(sub{
if(my($incdir) = $File::Find::name =~ $rx_header){
push @inc, $incdir;
}
( run in 1.424 second using v1.01-cache-2.11-cpan-39bf76dae61 )