File Coverage

blib/lib/FFI/Build/Platform.pm
Criterion Covered Total %
statement 139 164 84.7
branch 26 50 52.0
condition 9 24 37.5
subroutine 36 36 100.0
pod 20 20 100.0
total 230 294 78.2


line stmt bran cond sub pod time code
1             package FFI::Build::Platform;
2              
3 10     10   256690 use strict;
  10         25  
  10         257  
4 10     10   44 use warnings;
  10         17  
  10         226  
5 10     10   166 use 5.008001;
  10         31  
6 10     10   42 use Config ();
  10         17  
  10         151  
7 10     10   37 use Carp ();
  10         19  
  10         123  
8 10     10   3438 use Text::ParseWords ();
  10         9813  
  10         231  
9 10     10   62 use List::Util 1.45 ();
  10         151  
  10         144  
10 10     10   626 use File::Temp ();
  10         17410  
  10         128  
11 10     10   3995 use Capture::Tiny ();
  10         45448  
  10         9581  
12              
13             # ABSTRACT: Platform specific configuration.
14             our $VERSION = '0.11'; # VERSION
15              
16              
17             sub new
18             {
19 29     29 1 6244 my($class, $config) = @_;
20 29   50     178 $config ||= \%Config::Config;
21 29         89 my $self = bless {
22             config => $config,
23             }, $class;
24 29         130 $self;
25             }
26              
27              
28             my $default;
29             sub default
30             {
31 21   66 21 1 151 $default ||= FFI::Build::Platform->new;
32             }
33              
34             sub _context
35             {
36 260 50   260   475 if(defined wantarray)
37             {
38 260 100       390 if(wantarray)
39             {
40 6         75 return @_;
41             }
42             else
43             {
44 254         2130 return $_[0];
45             }
46             }
47             else
48             {
49 0         0 Carp::croak("method does not work in void context");
50             }
51             }
52              
53             sub _self
54             {
55 438     438   715 my($self) = @_;
56 438 100       1685 ref $self ? $self : $self->default;
57             }
58              
59              
60             sub osname
61             {
62 223     223 1 383 _context _self(shift)->{config}->{osname};
63             }
64              
65              
66             sub object_suffix
67             {
68 18     18 1 196 _context _self(shift)->{config}->{obj_ext};
69             }
70              
71              
72             sub library_suffix
73             {
74 19     19 1 157 my $self = _self(shift);
75 19         42 my $osname = $self->osname;
76 19 50       121 if($osname eq 'darwin')
    50          
77             {
78 0         0 return _context '.dylib', '.bundle';
79             }
80             elsif($osname =~ /^(MSWin32|msys|cygwin)$/)
81             {
82 0         0 return _context '.dll';
83             }
84             else
85             {
86 19         132 return _context '.' . $self->{config}->{dlext};
87             }
88             }
89              
90              
91             sub library_prefix
92             {
93 17     17 1 3571 my $self = _self(shift);
94            
95             # this almost certainly requires refinement.
96 17 50       58 if($self->osname =~ /^(MSWin32|msys|cygwin)$/)
97             {
98 0         0 return '';
99             }
100             else
101             {
102 17         95 return 'lib';
103             }
104             }
105              
106              
107             sub cc
108             {
109             # TODO: cc could include flags "cc --some-flag" so we should really parse
110             # the first element of cc to be our cc, and push the rest into cflags.
111 44     44 1 330 my $cc = shift->{config}->{cc};
112 44         229 $cc =~ s/^\s+//;
113 44         114 $cc =~ s/\s+$//;
114 44         166 $cc;
115             }
116              
117              
118             sub cxx
119             {
120 11     11 1 5489 my $self = _self(shift);
121 11 50 0     248 if($self->{config}->{ccname} eq 'gcc')
    0          
122             {
123 11 50       37 if($self->cc =~ /gcc$/)
124             {
125 0         0 my $maybe = $self->cc;
126 0         0 $maybe =~ s/gcc$/g++/;
127 0 0       0 return $maybe if $self->which($maybe);
128             }
129 11 50       27 if($self->cc =~ /clang/)
130             {
131 0         0 return 'clang++';
132             }
133             else
134             {
135 11         56 return 'g++';
136             }
137             }
138             elsif($self->osname eq 'MSWin32' && $self->{config}->{ccname} eq 'cl')
139             {
140 0         0 return 'cl';
141             }
142             else
143             {
144 0         0 Carp::croak("unable to detect corresponding C++ compiler");
145             }
146             }
147              
148              
149             sub for
150             {
151 2     2 1 4 my $self = _self(shift);
152 2 50       10 if($self->{config}->{ccname} eq 'gcc')
153             {
154 2 50       5 if($self->cc =~ /gcc$/)
155             {
156 0         0 my $maybe = $self->cc;
157 0         0 $maybe =~ s/gcc$/gfortran/;
158 0 0       0 return $maybe if $self->which($maybe);
159             }
160 2         9 return 'gfortran';
161             }
162             else
163             {
164 0         0 Carp::croak("unable to detect correspnding Fortran Compiler");
165             }
166             }
167              
168              
169             sub ld
170             {
171 7     7 1 159 my $ld = shift->{config}->{ld};
172 7         47 $ld =~ s/^\s+//;
173 7         21 $ld =~ s/\s+$//;
174 7         31 $ld;
175             }
176              
177             sub _uniq
178             {
179 60     60   16414 List::Util::uniq(@_);
180             }
181              
182              
183             sub shellwords
184             {
185 62     62 1 133 my $self = _self(shift);
186 62 50       123 if($self->osname eq 'MSWin32')
187             {
188             # Borrowed from Alien/Base.pm, see the caveat there.
189 0         0 Text::ParseWords::shellwords(map { my $x = $_; $x =~ s,\\,\\\\,g; $x } @_);
  0         0  
  0         0  
  0         0  
190             }
191             else
192             {
193 62         310 Text::ParseWords::shellwords(@_);
194             }
195             }
196              
197             sub _context_args
198             {
199 60 100   60   283 wantarray ? @_ : join ' ', @_;
200             }
201              
202              
203             sub cflags
204             {
205 23     23 1 71 my $self = _self(shift);
206 23         43 my @cflags;
207 23         117 push @cflags, _uniq grep /^-fPIC$/i, $self->shellwords($self->{config}->{cccdlflags});
208 23         84 _context_args @cflags;
209             }
210              
211              
212             sub ldflags
213             {
214 7     7 1 73 my $self = _self(shift);
215 7         24 my @ldflags;
216 7 50 33     35 if($self->osname eq 'cygwin')
    50          
    50          
    50          
217             {
218 10     10   73 no warnings 'qw';
  10         24  
  10         857  
219 0         0 push @ldflags, qw( --shared -Wl,--enable-auto-import -Wl,--export-all-symbols -Wl,--enable-auto-image-base );
220             }
221             elsif($self->osname eq 'MSWin32' && $self->{config}->{ccname} eq 'cl')
222             {
223 0         0 push @ldflags, qw( -link -dll );
224             }
225             elsif($self->osname eq 'MSWin32')
226             {
227             # TODO: VCC support *sigh*
228 10     10   63 no warnings 'qw';
  10         31  
  10         8250  
229 0         0 push @ldflags, qw( -mdll -Wl,--enable-auto-import -Wl,--export-all-symbols -Wl,--enable-auto-image-base );
230             }
231             elsif($self->osname eq 'darwin')
232             {
233 0         0 push @ldflags, '-shared';
234             }
235             else
236             {
237 7         47 push @ldflags, _uniq grep /^-shared$/i, $self->shellwords($self->{config}->{lddlflags});
238             }
239 7         43 _context_args @ldflags;
240             }
241              
242              
243             sub extra_system_inc
244             {
245 23     23 1 59 my $self = _self(shift);
246 23         38 my @dir;
247 23         60 push @dir, _uniq grep /^-I(.*)$/, $self->shellwords(map { $self->{config}->{$_} } qw( ccflags ccflags_nolargefiles cppflags ));
  69         693  
248 23         90 _context_args @dir;
249             }
250              
251              
252             sub extra_system_lib
253             {
254 7     7 1 25 my $self = _self(shift);
255 7         13 my @dir;
256 7         25 push @dir, _uniq grep /^-L(.*)$/, $self->shellwords(map { $self->{config}->{$_} } qw( lddlflags ldflags ldflags_nolargefiles ));
  21         309  
257 7         36 _context_args @dir;
258             }
259              
260              
261             sub cc_mm_works
262             {
263 5     5 1 1201 my $self = _self(shift);
264 5         21 my $verbose = shift;
265            
266 5 50       25 unless(defined $self->{cc_mm_works})
267             {
268 5         860 require FFI::Build::File::C;
269 5         48 my $c = FFI::Build::File::C->new(\"#include \"foo.h\"\n");
270 5         37 my $dir = File::Temp::tempdir( CLEANUP => 1 );
271             {
272 5         1991 open my $fh, '>', "$dir/foo.h";
  5         257  
273 5         52 print $fh "\n";
274 5         124 close $fh;
275             }
276              
277 5         31 my @cmd = (
278             $self->cc,
279             $self->cflags,
280             $self->extra_system_inc,
281             "-I$dir",
282             '-MM',
283             $c->path,
284             );
285            
286             my($out, $exit) = Capture::Tiny::capture_merged(sub {
287 5     5   4965 print "+ @cmd\n";
288 5         55679 system @cmd;
289 5         215 });
290            
291 5 100       5894 if($verbose)
292             {
293 1         39 print $out;
294             }
295            
296            
297 5 50 33     145 if(!$exit && $out =~ /foo\.h/)
298             {
299 5         203 $self->{cc_mm_works} = '-MM';
300             }
301             else
302             {
303 0         0 $self->{cc_mm_works} = 0;
304             }
305             }
306            
307 5         81 $self->{cc_mm_works};
308             }
309              
310              
311             sub flag_object_output
312             {
313 14     14 1 39 my $self = _self(shift);
314 14         31 my $file = shift;
315 14 50 33     28 if($self->osname eq 'MSWin32' && $self->{config}->{ccname} eq 'cl')
316             {
317 0         0 return ("-Fo$file");
318             }
319             else
320             {
321 14         66 return ('-o' => $file);
322             }
323             }
324              
325              
326             sub flag_library_output
327             {
328 5     5 1 17 my $self = _self(shift);
329 5         10 my $file = shift;
330 5 50 33     14 if($self->osname eq 'MSWin32' && $self->{config}->{ccname} eq 'cl')
331             {
332 0         0 return ("-OUT:$file");
333             }
334             else
335             {
336 5         53 return ('-o' => $file);
337             }
338             }
339              
340              
341             sub which
342             {
343 2     2 1 6 my(undef, $command) = @_;
344 2         1342 require IPC::Cmd;
345 2         73756 IPC::Cmd::can_run($command);
346             }
347              
348              
349             sub diag
350             {
351 2     2 1 931 my $self = _self(shift);
352 2         5 my @diag;
353            
354 2         5 push @diag, "osname : ". join(", ", $self->osname);
355 2         8 push @diag, "cc : ". $self->cc;
356 2   50     4 push @diag, "cxx : ". (eval { $self->cxx } || '???' );
357 2   50     4 push @diag, "for : ". (eval { $self->for } || '???' );
358 2         5 push @diag, "ld : ". $self->ld;
359 2         6 push @diag, "cflags : ". $self->cflags;
360 2         7 push @diag, "ldflags : ". $self->ldflags;
361 2         6 push @diag, "extra system inc : ". $self->extra_system_inc;
362 2         6 push @diag, "extra system lib : ". $self->extra_system_lib;
363 2         8 push @diag, "object suffix : ". join(", ", $self->object_suffix);
364 2         9 push @diag, "library prefix : ". join(", ", $self->library_prefix);
365 2         6 push @diag, "library suffix : ". join(", ", $self->library_suffix);
366 2         5 push @diag, "cc mm works : ". $self->cc_mm_works;
367              
368 2         91 join "\n", @diag;
369             }
370              
371             1;
372              
373             __END__