—package
Module::Build::FFI::Rust;
use
strict;
use
warnings;
use
Config;
# 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)
{
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'
);
"@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
{
STDERR
"copy failed for\n"
;
STDERR
" $build_dll => $dll\n"
;
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
{
STDERR
"== WARNING WARNING WARNING ==\n"
;
STDERR
"\n"
;
STDERR
"building rust project without cargo is deprecated and will be removed\n"
;
STDERR
"from a future version of Module::Build::FFI::Rust! But not before\n"
;
STDERR
"31 December 2015.\n"
;
STDERR
"\n"
;
STDERR
"== WARNING WARNING WARNING ==\n"
;
my
@sources
= bsd_glob(
"$src_dir/*.rs"
);
return
unless
@sources
;
if
(
@sources
!= 1)
{
STDERR
"Only one Rust source file at a time please.\n"
;
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
,
);
"@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'
);
"@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