Alien-ROOT
view release on metacpan or search on metacpan
inc/inc_Module-Build/Module/Build/WithXSpp.pm view on Meta::CPAN
package Module::Build::WithXSpp;
use strict;
use warnings;
use Module::Build;
use ExtUtils::CppGuess ();
our @ISA = qw(Module::Build);
our $VERSION = '0.12';
# TODO
# - configurable set of xsp and xspt files (and XS typemaps?)
# => works via directories for now.
# - configurable includes/C-preamble for the XS?
# => Works in the .xsp files, but the order of XS++ inclusion
# is undefined.
# - configurable C++ source folder(s) (works, needs docs)
# => to be documented another time. This is really not a feature that
# should be commonly used.
sub new {
my $proto = shift;
my $class = ref($proto) || $proto;
my %args = @_;
# This gives us the correct settings for the C++ compile (hopefully)
my $guess = ExtUtils::CppGuess->new();
if (defined $args{extra_compiler_flags}) {
if (ref($args{extra_compiler_flags})) {
$guess->add_extra_compiler_flags($_) for @{$args{extra_compiler_flags}};
}
else {
$guess->add_extra_compiler_flags($args{extra_compiler_flags})
}
delete $args{extra_compiler_flags};
}
if (defined $args{extra_linker_flags}) {
if (ref($args{extra_linker_flags})) {
$guess->add_extra_linker_flags($_) for @{$args{extra_linker_flags}};
}
else {
$guess->add_extra_linker_flags($args{extra_linker_flags})
}
delete $args{extra_linker_flags};
}
# add the typemap modules to the build dependencies
my $build_requires = $args{build_requires}||{};
my $extra_typemap_modules = $args{extra_typemap_modules}||{};
# FIXME: This prevents any potential subclasses from fudging with the extra typemaps?
foreach my $module (keys %$extra_typemap_modules) {
if (not defined $build_requires->{$module}
or defined($extra_typemap_modules->{$module})
&& $build_requires->{$module} < $extra_typemap_modules->{$module})
{
$build_requires->{$module} = $extra_typemap_modules->{$module};
}
}
$args{build_requires} = $build_requires;
# Construct object using C++ options guess
my $self = $class->SUPER::new(
%args,
$guess->module_build_options # FIXME find a way to let the user override this
);
push @{$self->extra_compiler_flags},
map "-I$_",
(@{$self->cpp_source_dirs||[]}, $self->build_dir);
$self->_init(\%args);
return $self;
}
sub _init {
my $self = shift;
my $args = shift;
}
sub auto_require {
my ($self) = @_;
my $p = $self->{properties};
if ($self->dist_name ne 'Module-Build-WithXSpp'
and $self->auto_configure_requires)
{
if (not exists $p->{configure_requires}{'Module::Build::WithXSpp'}) {
(my $ver = $VERSION) =~ s/^(\d+\.\d\d).*$/$1/; # last major release only
$self->_add_prereq('configure_requires', 'Module::Build::WithXSpp', $ver);
}
if (not exists $p->{configure_requires}{'ExtUtils::CppGuess'}) {
(my $ver = $ExtUtils::CppGuess::VERSION) =~ s/^(\d+\.\d\d).*$/$1/; # last major release only
$self->_add_prereq('configure_requires', 'ExtUtils::CppGuess', $ver);
}
if (not exists $p->{build_requires}{'ExtUtils::CppGuess'}
and eval("require ExtUtils::XSpp;")
and defined $ExtUtils::XSpp::VERSION)
{
(my $ver = $ExtUtils::XSpp::VERSION) =~ s/^(\d+\.\d\d).*$/$1/; # last major release only
$self->_add_prereq('build_requires', 'ExtUtils::XSpp', $ver);
}
}
$self->SUPER::auto_require();
return;
}
sub ACTION_create_buildarea {
my $self = shift;
mkdir($self->build_dir);
$self->add_to_cleanup($self->build_dir);
}
sub ACTION_code {
my $self = shift;
$self->depends_on('create_buildarea');
$self->depends_on('generate_typemap');
$self->depends_on('generate_main_xs');
my $files = {};
foreach my $ext (qw(c cc cxx cpp C)) {
foreach my $dir (@{$self->cpp_source_dirs||[]}) {
my $this = $self->_find_file_by_type($ext, $dir);
$files = $self->_merge_hashes($files, $this);
}
}
my @objects;
foreach my $file (keys %$files) {
my $obj = $self->compile_c($file);
push @objects, $obj;
$self->add_to_cleanup($obj);
}
$self->{properties}{objects} ||= [];
push @{$self->{properties}{objects}}, @objects;
return $self->SUPER::ACTION_code(@_);
}
# I guess I should use a module here.
sub _naive_shell_escape {
my $s = shift;
$s =~ s/\\/\\\\/g;
$s =~ s/"/\\"/g;
$s
}
sub ACTION_generate_main_xs {
my $self = shift;
my $xs_files = $self->find_xs_files;
my $main_xs_file = File::Spec->catfile($self->build_dir, 'main.xs');
if (keys(%$xs_files) > 1) {
# user knows what she's doing, do not generate XS
$self->log_info("Found custom XS files. Not auto-generating main XS file...\n");
return 1;
}
my $xsp_files = $self->find_xsp_files;
my $xspt_files = $self->find_xsp_typemaps;
my $newest = $self->_calc_newest(
keys(%$xsp_files),
keys(%$xspt_files),
'Build.PL',
File::Spec->catdir($self->build_dir, 'typemap'),
);
if (keys(%$xs_files) == 1
&& (values(%$xs_files))[0] =~ /\Q$main_xs_file\E$/)
{
# is main xs file still current?
if (-M $main_xs_file < $newest) {
return 1;
}
}
$self->log_info("Generating main XS file...\n");
my $early_includes = join "\n",
map {
s/^\s*#\s*include\s*//i;
/^"/ or $_ = "<$_>";
"#include $_"
}
@{ $self->early_includes || [] };
my $module_name = $self->module_name;
my $xs_code = <<"HERE";
/*
* WARNING: This file was auto-generated. Changes will be lost!
*/
$early_includes
#ifdef __cplusplus
extern "C" {
#endif
#include "EXTERN.h"
( run in 0.992 second using v1.01-cache-2.11-cpan-5b529ec07f3 )