Skip to content

Commit

Permalink
build swig wrappers for different versions of GSL (1.11 - 1.15)
Browse files Browse the repository at this point in the history
  • Loading branch information
tadam committed Jul 7, 2011
1 parent 298e0db commit 6b1150c
Show file tree
Hide file tree
Showing 57 changed files with 289 additions and 70 deletions.
3 changes: 3 additions & 0 deletions .gitignore
@@ -1,3 +1,5 @@
*~
pm
.gitignore
*.core
core
Expand All @@ -16,6 +18,7 @@ foo*
tags
.DS_Store
xs/*_wrap.c
swig/renames.i
swig/system.i
.prove
Math-GSL-*/
Expand Down
34 changes: 18 additions & 16 deletions Build.PL
Expand Up @@ -77,7 +77,7 @@ sub try_compile {
my $errno = $? >> 8;
local $! = $errno;
print "
*** The test compile of '$tmp.c' failed: status $?
*** (the status means: errno = $errno or '$!')
*** DO NOT PANIC: this just means that you may get some innocuous
Expand All @@ -101,26 +101,28 @@ sub try_cflags ($) {
}
print "no\n";
return '';

}

print "Checking for GSL..";
my %gsl_pkgcfg = ExtUtils::PkgConfig->find ('gsl');

my $MIN_GSL_VERSION = "1.8";
my $MIN_GSL_VERSION = "1.11";
my $gv = $gsl_pkgcfg{'modversion'};
my $current_minor_version;

my $path_system = File::Spec->catfile('swig', 'system.i');
open my $fh, ">", "$path_system" or die "Could not create system.i : $!";

