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   221867 use strict;
  3         11  
  3         91  
4 3     3   16 use warnings;
  3         5  
  3         75  
5 3     3   60 use 5.008004;
  3         11  
6 3     3   15 use Carp ();
  3         11  
  3         67  
7 3     3   947 use FFI::Build;
  3         9  
  3         23  
8 3     3   2261 use JSON::PP ();
  3         42083  
  3         138  
9 3     3   25 use File::Glob ();
  3         7  
  3         62  
10 3     3   15 use File::Basename ();
  3         8  
  3         39  
11 3     3   14 use File::Path ();
  3         6  
  3         36  
12 3     3   1761 use File::Copy ();
  3         7212  
  3         93  
13 3     3   2435 use ExtUtils::MakeMaker 7.12;
  3         292626  
  3         5029  
14              
15             # ABSTRACT: FFI::Build installer code for ExtUtils::MakeMaker
16             our $VERSION = '2.06_01'; # TRIAL VERSION
17              
18              
19             sub new
20             {
21 9     9 1 16814 my($class, %opt) = @_;
22              
23 9 100       56 my $save = defined $opt{save} ? $opt{save} : 1;
24              
25 9         44 my $self = bless { save => $save }, $class;
26 9         59 $self->load_prop;
27              
28 9         34 $self;
29             }
30              
31              
32             sub mm_args
33             {
34 6     6 1 623 my($self, %args) = @_;
35              
36 6 50       20 if($args{DISTNAME})
37             {
38 6   33     72 $self->{prop}->{distname} ||= $args{DISTNAME};
39 6   33     32 $self->{prop}->{share} ||= "blib/lib/auto/share/dist/@{[ $self->distname ]}";
  6         17  
40 6   33     35 $self->{prop}->{arch} ||= "blib/arch/auto/@{[ join '/', split /-/, $self->distname ]}";
  6         16  
41 6         24 $self->save_prop;
42             }
43             else
44             {
45 0         0 Carp::croak "DISTNAME is required";
46             }
47              
48              
49 6 50       31 if(my $build = $self->build)
50             {
51 6         13 foreach my $alien (@{ $build->alien })
  6         25  
52             {
53 0 0       0 next if ref $alien;
54 0   0     0 $args{BUILD_REQUIRES}->{$alien} ||= 0;
55             }
56             }
57              
58 6 100       19 if(my $test = $self->test)
59             {
60 3         6 foreach my $alien (@{ $test->alien })
  3         9  
61             {
62 0 0       0 next if ref $alien;
63 0   0     0 $args{TEST_REQUIRES}->{$alien} ||= 0;
64             }
65             }
66              
67 6         43 %args;
68             }
69              
70 21     21 0 158 sub distname { shift->{prop}->{distname} }
71              
72             sub sharedir
73             {
74 11     11 0 681 my($self, $new) = @_;
75              
76 11 100       43 if(defined $new)
77             {
78 1         4 $self->{prop}->{share} = $new;
79 1         5 $self->save_prop;
80             }
81              
82 11         63 $self->{prop}->{share};
83             }
84              
85             sub archdir
86             {
87 7     7 0 24 my($self, $new) = @_;
88              
89 7 100       21 if(defined $new)
90             {
91 1         5 $self->{prop}->{arch} = $new;
92 1         4 $self->save_prop;
93             }
94              
95 7         816 $self->{prop}->{arch};
96             }
97              
98             sub load_build
99             {
100 22     22 0 980 my($self, $dir, $name, $install) = @_;
101 22 100       372 return unless -d $dir;
102 19         1356 my($fbx) = File::Glob::bsd_glob("./$dir/*.fbx");
103              
104 19         79 my $options;
105 19         163 my $platform = FFI::Build::Platform->default;
106              
107 19 100       49 if($fbx)
108             {
109 6         216 $name = File::Basename::basename($fbx);
110 6         39 $name =~ s/\.fbx$//;
111 6         13 $options = do {
112             package FFI::Build::MM::FBX;
113 6         12 our $DIR = $dir;
114 6         12 our $PLATFORM = $platform;
115              
116             # make sure we catch all of the errors
117             # code copied from `perldoc -f do`
118 6         1292 my $return = do $fbx;
119 6 100       25 unless ( $return ) {
120 1 50       175 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         11 $return;
126             };
127             }
128             else
129             {
130 13   66     56 $name ||= $self->distname;
131 13         83 $options = {
132             source => ["$dir/*.c", "$dir/*.cxx", "$dir/*.cpp"],
133             };
134             # if we see a Go, Rust or Zig control file then we assume the
135             # ffi mod is written in that language.
136 13         66 foreach my $control_file ("$dir/Cargo.toml", "$dir/go.mod", "$dir/build.zig")
137             {
138 39 50       524 if(-f $control_file)
139             {
140 0         0 $options->{source} = [$control_file];
141 0         0 last;
142             }
143             }
144             }
145              
146 18   33     142 $options->{platform} ||= $platform;
147 18 100 66     119 $options->{dir} ||= ref $install ? $install->($options) : $install;
148 18 50       71 $options->{verbose} = 1 unless defined $options->{verbose};
149 18         160 FFI::Build->new($name, %$options);
150             }
151              
152             sub build
153             {
154 8     8 0 21 my($self) = @_;
155 8   33     249 $self->{build} ||= $self->load_build('ffi', undef, $self->sharedir . "/lib");
156             }
157              
158             sub test
159             {
160 8     8 0 20 my($self) = @_;
161             $self->{test} ||= $self->load_build('t/ffi', 'test', sub {
162 5     5   13 my($opt) = @_;
163 5   50     38 my $buildname = $opt->{buildname} || '_build';
164 5         25 "t/ffi/$buildname";
165 8   66     136 });
166             }
167              
168             sub save_prop
169             {
170 5     5   14 my($self) = @_;
171 5 100       22 return unless $self->{save};
172 1         136 open my $fh, '>', 'fbx.json';
173 1         12 print $fh JSON::PP::encode_json($self->{prop});
174 1         382 close $fh;
175             }
176              
177             sub load_prop
178             {
179 9     9 0 27 my($self) = @_;
180 9 100       55 return unless $self->{save};
181 5 100       93 unless(-f 'fbx.json')
182             {
183 2         9 $self->{prop} = {};
184 2         5 return;
185             }
186 3         118 open my $fh, '<', 'fbx.json';
187 3         12 $self->{prop} = JSON::PP::decode_json(do { local $/; <$fh> });
  3         14  
  3         141  
188 3         3522 close $fh;
189             }
190              
191             sub clean
192             {
193 1     1 0 9 my($self) = @_;
194 1         9 foreach my $stage (qw( build test ))
195             {
196 2         21 my $build = $self->$stage;
197 2 50       24 $build->clean if $build;
198             }
199 1 50       59 unlink 'fbx.json' if -f 'fbx.json';
200             }
201              
202              
203             sub mm_postamble
204             {
205 1     1 1 4 my($self) = @_;
206              
207 1         3 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         3 $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         4 $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         3 $postamble;
228             }
229              
230             sub action_build
231             {
232 1     1 0 3 my($self) = @_;
233 1         4 my $build = $self->build;
234 1 50       6 if($build)
235             {
236 1         4 my $lib = $build->build;
237 1 50       29 if($self->archdir)
238             {
239 1         5 File::Path::mkpath($self->archdir, 0, oct(755));
240 1         17 my $archfile = File::Spec->catfile($self->archdir, File::Basename::basename($self->archdir) . ".txt");
241 1         100 open my $fh, '>', $archfile;
242 1         17 my $lib_path = $lib->path;
243 1         33 $lib_path =~ s/^blib\/lib\///;
244 1         12 print $fh "FFI::Build\@$lib_path\n";
245 1         39 close $fh;
246             }
247             }
248 1         41 return;
249             }
250              
251             sub action_test
252             {
253 1     1 0 5 my($self) = @_;
254 1         9 my $build = $self->test;
255 1 50       11 $build->build if $build;
256             }
257              
258             sub action_clean
259             {
260 1     1 0 12 my($self) = @_;
261 1         14 my $build = $self->clean;
262 1         14 ();
263             }
264              
265             sub import
266             {
267 2     2   1417 my(undef, @args) = @_;
268 2         33 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   20 my($action) = @_;
276 3         58 my $build = FFI::Build::MM->new;
277 3         30 $build->$action;
278 1         5 };
279              
280 3     3   34 no warnings 'once';
  3         8  
  3         528  
281              
282             *fbx_build = sub {
283 1     1   3527 $mm->('action_build');
284 1         5 };
285              
286             *fbx_test = sub {
287 1     1   3484 $mm->('action_test');
288 1         4 };
289              
290             *fbx_clean = sub {
291 1     1   4625 $mm->('action_clean');
292 1         6 };
293             }
294             }
295             }
296              
297             1;
298              
299             __END__