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   234274 use strict;
  3         14  
  3         98  
4 3     3   18 use warnings;
  3         6  
  3         80  
5 3     3   74 use 5.008004;
  3         11  
6 3     3   14 use Carp ();
  3         5  
  3         57  
7 3     3   958 use FFI::Build;
  3         11  
  3         23  
8 3     3   2398 use JSON::PP ();
  3         43579  
  3         92  
9 3     3   27 use File::Glob ();
  3         9  
  3         54  
10 3     3   17 use File::Basename ();
  3         11  
  3         42  
11 3     3   13 use File::Path ();
  3         5  
  3         37  
12 3     3   1560 use File::Copy ();
  3         7382  
  3         93  
13 3     3   2571 use ExtUtils::MakeMaker 7.12;
  3         299713  
  3         5308  
14              
15             # ABSTRACT: FFI::Build installer code for ExtUtils::MakeMaker
16             our $VERSION = '2.08'; # VERSION
17              
18              
19             sub new
20             {
21 9     9 1 14349 my($class, %opt) = @_;
22              
23 9 100       51 my $save = defined $opt{save} ? $opt{save} : 1;
24              
25 9         34 my $self = bless { save => $save }, $class;
26 9         62 $self->load_prop;
27              
28 9         51 $self;
29             }
30              
31              
32             sub mm_args
33             {
34 6     6 1 621 my($self, %args) = @_;
35              
36 6 50       24 if($args{DISTNAME})
37             {
38 6   33     67 $self->{prop}->{distname} ||= $args{DISTNAME};
39 6   33     39 $self->{prop}->{share} ||= "blib/lib/auto/share/dist/@{[ $self->distname ]}";
  6         53  
40 6   33     45 $self->{prop}->{arch} ||= "blib/arch/auto/@{[ join '/', split /-/, $self->distname ]}";
  6         19  
41 6         33 $self->save_prop;
42             }
43             else
44             {
45 0         0 Carp::croak "DISTNAME is required";
46             }
47              
48              
49 6 50       35 if(my $build = $self->build)
50             {
51 6         13 foreach my $alien (@{ $build->alien })
  6         24  
52             {
53 0 0       0 next if ref $alien;
54 0   0     0 $args{BUILD_REQUIRES}->{$alien} ||= 0;
55             }
56             }
57              
58 6 100       22 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         48 %args;
68             }
69              
70 21     21 0 191 sub distname { shift->{prop}->{distname} }
71              
72             sub sharedir
73             {
74 11     11 0 790 my($self, $new) = @_;
75              
76 11 100       52 if(defined $new)
77             {
78 1         5 $self->{prop}->{share} = $new;
79 1         6 $self->save_prop;
80             }
81              
82 11         81 $self->{prop}->{share};
83             }
84              
85             sub archdir
86             {
87 7     7 0 27 my($self, $new) = @_;
88              
89 7 100       26 if(defined $new)
90             {
91 1         4 $self->{prop}->{arch} = $new;
92 1         3 $self->save_prop;
93             }
94              
95 7         899 $self->{prop}->{arch};
96             }
97              
98             sub load_build
99             {
100 22     22 0 1040 my($self, $dir, $name, $install) = @_;
101 22 100       403 return unless -d $dir;
102 19         1488 my($fbx) = File::Glob::bsd_glob("./$dir/*.fbx");
103              
104 19         91 my $options;
105 19         215 my $platform = FFI::Build::Platform->default;
106              
107 19 100       67 if($fbx)
108             {
109 6         313 $name = File::Basename::basename($fbx);
110 6         57 $name =~ s/\.fbx$//;
111 6         15 $options = do {
112             package FFI::Build::MM::FBX;
113 6         17 our $DIR = $dir;
114 6         13 our $PLATFORM = $platform;
115              
116             # make sure we catch all of the errors
117             # code copied from `perldoc -f do`
118 6         1827 my $return = do $fbx;
119 6 100       35 unless ( $return ) {
120 1 50       173 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         14 $return;
126             };
127             }
128             else
129             {
130 13   66     57 $name ||= $self->distname;
131 13         92 $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         93 foreach my $control_file ("$dir/Cargo.toml", "$dir/go.mod", "$dir/build.zig")
137             {
138 39 50       548 if(-f $control_file)
139             {
140 0         0 $options->{source} = [$control_file];
141 0         0 last;
142             }
143             }
144             }
145              
146 18   33     180 $options->{platform} ||= $platform;
147 18 100 66     153 $options->{dir} ||= ref $install ? $install->($options) : $install;
148 18 50       81 $options->{verbose} = 1 unless defined $options->{verbose};
149 18         189 FFI::Build->new($name, %$options);
150             }
151              
152             sub build
153             {
154 8     8 0 353 my($self) = @_;
155 8   33     123 $self->{build} ||= $self->load_build('ffi', undef, $self->sharedir . "/lib");
156             }
157              
158             sub test
159             {
160 8     8 0 25 my($self) = @_;
161             $self->{test} ||= $self->load_build('t/ffi', 'test', sub {
162 5     5   13 my($opt) = @_;
163 5   50     30 my $buildname = $opt->{buildname} || '_build';
164 5         25 "t/ffi/$buildname";
165 8   66     126 });
166             }
167              
168             sub save_prop
169             {
170 5     5   15 my($self) = @_;
171 5 100       24 return unless $self->{save};
172 1         97 open my $fh, '>', 'fbx.json';
173 1         10 print $fh JSON::PP::encode_json($self->{prop});
174 1         387 close $fh;
175             }
176              
177             sub load_prop
178             {
179 9     9 0 28 my($self) = @_;
180 9 100       66 return unless $self->{save};
181 5 100       122 unless(-f 'fbx.json')
182             {
183 2         9 $self->{prop} = {};
184 2         7 return;
185             }
186 3         148 open my $fh, '<', 'fbx.json';
187 3         13 $self->{prop} = JSON::PP::decode_json(do { local $/; <$fh> });
  3         15  
  3         203  
188 3         4462 close $fh;
189             }
190              
191             sub clean
192             {
193 1     1 0 17 my($self) = @_;
194 1         9 foreach my $stage (qw( build test ))
195             {
196 2         49 my $build = $self->$stage;
197 2 50       26 $build->clean if $build;
198             }
199 1 50       83 unlink 'fbx.json' if -f 'fbx.json';
200             }
201              
202              
203             sub mm_postamble
204             {
205 1     1 1 5 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         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         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         12 $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         5 $postamble;
228             }
229              
230             sub action_build
231             {
232 1     1 0 13 my($self) = @_;
233 1         5 my $build = $self->build;
234 1 50       6 if($build)
235             {
236 1         20 my $lib = $build->build;
237 1 50       33 if($self->archdir)
238             {
239 1         12 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         125 open my $fh, '>', $archfile;
242 1         11 my $lib_path = $lib->path;
243 1         25 $lib_path =~ s/^blib\/lib\///;
244 1         18 print $fh "FFI::Build\@$lib_path\n";
245 1         63 close $fh;
246             }
247             }
248 1         75 return;
249             }
250              
251             sub action_test
252             {
253 1     1 0 6 my($self) = @_;
254 1         10 my $build = $self->test;
255 1 50       11 $build->build if $build;
256             }
257              
258             sub action_clean
259             {
260 1     1 0 20 my($self) = @_;
261 1         30 my $build = $self->clean;
262 1         10 ();
263             }
264              
265             sub import
266             {
267 2     2   1439 my(undef, @args) = @_;
268 2         41 foreach my $arg (@args)
269             {
270 1 50       10 if($arg eq 'cmd')
271             {
272             package main;
273              
274             my $mm = sub {
275 3     3   35 my($action) = @_;
276 3         82 my $build = FFI::Build::MM->new;
277 3         41 $build->$action;
278 1         6 };
279              
280 3     3   32 no warnings 'once';
  3         6  
  3         525  
281              
282             *fbx_build = sub {
283 1     1   3729 $mm->('action_build');
284 1         6 };
285              
286             *fbx_test = sub {
287 1     1   3960 $mm->('action_test');
288 1         6 };
289              
290             *fbx_clean = sub {
291 1     1   8277 $mm->('action_clean');
292 1         8 };
293             }
294             }
295             }
296              
297             1;
298              
299             __END__