File Coverage

blib/lib/FFI/Build/MM.pm
Criterion Covered Total %
statement 154 163 94.4
branch 33 52 63.4
condition 12 30 40.0
subroutine 33 33 100.0
pod 3 14 21.4
total 235 292 80.4


line stmt bran cond sub pod time code
1             package FFI::Build::MM;
2              
3 3     3   258268 use strict;
  3         6  
  3         106  
4 3     3   17 use warnings;
  3         6  
  3         144  
5 3     3   44 use 5.008004;
  3         13  
6 3     3   16 use Carp ();
  3         5  
  3         70  
7 3     3   974 use FFI::Build;
  3         9  
  3         17  
8 3     3   692 use JSON::PP ();
  3         12949  
  3         60  
9 3     3   15 use File::Glob ();
  3         4  
  3         40  
10 3     3   10 use File::Basename ();
  3         4  
  3         38  
11 3     3   11 use File::Path ();
  3         4  
  3         34  
12 3     3   1671 use File::Copy ();
  3         10525  
  3         114  
13 3     3   2650 use ExtUtils::MakeMaker 7.12;
  3         407843  
  3         7098  
14              
15             # ABSTRACT: FFI::Build installer code for ExtUtils::MakeMaker
16             our $VERSION = '2.11'; # VERSION
17              
18              
19             sub new
20             {
21 9     9 1 276352 my($class, %opt) = @_;
22              
23 9 100       56 my $save = defined $opt{save} ? $opt{save} : 1;
24              
25 9         46 my $self = bless { save => $save }, $class;
26 9         60 $self->load_prop;
27              
28 9         29 $self;
29             }
30              
31              
32             sub mm_args
33             {
34 6     6 1 510 my($self, %args) = @_;
35              
36 6 50       25 if($args{DISTNAME})
37             {
38 6   33     52 $self->{prop}->{distname} ||= $args{DISTNAME};
39 6   33     37 $self->{prop}->{share} ||= "blib/lib/auto/share/dist/@{[ $self->distname ]}";
  6         23  
40 6   33     34 $self->{prop}->{arch} ||= "blib/arch/auto/@{[ join '/', split /-/, $self->distname ]}";
  6         14  
41 6         25 $self->save_prop;
42             }
43             else
44             {
45 0         0 Carp::croak "DISTNAME is required";
46             }
47              
48              
49 6 50       29 if(my $build = $self->build)
50             {
51 6         12 foreach my $alien (@{ $build->alien })
  6         26  
52             {
53 0 0       0 next if ref $alien;
54 0   0     0 $args{BUILD_REQUIRES}->{$alien} ||= 0;
55             }
56             }
57              
58 6 100       27 if(my $test = $self->test)
59             {
60 3         6 foreach my $alien (@{ $test->alien })
  3         8  
61             {
62 0 0       0 next if ref $alien;
63 0   0     0 $args{TEST_REQUIRES}->{$alien} ||= 0;
64             }
65             }
66              
67 6         50 %args;
68             }
69              
70 21     21 0 166 sub distname { shift->{prop}->{distname} }
71              
72             sub sharedir
73             {
74 11     11 0 505 my($self, $new) = @_;
75              
76 11 100       34 if(defined $new)
77             {
78 1         3 $self->{prop}->{share} = $new;
79 1         4 $self->save_prop;
80             }
81              
82 11         79 $self->{prop}->{share};
83             }
84              
85             sub archdir
86             {
87 7     7 0 20 my($self, $new) = @_;
88              
89 7 100       17 if(defined $new)
90             {
91 1         4 $self->{prop}->{arch} = $new;
92 1         3 $self->save_prop;
93             }
94              
95 7         858 $self->{prop}->{arch};
96             }
97              
98             sub load_build
99             {
100 22     22 0 742 my($self, $dir, $name, $install) = @_;
101 22 100       566 return unless -d $dir;
102 19         1567 my($fbx) = File::Glob::bsd_glob("./$dir/*.fbx");
103              
104 19         59 my $options;
105 19         193 my $platform = FFI::Build::Platform->default;
106              
107 19 100       57 if($fbx)
108             {
109 6         250 $name = File::Basename::basename($fbx);
110 6         34 $name =~ s/\.fbx$//;
111 6         9 $options = do {
112             package FFI::Build::MM::FBX;
113 6         14 our $DIR = $dir;
114 6         29 our $PLATFORM = $platform;
115              
116             # make sure we catch all of the errors
117             # code copied from `perldoc -f do`
118 6         1600 my $return = do $fbx;
119 6 100       26 unless ( $return ) {
120 1 50       199 Carp::croak( "couldn't parse $fbx: $@" ) if $@;
121 0 0       0 Carp::croak( "couldn't do $fbx: $!" ) unless defined $return;
122 0 0       0 Carp::croak( "couldn't run $fbx" ) unless $return;
123             }
124              
125 5         13 $return;
126             };
127             }
128             else
129             {
130 13   66     58 $name ||= $self->distname;
131 13         90 $options = {
132             source => ["$dir/*.c", "$dir/*.cxx", "$dir/*.cpp"],
133             };
134             # if we see a Go, V, Rust or Zig control file then we assume the
135             # ffi mod is written in that language.
136 13         61 foreach my $control_file ("$dir/Cargo.toml", "$dir/go.mod", "$dir/v.mod", "$dir/build.zig")
137             {
138 52 50       790 if(-f $control_file)
139             {
140 0         0 $options->{source} = [$control_file];
141 0         0 last;
142             }
143             }
144             }
145              
146 18   33     128 $options->{platform} ||= $platform;
147 18 100 66     127 $options->{dir} ||= ref $install ? $install->($options) : $install;
148 18 50       71 $options->{verbose} = 1 unless defined $options->{verbose};
149 18         159 FFI::Build->new($name, %$options);
150             }
151              
152             sub build
153             {
154 8     8 0 18 my($self) = @_;
155 8   33     76 $self->{build} ||= $self->load_build('ffi', undef, $self->sharedir . "/lib");
156             }
157              
158             sub test
159             {
160 8     8 0 22 my($self) = @_;
161             $self->{test} ||= $self->load_build('t/ffi', 'test', sub {
162 5     5   11 my($opt) = @_;
163 5   50     30 my $buildname = $opt->{buildname} || '_build';
164 5         19 "t/ffi/$buildname";
165 8   66     110 });
166             }
167              
168             sub save_prop
169             {
170 5     5   13 my($self) = @_;
171 5 100       21 return unless $self->{save};
172 1         283 open my $fh, '>', 'fbx.json';
173 1         13 print $fh JSON::PP::encode_json($self->{prop});
174 1         373 close $fh;
175             }
176              
177             sub load_prop
178             {
179 9     9 0 22 my($self) = @_;
180 9 100       57 return unless $self->{save};
181 5 100       4186 unless(-f 'fbx.json')
182             {
183 2         9 $self->{prop} = {};
184 2         5 return;
185             }
186 3         175 open my $fh, '<', 'fbx.json';
187 3         9 $self->{prop} = JSON::PP::decode_json(do { local $/; <$fh> });
  3         20  
  3         188  
188 3         3598 close $fh;
189             }
190              
191             sub clean
192             {
193 1     1 0 8 my($self) = @_;
194 1         11 foreach my $stage (qw( build test ))
195             {
196 2         93 my $build = $self->$stage;
197 2 50       24 $build->clean if $build;
198             }
199 1 50       796 unlink 'fbx.json' if -f 'fbx.json';
200             }
201              
202              
203             sub mm_postamble
204             {
205 1     1 1 3 my($self) = @_;
206              
207 1         2 my $postamble = ".PHONY: fbx_build ffi fbx_test ffi-test fbx_clean ffi-clean\n\n";
208              
209             # make fbx_realclean ; make clean
210 1         2 $postamble .= "realclean :: fbx_clean\n" .
211             "\n" .
212             "fbx_clean ffi-clean:\n" .
213             "\t\$(FULLPERL) -MFFI::Build::MM=cmd -e fbx_clean\n\n";
214              
215             # make fbx_build; make
216 1         2 $postamble .= "pure_all :: fbx_build\n" .
217             "\n" .
218             "fbx_build ffi:\n" .
219             "\t\$(FULLPERL) -MFFI::Build::MM=cmd -e fbx_build\n\n";
220              
221             # make fbx_test; make test
222 1         2 $postamble .= "subdirs-test_dynamic subdirs-test_static subdirs-test :: fbx_test\n" .
223             "\n" .
224             "fbx_test ffi-test:\n" .
225             "\t\$(FULLPERL) -MFFI::Build::MM=cmd -e fbx_test\n\n";
226              
227 1         2 $postamble;
228             }
229              
230             sub action_build
231             {
232 1     1 0 3 my($self) = @_;
233 1         5 my $build = $self->build;
234 1 50       5 if($build)
235             {
236 1         6 my $lib = $build->build;
237 1 50       20 if($self->archdir)
238             {
239 1         186 File::Path::mkpath($self->archdir, 0, oct(755));
240 1         12 my $archfile = File::Spec->catfile($self->archdir, File::Basename::basename($self->archdir) . ".txt");
241 1         189 open my $fh, '>', $archfile;
242 1         28 my $lib_path = $lib->path;
243 1         14 $lib_path =~ s/^blib\/lib\///;
244 1         10 print $fh "FFI::Build\@$lib_path\n";
245 1         43 close $fh;
246             }
247             }
248 1         35 return;
249             }
250              
251             sub action_test
252             {
253 1     1 0 4 my($self) = @_;
254 1         8 my $build = $self->test;
255 1 50       16 $build->build if $build;
256             }
257              
258             sub action_clean
259             {
260 1     1 0 10 my($self) = @_;
261 1         9 my $build = $self->clean;
262 1         21 ();
263             }
264              
265             sub import
266             {
267 2     2   1877 my(undef, @args) = @_;
268 2         43 foreach my $arg (@args)
269             {
270 1 50       5 if($arg eq 'cmd')
271             {
272             package main;
273              
274             my $mm = sub {
275 3     3   28 my($action) = @_;
276 3         57 my $build = FFI::Build::MM->new;
277 3         27 $build->$action;
278 1         5 };
279              
280 3     3   33 no warnings 'once';
  3         33  
  3         641  
281              
282             *fbx_build = sub {
283 1     1   4747 $mm->('action_build');
284 1         6 };
285              
286             *fbx_test = sub {
287 1     1   3408 $mm->('action_test');
288 1         5 };
289              
290             *fbx_clean = sub {
291 1     1   6091 $mm->('action_clean');
292 1         7 };
293             }
294             }
295             }
296              
297             1;
298              
299             __END__