my $current_version;
if (defined $gv) {
if ($gv =~ m{\A(\d+(?:\.\d+)+)}) {
my @current= split /\./, $1;
$current_version = $1;
my @current = split /\./, $current_version;
print $fh "#define GSL_MAJOR_VERSION $current[0]\n";
print $fh "#define GSL_MINOR_VERSION $current[1]\n";

my @min= split /\./, $MIN_GSL_VERSION;
my @min = split /\./, $MIN_GSL_VERSION;
$current_minor_version = $current[1];
unless ($current[0] >= $min[0] && $current[1] >= $min[1]) {
printf "
Expand All @@ -130,7 +132,6 @@ if (defined $gv) {
exit 1;
} else {
print "Found GSL version $gv\n";

}
} else {
print "
Expand Down Expand Up @@ -187,21 +188,19 @@ if ($Config{archname} =~ /x86_64|amd64/ ) {

my @Subsystems = grep { ! /^Test$/ } GSLBuilder::subsystems;

# BSplines appeared in 1.9
if ($current_minor_version < 9 ) {
@Subsystems = grep { ! /BSpline/ } @Subsystems;
}
my $cleanup = qq{
xs/*_wrap.c core *.core swig/system.i
swig/*.o Makefile Math-GSL-* tmp* pod2ht*.tmp _build
lib/Math/GSL/[A-z]+/* blib *.so *.orig
xs/*_wrap*.c core *.core swig/system.i swig/renames.i
swig/*.o Makefile Math-GSL-* tmp* pod2ht*.tmp _build pm
lib/Math/GSL/[A-z]+/* blib *.so *.orig
} . join " ", map { catfile( (qw( lib Math GSL ), "$_.pm") ) } @Subsystems;

if ($^O ne 'darwin') {
$ldflags = '-shared ' . $ldflags;
}

my $builder = GSLBuilder->new(
my $ver2func = do("inc/ver2func");

my $builder = GSLBuilder->new(
module_name => 'Math::GSL',
add_to_cleanup => [ $cleanup ],
create_makefile_pl => 'passthrough',
Expand All @@ -211,7 +210,7 @@ my $builder = GSLBuilder->new(
include_dirs => [],
extra_linker_flags => $ldflags,
extra_compiler_flags=> "$ccflags " . ($ENV{CC_FLAGS}||''),
swig_flags => $swig_flags,
swig_flags => $swig_flags,
license => 'gpl',
build_requires => {
'Test::Most' => 0,
Expand All @@ -229,9 +228,12 @@ my $builder = GSLBuilder->new(
'ExtUtils::PkgConfig' => '1.03',
},
swig_source => [
map { [ "swig/$_.i", "pod/$_.pod" ] } @Subsystems ,
map { [ "swig/$_.i", ["pod/$_.pod"] ] } @Subsystems ,
],
ver2func => $ver2func,
current_version => $current_version,
);
$builder->add_build_element('swig');

$builder->create_build_script();
print "Have a great day!\n";
2 changes: 2 additions & 0 deletions MANIFEST.SKIP
Expand Up @@ -14,5 +14,7 @@ foo*
Math-GSL
\.prove
swig/system\.i
swig/renames\.i
.*~
^MYMETA.yml$
META.json
2 changes: 1 addition & 1 deletion README
Expand Up @@ -5,7 +5,7 @@ Scientific Library (GSL) is a numerical library for C and C++ programmers. It
is free software under the GNU General Public License. Math::GSL uses SWIG to
generate Perl bindings to *most* GSL functionality.

Currently Math::GSL requires at least Perl 5.8 and GSL 1.8 to compile. SWIG
Currently Math::GSL requires at least Perl 5.8 and GSL 1.11 to compile. SWIG
is only needed if you want help work on Math::GSL and checkout code from the
Math::GSL git repository.

Expand Down
148 changes: 105 additions & 43 deletions inc/GSLBuilder.pm
@@ -1,28 +1,31 @@
package GSLBuilder;

use strict;
use warnings;

use Config;
use File::Copy;
use File::Path qw/mkpath/;
use File::Spec::Functions qw/:ALL/;
use Data::Dumper;
use base 'Module::Build';

sub is_release {
return -e '.git' ? 0 : 1;
}
sub subsystems {
sub subsystems {
sort qw/
Diff Machine Statistics BLAS
Eigen Matrix Poly MatrixComplex
BSpline Errno PowInt VectorComplex
CBLAS FFT Min IEEEUtils
CDF Fit QRNG
Chebyshev Monte RNG Vector
Heapsort Multifit Randist Roots
Heapsort Multifit Randist Roots
Combination Histogram Multimin Wavelet
Complex Histogram2D Multiroots Wavelet2D
Const Siman Sum Sys
NTuple Integration Sort Test
DHT Interp ODEIV SF
NTuple Integration Sort Test
DHT Interp ODEIV SF
Deriv Linalg Permutation Spline
/;
}
Expand All @@ -31,33 +34,55 @@ sub process_swig_files {
my $self = shift;
my $p = $self->{properties};


return unless $p->{swig_source};
my $files_ref = $p->{swig_source};
return unless ($files_ref);

unless (is_release()) {
$self->process_versioned_swig_files;
}
foreach my $file (@$files_ref) {
$self->process_swig($file->[0], $file->[1]);
$self->process_xs_file($file->[0]);
}
}

# Check check dependencies for $main_swig_file. These are the
# %includes. If needed, arrange to run swig on $main_swig_file to
# produce a xxx_wrap.c C file.
sub process_versioned_swig_files {
my $self = shift;

sub process_swig {
my ($self, $main_swig_file, $deps_ref) = @_;
my ($cf, $p) = ($self->{config}, $self->{properties});
my $p = $self->{properties};
my $files_ref = $p->{swig_source};

my $cur_ver = $p->{current_version};
my $ver2func = $p->{ver2func};
foreach my $ver (sort {cmp_versions($a, $b)} keys %{$ver2func}) {
next if (cmp_versions($cur_ver, $ver) == -1);
my @renames;
foreach my $high_ver (keys %{$ver2func}) {
next if (cmp_versions($high_ver, $ver) < 1);
push @renames, @{$ver2func->{$high_ver}};
}
print "Building wrappers for GSL $ver\n";
open(my $fh, '>', 'swig/renames.i');
foreach my $rename (@renames) {
print $fh q{%rename("%(regex:/} . $rename . q{/$ignore/)s") "";} . "\n";
}
close($fh);

foreach my $file (@$files_ref) {
$self->process_swig($file->[0], $file->[1], $ver);
}
}
$self->add_to_cleanup('swig/renames.i');
}

sub process_xs_file {
my ($self, $main_swig_file) = @_;

my $ver = $self->{properties}->{current_version};

(my $file_base = $main_swig_file) =~ s/\.[^.]+$//;
$file_base =~ s!swig/!!g;
my $c_file = catdir('xs',"${file_base}_wrap.c");

my @deps = defined $deps_ref ? @$deps_ref : ();
my $c_file = catfile('xs',"${file_base}_wrap.$ver.c");

# don't bother with swig if this is a CPAN release
unless ( is_release() ) {
$self->compile_swig($main_swig_file, $c_file)
unless($self->up_to_date( [$main_swig_file, @deps],$c_file));
}
# .c -> .o
my $obj_file = $self->compile_c($c_file);
$self->add_to_cleanup($obj_file);
Expand All @@ -67,11 +92,44 @@ sub process_swig {

# .o -> .so
$self->link_c($archdir, $file_base, $obj_file);

my $from = catfile(qw/pm Math GSL/, "${file_base}.pm.$ver");
my $to = catfile(qw/blib lib Math GSL/, "${file_base}.pm");
chmod 0644, $from, $to;
copy($from, $to);
}

sub cmp_versions {
my ($v1, $v2) = @_;
my @v1 = split(/\./, $v1);
my @v2 = split(/\./, $v2);
my $cmp_major = $v1[0] <=> $v2[0];
return $cmp_major if ($cmp_major != 0);
my $cmp_minor = $v1[1] <=> $v2[1];
return $cmp_minor;
}

# Check dependencies for $main_swig_file. These are the
# %includes. If needed, arrange to run swig on $main_swig_file to
# produce a xxx_wrap.c C file.
sub process_swig {
my ($self, $main_swig_file, $deps_ref, $ver) = @_;
my ($cf, $p) = ($self->{config}, $self->{properties});

(my $file_base = $main_swig_file) =~ s/\.[^.]+$//;
$file_base =~ s!swig/!!g;
my $c_file = catfile('xs',"${file_base}_wrap.$ver.c");

my @deps = defined $deps_ref ? @$deps_ref : ();

# don't bother with swig if this is a CPAN release
$self->compile_swig($main_swig_file, $c_file, $ver)
unless($self->up_to_date([$main_swig_file, @deps], $c_file));
}

# Invoke swig with -perl -outdir and other options.
sub compile_swig {
my ($self, $file, $c_file) = @_;
my ($self, $file, $c_file, $ver) = @_;
my ($cf, $p) = ($self->{config}, $self->{properties}); # For convenience

# File name, minus the suffix
Expand All @@ -81,26 +139,30 @@ sub compile_swig {
$file_base =~ s!swig/!!g;

my $pm_file = "${file_base}.pm";

my @swig = qw/swig/, defined($p->{swig}) ? ($self->split_like_shell($p->{swig})) : ();
my @swig_flags = defined($p->{swig_flags}) ? $self->split_like_shell($p->{swig_flags}) : ();

my $blib_lib = catfile(qw/blib lib/);
my $gsldir = catfile($blib_lib, qw/Math GSL/);
mkdir $gsldir unless -e $gsldir;


my $blib_lib = catdir(qw/blib lib/);
my $gsldir = catdir('pm', qw/Math GSL/);
mkpath $gsldir unless -e $gsldir;

my $from = catfile($gsldir, $pm_file);
my $to = catfile(qw/lib Math GSL/,$pm_file);
my $to = catfile(qw/lib Math GSL/, $pm_file);
chmod 0644, $from, $to;

$self->do_system(@swig, '-o', $c_file ,
'-outdir', $gsldir,
'-outdir', $gsldir,
'-perl5', @swig_flags, $file)
or die "error : $! while building ( @swig_flags ) $c_file in $gsldir from '$file'";
print "Copying from: $from, to: $to; it makes the CPAN indexer happy.\n";
copy($from,$to);
return $c_file;
move($from, "$from.$ver");

if ($p->{current_version} eq $ver) {
print "Copying from: $from.$ver, to: $to; it makes the CPAN indexer happy.\n";
copy("$from.$ver", $to);
}

return $c_file;
}
sub is_windows { $^O =~ /MSWin32/i }
sub is_darwin { $^O =~ /darwin/i }
Expand All @@ -116,34 +178,34 @@ sub link_c {

$self->add_to_cleanup($lib_file);
my $objects = $p->{objects} || [];

unless ($self->up_to_date([$obj_file, @$objects], $lib_file)) {
my @linker_flags = $self->split_like_shell($p->{extra_linker_flags});

push @linker_flags, $Config{archlib} . '/CORE/' . $Config{libperl} if (is_windows() or is_darwin());

my @lddlflags = $self->split_like_shell($cf->{lddlflags});
my @lddlflags = $self->split_like_shell($cf->{lddlflags});
my @shrp = $self->split_like_shell($cf->{shrpenv});
my @ld = $self->split_like_shell($cf->{ld}) || "gcc";

# Strip binaries if we are compiling on windows
push @ld, "-s" if (is_windows() && $Config{cc} eq 'gcc');

$self->do_system(@shrp, @ld, @lddlflags, @user_libs, '-o', $lib_file ,
$self->do_system(@shrp, @ld, @lddlflags, '-o', $lib_file,
$obj_file, @$objects, @linker_flags)
or die "error building $lib_file file from '$obj_file'";
}

return $lib_file;
}

# From Base.pm but modified to put package cflags *after*
# From Base.pm but modified to put package cflags *after*
# installed c flags so warning-removal will have an effect.

sub compile_c {
my ($self, $file) = @_;
my ($cf, $p) = ($self->{config}, $self->{properties}); # For convenience

# File name, minus the suffix
(my $file_base = $file) =~ s/\.[^.]+$//;
my $obj_file = $file_base . $Config{_o};
Expand All @@ -154,7 +216,7 @@ sub compile_c {

$cf->{installarchlib} = $Config{archlib};

my @include_dirs = @{$p->{include_dirs}}
my @include_dirs = @{$p->{include_dirs}}
? map {"-I$_"} (@{$p->{include_dirs}}, catdir($cf->{installarchlib}, 'CORE'))
: map {"-I$_"} ( catdir($cf->{installarchlib}, 'CORE') ) ;

Expand All @@ -175,10 +237,10 @@ sub compile_c {
# it can be added back via @extra_compiler_flags.

my @flags = (@include_dirs, @cccdlflags, '-c', @ccflags, @extra_compiler_flags, );

my @cc = $self->split_like_shell($cf->{cc});
@cc = "gcc" unless @cc;

$self->do_system(@cc, @flags, '-o', $obj_file, $file)
or die "error building $Config{_o} file from '$file'";

Expand Down

0 comments on commit 6b1150c

Please sign in to comment.