use strict;
use Config;
use File::Glob qw( bsd_glob );
use File::Which qw( which );
use File::chdir;
use File::Copy qw( copy );
# ABSTRACT: (Deprecated) Build Perl extensions in Rust with FFI
our $VERSION = '0.54'; # VERSION
__PACKAGE__->add_property( ffi_rust_extra_compiler_flags =>
default => [],
);
__PACKAGE__->add_property( ffi_rust_extra_linker_flags =>
default => [],
);
sub ffi_have_compiler
{
my($self) = @_;
my $rustc = which('rustc');
my $cargo = which('cargo');
return (!!$rustc) && (!!$cargo);
}
sub ffi_build_dynamic_lib
{
my($self, $src_dir, $name, $target_dir) = @_;
if(@$src_dir > 1)
{
print STDERR "Module::Build::FFI::Rust only supports one ffi directory";
exit 2;
}
$src_dir = $src_dir->[0];
$target_dir = $src_dir unless defined $target_dir;
my $dll = File::Spec->catfile($target_dir, "$name.$Config{dlext}");
if(-e File::Spec->catfile($src_dir, 'Cargo.toml'))
{
$self->add_to_cleanup("$src_dir/target");
do {
local $CWD = $src_dir;
my @cmd = ('cargo', 'build', '--release');
print "@cmd\n";
system @cmd;
exit 2 if $?;
};
# Note: $Config{dlext} is frequently the right extension to look for,
# some platforms however have exceptions.
my $dlext = $Config{dlext};
# On OS X rust produces a dynamic library, but Perl extensions are
# built as bundles. Platypus can work with either and doesn't care
# about the extension, so we install the dylib as a bundle.
if($^O eq 'darwin')
{ $dlext = 'dylib' }
# On Strawberry Perl of recent vintage they use .xs.dll as the dynamic
# library extension.
elsif($^O eq 'MSWin32')
{ $dlext = 'dll' }
my($build_dll) = bsd_glob("$src_dir/target/release/*.$dlext");
copy($build_dll, $dll) || do {
print STDERR "copy failed for\n";
print STDERR " $build_dll => $dll\n";
print STDERR "reason: $!\n";
exit 2;
};
my $test_dirs = $self->notes('ffi_rust_dirs');
my %test_dirs = $test_dirs ? map { $_ => 1 } @$test_dirs : ();
$test_dirs{$src_dir} = 1;
$self->notes('ffi_rust_dirs' => [keys %test_dirs]);
}
else
{
print STDERR "== WARNING WARNING WARNING ==\n";
print STDERR "\n";
print STDERR "building rust project without cargo is deprecated and will be removed\n";
print STDERR "from a future version of Module::Build::FFI::Rust! But not before\n";
print STDERR "31 December 2015.\n";
print STDERR "\n";
print STDERR "== WARNING WARNING WARNING ==\n";
my @sources = bsd_glob("$src_dir/*.rs");
return unless @sources;
if(@sources != 1)
{
print STDERR "Only one Rust source file at a time please.\n";
print STDERR "You appear to have more than one in $src_dir.\n";
exit 2;
}
my $rustc = which('rustc');
my @cmd = (
$rustc,
@{ $self->ffi_rust_extra_compiler_flags },
@{ $self->ffi_rust_extra_linker_flags },
'--crate-type' => 'dylib',
@sources,
'-o', => $dll,
);
print "@cmd\n";
system @cmd;
exit 2 if $?;
}
$dll;
}
sub ACTION_testrust
{
my($self) = @_;
$self->notes('ffi_rust_test_fail' => 0);
my $test_dirs = $self->notes('ffi_rust_dirs');
return unless $test_dirs;
foreach my $dir (@$test_dirs)
{
local $CWD = $dir;
my @cmd = ('cargo', 'test');
print "@cmd\n";
system @cmd;
$self->notes('ffi_rust_test_fail' => 1) if $?;
}
}
sub ACTION_test
{
my($self) = @_;
$self->depends_on('testrust');
$self->SUPER::ACTION_test;
if($self->notes('ffi_rust_test_fail'))
{
exit 2;
}
}
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
Module::Build::FFI::Rust - (Deprecated) Build Perl extensions in Rust with FFI
=head1 VERSION
version 0.54
=head1 DESCRIPTION
B<Note>: This module is deprecated, please see L<FFI::Build> for another
way to bundle Rust code with your Perl distribution.
L<Module::Build::FFI> variant for writing Perl extensions in Rust with
FFI (sans XS).
=head1 BASE CLASS
All methods, properties and actions are inherited from:
L<Module::Build::FFI>
=head1 PROPERTIES
Currently the Rust compile and link is done in one command so these are
both provided to that one step.
=over 4
=item ffi_rust_extra_compiler_flags
Extra compiler flags to be passed to C<rustc>.
Must be a array reference.
=item ffi_rust_extra_linker_flags
Extra linker flags to be passed to C<rustc>.
Must be a array reference.
=back
=head1 BASE CLASS
=over
=item L<Module::Build::FFI>
=back
=head1 METHODS
=head2 ffi_have_compiler
my $has_compiler = $mb->ffi_have_compiler;
Returns true if a rust compiler (rustc) is available.
=head2 ffi_build_dynamic_lib
my $dll_path = $mb->ffi_build_dynamic_lib($src_dir, $name, $target_dir);
my $dll_path = $mb->ffi_build_dynamic_lib($src_dir, $name);
Compiles the Rust source in the C<$src_dir> and link it into a dynamic library
with base name of C<$name.$Config{dlexe}>. If C<$target_dir> is specified
then the dynamic library will be delivered into that directory.
=head1 EXAMPLES
For a complete example working example, see this module which calculates
fibonacci numbers using Rust.
=head1 SEE ALSO
=over 4
=item L<FFI::Platypus>
The Core Platypus documentation.
=item L<Module::Build::FFI>
General MB class for FFI / Platypus.
=back
=head1 AUTHOR
Graham Ollis <plicease@cpan.org>
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2017 by Graham Ollis.
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