File Coverage

blib/lib/Module/Install/Rust.pm
Criterion Covered Total %
statement 17 51 33.3
branch 0 12 0.0
condition 0 4 0.0
subroutine 6 15 40.0
pod 5 5 100.0
total 28 87 32.1


line stmt bran cond sub pod time code
1             package Module::Install::Rust;
2              
3 1     1   14669 use 5.006;
  1         2  
4 1     1   3 use strict;
  1         2  
  1         16  
5 1     1   2 use warnings;
  1         4  
  1         23  
6              
7 1     1   385 use Module::Install::Base;
  1         2  
  1         22  
8 1     1   480 use TOML 0.97 ();
  1         20147  
  1         22  
9 1     1   9 use Config ();
  1         1  
  1         425  
10              
11             our @ISA = qw( Module::Install::Base );
12              
13             =head1 NAME
14              
15             Module::Install::Rust - Helpers to build Perl extensions written in Rust
16              
17             =head1 VERSION
18              
19             Version 0.02
20              
21             =cut
22              
23             our $VERSION = '0.02';
24              
25              
26             =head1 SYNOPSIS
27              
28             # In Makefile.PL
29             use inc::Module::Install;
30              
31             # ...
32              
33             rust_requires libc => "0.2";
34             rust_write;
35              
36             WriteAll;
37              
38             =head1 DESCRIPTION
39              
40             This package allows L to build Perl extensions written in Rust.
41              
42             =head1 COMMANDS
43              
44             =head2 rust_requires
45              
46             rust_requires libc => "0.2";
47             rust_requires internal_crate => { path => "../internal_crate" };
48              
49             This command is used to specify Rust dependencies. First argument should be a
50             crate name, second - either a version string, or a hashref with keys per Cargo
51             manifest spec.
52              
53             =cut
54              
55             sub rust_requires {
56 0     0 1   my ($self, $name, $spec) = @_;
57 0           $self->{rust_requires}{$name} = $spec;
58             }
59              
60             =head2 rust_feature
61              
62             rust_feature default => [ "some_feature" ];
63             rust_feature some_feature => [ "some-crate/feature" ];
64              
65             This command adds items to C<[features]> section of the generated C.
66              
67             =cut
68              
69             sub rust_feature {
70 0     0 1   my ($self, $name, $spec) = @_;
71 0 0         die "Feature $name is already defined" if $self->{rust_features}{$name};
72 0           $self->{rust_features}{$name} = $spec;
73             }
74              
75             =head2 rust_use_perl_xs
76              
77             rust_use_perl_xs;
78              
79             Configure crate to use C bindings.
80              
81             =cut
82              
83             sub rust_use_perl_xs {
84 0     0 1   my ($self, $spec) = @_;
85              
86 0   0       $spec //= { version => "0" };
87              
88 0           $self->rust_requires("perl-xs", $spec);
89 0           $self->rust_clean_on_rebuild("perl-sys");
90             }
91              
92             =head2 rust_clean_on_rebuild
93              
94             rust_clean_on_rebuild;
95             # or
96             rust_clean_on_rebuild qw/crate_name/;
97              
98             If Makefile changed since last build, force C run. If crate names
99             are specified, force clean only for those packages (C).
100              
101             =cut
102              
103             sub rust_clean_on_rebuild {
104 0     0 1   my ($self, @args) = @_;
105              
106 0   0       my $crates = $self->{cargo_clean} //= [];
107 0           push @$crates, @args;
108             }
109              
110             =head2 rust_write
111              
112             rust_write;
113              
114             Writes C and sets up Makefile options as needed.
115              
116             =cut
117              
118             sub rust_write {
119 0     0 1   my $self = shift;
120              
121 0           $self->_rust_write_cargo;
122 0           $self->_rust_setup_makefile;
123             }
124              
125             sub _rust_crate_name {
126             lc shift->name
127 0     0     }
128              
129             sub _rust_target_name {
130 0     0     shift->_rust_crate_name =~ s/-/_/gr
131             }
132              
133             sub _rust_write_cargo {
134 0     0     my $self = shift;
135              
136 0           my $crate_spec = {
137             package => {
138             name => $self->_rust_crate_name,
139             description => $self->abstract,
140             version => "1.0.0", # FIXME
141             },
142              
143             lib => {
144             "crate-type" => [ "dylib" ],
145             },
146             };
147              
148             $crate_spec->{dependencies} = $self->{rust_requires}
149 0 0         if $self->{rust_requires};
150              
151             $crate_spec->{features} = $self->{rust_features}
152 0 0         if $self->{rust_features};
153              
154 0 0         open my $f, ">", "Cargo.toml" or die $!;
155 0           $f->print("# This file is autogenerated\n\n");
156 0           $f->print(TOML::to_toml($crate_spec));
157 0 0         close $f or die $!;
158             }
159              
160             sub _rust_setup_makefile {
161 0     0     my $self = shift;
162 0           my $class = ref $self;
163              
164             # FIXME: don't assume libraries have "lib" prefix
165 0           my $libname = "lib" . $self->_rust_target_name;
166              
167 0           $self->postamble(<
168             # --- $class section:
169              
170             INST_RUSTDYLIB = \$(INST_ARCHAUTODIR)/\$(DLBASE).\$(DLEXT)
171             RUST_TARGETDIR = target/release
172             RUST_DYLIB = \$(RUST_TARGETDIR)/$libname.\$(DLEXT)
173             CARGO = cargo
174             CARGO_OPTS = --release
175              
176             dynamic :: \$(INST_RUSTDYLIB)
177              
178             MAKE
179              
180 0 0         if ($self->{cargo_clean}) {
181 0           my @opts = map qq{-p "$_"}, @{$self->{cargo_clean}};
  0            
182              
183 0           $self->postamble(<
184             \$(RUST_DYLIB) ::
185             test \$(FIRST_MAKEFILE) -ot \$@ || \$(CARGO) clean \$(CARGO_OPTS) @opts
186              
187             MAKE
188             }
189              
190 0           $self->postamble(<
191             \$(RUST_DYLIB) ::
192             PERL=\$(FULLPERL) \$(CARGO) build \$(CARGO_OPTS)
193              
194             \$(INST_RUSTDYLIB): \$(RUST_DYLIB)
195             \$(CP) \$< \$@
196              
197             clean ::
198             \$(CARGO) clean
199             \$(RM) Cargo.toml Cargo.lock
200             MAKE
201             }
202              
203             =head1 AUTHOR
204              
205             Vickenty Fesunov, C<< >>
206              
207             =head1 BUGS
208              
209             Please report any bugs or feature requests to L.
210              
211             =head1 LICENSE AND COPYRIGHT
212              
213             Copyright 2015 Vickenty Fesunov.
214              
215             This module may be used, modified, and distributed under the same terms as Perl
216             itself. Please see the license that came with your Perl distribution for
217             details.
218              
219             =cut
220              
221             1;