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   179652 use strict;
  3         12  
  3         73  
4 3     3   15 use warnings;
  3         12  
  3         59  
5 3     3   46 use 5.008004;
  3         24  
6 3     3   17 use Carp ();
  3         4  
  3         52  
7 3     3   708 use FFI::Build;
  3         9  
  3         16  
8 3     3   1803 use JSON::PP ();
  3         34613  
  3         81  
9 3     3   22 use File::Glob ();
  3         6  
  3         47  
10 3     3   14 use File::Basename ();
  3         6  
  3         37  
11 3     3   13 use File::Path ();
  3         6  
  3         32  
12 3     3   1395 use File::Copy ();
  3         5928  
  3         77  
13 3     3   1955 use ExtUtils::MakeMaker 7.12;
  3         242074  
  3         4121  
14              
15             # ABSTRACT: FFI::Build installer code for ExtUtils::MakeMaker
16             our $VERSION = '2.07'; # VERSION
17              
18              
19             sub new
20             {
21 9     9 1 14237 my($class, %opt) = @_;
22              
23 9 100       37 my $save = defined $opt{save} ? $opt{save} : 1;
24              
25 9         28 my $self = bless { save => $save }, $class;
26 9         42 $self->load_prop;
27              
28 9         28 $self;
29             }
30              
31              
32             sub mm_args
33             {
34 6     6 1 519 my($self, %args) = @_;
35              
36 6 50       20 if($args{DISTNAME})
37             {
38 6   33     50 $self->{prop}->{distname} ||= $args{DISTNAME};
39 6   33     30 $self->{prop}->{share} ||= "blib/lib/auto/share/dist/@{[ $self->distname ]}";
  6         15  
40 6   33     31 $self->{prop}->{arch} ||= "blib/arch/auto/@{[ join '/', split /-/, $self->distname ]}";
  6         23  
41 6         23 $self->save_prop;
42             }
43             else
44             {
45 0         0 Carp::croak "DISTNAME is required";
46             }
47              
48              
49 6 50       27 if(my $build = $self->build)
50             {
51 6         11 foreach my $alien (@{ $build->alien })
  6         20  
52             {
53 0 0       0 next if ref $alien;
54 0   0     0 $args{BUILD_REQUIRES}->{$alien} ||= 0;
55             }
56             }
57              
58 6 100       17 if(my $test = $self->test)
59             {
60 3         6 foreach my $alien (@{ $test->alien })
  3         7  
61             {
62 0 0       0 next if ref $alien;
63 0   0     0 $args{TEST_REQUIRES}->{$alien} ||= 0;
64             }
65             }
66              
67 6         37 %args;
68             }
69              
70 21     21 0 159 sub distname { shift->{prop}->{distname} }
71              
72             sub sharedir
73             {
74 11     11 0 567 my($self, $new) = @_;
75              
76 11 100       29 if(defined $new)
77             {
78 1         3 $self->{prop}->{share} = $new;
79 1         4 $self->save_prop;
80             }
81              
82 11         54 $self->{prop}->{share};
83             }
84              
85             sub archdir
86             {
87 7     7 0 17 my($self, $new) = @_;
88              
89 7 100       19 if(defined $new)
90             {
91 1         3 $self->{prop}->{arch} = $new;
92 1         4 $self->save_prop;
93             }
94              
95 7         614 $self->{prop}->{arch};
96             }
97              
98             sub load_build
99             {
100 22     22 0 833 my($self, $dir, $name, $install) = @_;
101 22 100       289 return unless -d $dir;
102 19         1026 my($fbx) = File::Glob::bsd_glob("./$dir/*.fbx");
103              
104 19         64 my $options;
105 19         161 my $platform = FFI::Build::Platform->default;
106              
107 19 100       45 if($fbx)
108             {
109 6         183 $name = File::Basename::basename($fbx);
110 6         32 $name =~ s/\.fbx$//;
111 6         12 $options = do {
112             package FFI::Build::MM::FBX;
113 6         13 our $DIR = $dir;
114 6         16 our $PLATFORM = $platform;
115              
116             # make sure we catch all of the errors
117             # code copied from `perldoc -f do`
118 6         1095 my $return = do $fbx;
119 6 100       20 unless ( $return ) {
120 1 50       154 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     54 $name ||= $self->distname;
131 13         65 $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         64 foreach my $control_file ("$dir/Cargo.toml", "$dir/go.mod", "$dir/build.zig")
137             {
138 39 50       431 if(-f $control_file)
139             {
140 0         0 $options->{source} = [$control_file];
141 0         0 last;
142             }
143             }
144             }
145              
146 18   33     122 $options->{platform} ||= $platform;
147 18 100 66     111 $options->{dir} ||= ref $install ? $install->($options) : $install;
148 18 50       55 $options->{verbose} = 1 unless defined $options->{verbose};
149 18         143 FFI::Build->new($name, %$options);
150             }
151              
152             sub build
153             {
154 8     8 0 21 my($self) = @_;
155 8   33     192 $self->{build} ||= $self->load_build('ffi', undef, $self->sharedir . "/lib");
156             }
157              
158             sub test
159             {
160 8     8 0 16 my($self) = @_;
161             $self->{test} ||= $self->load_build('t/ffi', 'test', sub {
162 5     5   11 my($opt) = @_;
163 5   50     32 my $buildname = $opt->{buildname} || '_build';
164 5         22 "t/ffi/$buildname";
165 8   66     97 });
166             }
167              
168             sub save_prop
169             {
170 5     5   12 my($self) = @_;
171 5 100       17 return unless $self->{save};
172 1         92 open my $fh, '>', 'fbx.json';
173 1         8 print $fh JSON::PP::encode_json($self->{prop});
174 1         326 close $fh;
175             }
176              
177             sub load_prop
178             {
179 9     9 0 18 my($self) = @_;
180 9 100       42 return unless $self->{save};
181 5 100       76 unless(-f 'fbx.json')
182             {
183 2         8 $self->{prop} = {};
184 2         6 return;
185             }
186 3         94 open my $fh, '<', 'fbx.json';
187 3         9 $self->{prop} = JSON::PP::decode_json(do { local $/; <$fh> });
  3         14  
  3         115  
188 3         2911 close $fh;
189             }
190              
191             sub clean
192             {
193 1     1 0 5 my($self) = @_;
194 1         8 foreach my $stage (qw( build test ))
195             {
196 2         23 my $build = $self->$stage;
197 2 50       20 $build->clean if $build;
198             }
199 1 50       55 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         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         3 $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         3 $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         6 my $build = $self->build;
234 1 50       6 if($build)
235             {
236 1         4 my $lib = $build->build;
237 1 50       17 if($self->archdir)
238             {
239 1         4 File::Path::mkpath($self->archdir, 0, oct(755));
240 1         6 my $archfile = File::Spec->catfile($self->archdir, File::Basename::basename($self->archdir) . ".txt");
241 1         67 open my $fh, '>', $archfile;
242 1         20 my $lib_path = $lib->path;
243 1         17 $lib_path =~ s/^blib\/lib\///;
244 1         11 print $fh "FFI::Build\@$lib_path\n";
245 1         32 close $fh;
246             }
247             }
248 1         31 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       10 $build->build if $build;
256             }
257              
258             sub action_clean
259             {
260 1     1 0 8 my($self) = @_;
261 1         13 my $build = $self->clean;
262 1         8 ();
263             }
264              
265             sub import
266             {
267 2     2   1224 my(undef, @args) = @_;
268 2         28 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   17 my($action) = @_;
276 3         48 my $build = FFI::Build::MM->new;
277 3         27 $build->$action;
278 1         5 };
279              
280 3     3   28 no warnings 'once';
  3         12  
  3         445  
281              
282             *fbx_build = sub {
283 1     1   2956 $mm->('action_build');
284 1         6 };
285              
286             *fbx_test = sub {
287 1     1   2944 $mm->('action_test');
288 1         3 };
289              
290             *fbx_clean = sub {
291 1     1   3819 $mm->('action_clean');
292 1         6 };
293             }
294             }
295             }
296              
297             1;
298              
299             __END__