From: Graham Knop Date: Tue, 27 Oct 2015 18:10:49 +0000 (-0400) Subject: use ExtUtils::HasCompiler for compiler detection X-Git-Tag: v2.000002~6 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=058acc2be0bed8de9d581a9f01a5ee6d9b6631d2;p=p5sagit%2Fstrictures.git use ExtUtils::HasCompiler for compiler detection --- diff --git a/.gitignore b/.gitignore index cdda7b5..3383888 100644 --- a/.gitignore +++ b/.gitignore @@ -7,20 +7,16 @@ /blib/ /pm_to_blib /.build -!.gitignore *.bs -/xs/*.c *.o -cover_db +/cover_db *.gc?? -test-mydeps-* nytprof* -/inc/ -!.gitignore .*.sw? -README -Distar/ -/strictures-* +/README +/Distar/ +/strictures-*/ +/strictures-*.tar.gz # yes that's right, distar makes it for us MANIFEST.SKIP diff --git a/Changes b/Changes index 386ef32..3e5ed60 100644 --- a/Changes +++ b/Changes @@ -1,5 +1,7 @@ Release history for strictures + - use ExtUtils::HasCompiler to detect compiler rather than ExtUtils::CBuilder + 2.000001 - 2015-06-28 - update for perl 5.22 warning categories - avoid using goto &UNIVERSAL::VERSION on perl 5.8, since it segfaults some diff --git a/Makefile.PL b/Makefile.PL index 90be8ea..cf7f30e 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -1,11 +1,11 @@ use strict; use warnings FATAL => 'all'; use 5.006; +require "inc/ExtUtils/HasCompiler.pm"; my $have_compiler = ! parse_args()->{PUREPERL_ONLY} - && eval { require ExtUtils::CBuilder; 1 } - && ExtUtils::CBuilder->new->have_compiler; + && ExtUtils::HasCompiler::can_compile_loadable_object(quiet => 1); my %extra_prereqs = ( indirect => 0, diff --git a/inc/ExtUtils/HasCompiler.pm b/inc/ExtUtils/HasCompiler.pm new file mode 100644 index 0000000..06d4efc --- /dev/null +++ b/inc/ExtUtils/HasCompiler.pm @@ -0,0 +1,212 @@ +package ExtUtils::HasCompiler; +$ExtUtils::HasCompiler::VERSION = '0.012'; +use strict; +use warnings; + +use base 'Exporter'; +our @EXPORT_OK = qw/can_compile_loadable_object/; +our %EXPORT_TAGS = (all => \@EXPORT_OK); + +use Config; +use Carp 'carp'; +use File::Basename 'basename'; +use File::Spec::Functions qw/catfile catdir/; +use File::Temp qw/tempdir tempfile/; + +my $tempdir = tempdir(CLEANUP => 1); + +my $loadable_object_format = <<'END'; +#define PERL_NO_GET_CONTEXT +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" + +#ifndef PERL_UNUSED_VAR +#define PERL_UNUSED_VAR(var) +#endif + +XS(exported) { +#ifdef dVAR + dVAR; +#endif + dXSARGS; + + PERL_UNUSED_VAR(cv); /* -W */ + PERL_UNUSED_VAR(items); /* -W */ + + XSRETURN_IV(42); +} + +#ifndef XS_EXTERNAL +#define XS_EXTERNAL(foo) XS(foo) +#endif + +/* we don't want to mess with .def files on mingw */ +#if defined(WIN32) && defined(__GNUC__) +# define EXPORT __declspec(dllexport) +#else +# define EXPORT +#endif + +EXPORT XS_EXTERNAL(boot_%s) { +#ifdef dVAR + dVAR; +#endif + dXSARGS; + + PERL_UNUSED_VAR(cv); /* -W */ + PERL_UNUSED_VAR(items); /* -W */ + + newXS("%s::exported", exported, __FILE__); +} + +END + +my $counter = 1; +my %prelinking = map { $_ => 1 } qw/MSWin32 VMS aix/; + +sub can_compile_loadable_object { + my %args = @_; + + my $config = $args{config} || 'ExtUtils::HasCompiler::Config'; + return if not $config->get('usedl'); + + my ($source_handle, $source_name) = tempfile(DIR => $tempdir, SUFFIX => '.c', UNLINK => 1); + my $basename = basename($source_name, '.c'); + + my $shortname = '_Loadable' . $counter++; + my $package = "ExtUtils::HasCompiler::$shortname"; + printf $source_handle $loadable_object_format, $basename, $package or do { carp "Couldn't write to $source_name: $!"; return }; + close $source_handle or do { carp "Couldn't close $source_name: $!"; return }; + + my $abs_basename = catfile($tempdir, $basename); + my $object_file = $abs_basename . $config->get('_o'); + my $loadable_object = $abs_basename . '.' . $config->get('dlext'); + my $incdir = catdir($config->get('archlibexp'), 'CORE'); + + my ($cc, $ccflags, $optimize, $cccdlflags, $ld, $ldflags, $lddlflags, $libperl, $perllibs) = map { $config->get($_) } qw/cc ccflags optimize cccdlflags ld ldflags lddlflags libperl perllibs/; + + if ($prelinking{$^O}) { + require ExtUtils::Mksymlists; + ExtUtils::Mksymlists::Mksymlists(NAME => $basename, FILE => $abs_basename, IMPORTS => {}); + } + my @commands; + if ($^O eq 'MSWin32' && $cc =~ /^cl/) { + push @commands, qq{$cc $ccflags $cccdlflags $optimize /I "$incdir" /c $source_name /Fo$object_file}; + push @commands, qq{$ld $object_file $lddlflags $libperl $perllibs /out:$loadable_object /def:$abs_basename.def /pdb:$abs_basename.pdb}; + } + elsif ($^O eq 'VMS') { + # Mksymlists is only the beginning of the story. + open my $opt_fh, '>>', "$abs_basename.opt" or do { carp "Couldn't append to '$abs_basename.opt'"; return }; + print $opt_fh "PerlShr/Share\n"; + close $opt_fh; + + my $incdirs = $ccflags =~ s{ /inc[^=]+ (?:=)+ (?:\()? ( [^\/\)]* ) }{}xi ? "$1,$incdir" : $incdir; + push @commands, qq{$cc $ccflags $optimize /include=($incdirs) $cccdlflags $source_name /obj=$object_file}; + push @commands, qq{$ld $ldflags $lddlflags=$loadable_object $object_file,$abs_basename.opt/OPTIONS,${incdir}perlshr_attr.opt/OPTIONS' $perllibs}; + } + else { + my @extra; + if ($^O eq 'MSWin32') { + push @extra, "$abs_basename.def"; + push @extra, '-l' . ($libperl =~ /lib([^.]+)\./)[0]; + } + elsif ($^O eq 'cygwin') { + push @extra, catfile($incdir, $config->get('useshrplib') ? 'libperl.dll.a' : 'libperl.a'); + } + elsif ($^O eq 'aix') { + $lddlflags =~ s/\Q$(BASEEXT)\E/$abs_basename/; + $lddlflags =~ s/\Q$(PERL_INC)\E/$incdir/; + } + push @commands, qq{$cc $ccflags $optimize "-I$incdir" $cccdlflags -c $source_name -o $object_file}; + push @commands, qq{$cc $optimize $object_file -o $loadable_object $lddlflags @extra $perllibs}; + } + + for my $command (@commands) { + print "$command\n" if not $args{quiet}; + system $command and do { carp "Couldn't execute $command: $!"; return }; + } + + # Skip loading when cross-compiling + return 1 if exists $args{skip_load} ? $args{skip_load} : $config->get('usecrosscompile'); + + require DynaLoader; + local @DynaLoader::dl_require_symbols = "boot_$basename"; + my $handle = DynaLoader::dl_load_file($loadable_object, 0); + if ($handle) { + my $symbol = DynaLoader::dl_find_symbol($handle, "boot_$basename") or do { carp "Couldn't find boot symbol for $basename"; return }; + my $compilet = DynaLoader::dl_install_xsub('__ANON__::__ANON__', $symbol, $source_name); + my $ret = eval { $compilet->(); $package->exported } or carp $@; + delete $ExtUtils::HasCompiler::{"$shortname\::"}; + eval { DynaLoader::dl_unload_file($handle) } or carp $@; + return defined $ret && $ret == 42; + } + else { + carp "Couldn't load $loadable_object: " . DynaLoader::dl_error(); + return; + } +} + +sub ExtUtils::HasCompiler::Config::get { + my (undef, $key) = @_; + return $ENV{uc $key} || $Config{$key}; +} + +1; + +# ABSTRACT: Check for the presence of a compiler + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +ExtUtils::HasCompiler - Check for the presence of a compiler + +=head1 VERSION + +version 0.012 + +=head1 DESCRIPTION + +This module tries to check if the current system is capable of compiling, linking and loading an XS module. + +B: this is an early release, interface stability isn't guaranteed yet. + +=head1 FUNCTIONS + +=head2 can_compile_loadable_object(%opts) + +This checks if the system can compile, link and load a perl loadable object. It may take the following options: + +=over 4 + +=item * quiet + +Do not output the executed compilation commands. + +=item * config + +An L (compatible) object for configuration. + +=item * skip_load + +This causes can_compile_loadable_object to not try to load the generated object. This defaults to true on a cross-compiling perl. + +=back + +=head1 AUTHOR + +Leon Timmermans + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2014 by 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 diff --git a/maint/Makefile.PL.include b/maint/Makefile.PL.include index 3f4e47a..0d7f6e9 100644 --- a/maint/Makefile.PL.include +++ b/maint/Makefile.PL.include @@ -3,3 +3,7 @@ use lib 'Distar/lib'; use Distar; author 'mst - Matt S. Trout (cpan:MSTROUT) '; + +manifest_include inc => '.pm'; + +1;