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   279176 use strict;
  10         29  
  10         294  
4 10     10   53 use warnings;
  10         19  
  10         249  
5 10     10   187 use 5.008001;
  10         37  
6 10     10   52 use Config ();
  10         19  
  10         236  
7 10     10   53 use Carp ();
  10         23  
  10         163  
8 10     10   4104 use Text::ParseWords ();
  10         11866  
  10         315  
9 10     10   68 use List::Util 1.45 ();
  10         196  
  10         180  
10 10     10   799 use File::Temp ();
  10         20949  
  10         195  
11 10     10   4580 use Capture::Tiny ();
  10         54308  
  10         11493  
12              
13             # ABSTRACT: Platform specific configuration.
14             our $VERSION = '0.12'; # VERSION
15              
16              
17             sub new
18             {
19 29     29 1 5254 my($class, $config) = @_;
20 29   50     213 $config ||= \%Config::Config;
21 29         105 my $self = bless {
22             config => $config,
23             }, $class;
24 29         139 $self;
25             }
26              
27              
28             my $default;
29             sub default
30             {
31 21   66 21 1 190 $default ||= FFI::Build::Platform->new;
32             }
33              
34             sub _context
35             {
36 260 50   260   670 if(defined wantarray)
37             {
38 260 100       487 if(wantarray)
39             {
40 6         99 return @_;
41             }
42             else
43             {
44 254         2936 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   868 my($self) = @_;
56 438 100       2257 ref $self ? $self : $self->default;
57             }
58              
59              
60             sub osname
61             {
62 223     223 1 534 _context _self(shift)->{config}->{osname};
63             }
64              
65              
66             sub object_suffix
67             {
68 18     18 1 233 _context _self(shift)->{config}->{obj_ext};
69             }
70              
71              
72             sub library_suffix
73             {
74 19     19 1 168 my $self = _self(shift);
75 19         78 my $osname = $self->osname;
76 19 50       176 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         179 return _context '.' . $self->{config}->{dlext};
87             }
88             }
89              
90              
91             sub library_prefix
92             {
93 17     17 1 5058 my $self = _self(shift);
94            
95             # this almost certainly requires refinement.
96 17 50       74 if($self->osname =~ /^(MSWin32|msys|cygwin)$/)
97             {
98 0         0 return '';
99             }
100             else
101             {
102 17         129 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 1052 my $cc = shift->{config}->{cc};
112 44         318 $cc =~ s/^\s+//;
113 44         194 $cc =~ s/\s+$//;
114 44         224 $cc;
115             }
116              
117              
118             sub cxx
119             {
120 11     11 1 5327 my $self = _self(shift);
121 11 50 0     491 if($self->{config}->{ccname} eq 'gcc')
    0          
122             {
123 11 50       64 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       34 if($self->cc =~ /clang/)
130             {
131 0         0 return 'clang++';
132             }
133             else
134             {
135 11         87 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 5 my $self = _self(shift);
152 2 50       12 if($self->{config}->{ccname} eq 'gcc')
153             {
154 2 50       6 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         10 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 198 my $ld = shift->{config}->{ld};
172 7         48 $ld =~ s/^\s+//;
173 7         26 $ld =~ s/\s+$//;
174 7         25 $ld;
175             }
176              
177             sub _uniq
178             {
179 60     60   21691 List::Util::uniq(@_);
180             }
181              
182              
183             sub shellwords
184             {
185 62     62 1 186 my $self = _self(shift);
186 62 50       172 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         395 Text::ParseWords::shellwords(@_);
194             }
195             }
196              
197             sub _context_args
198             {
199 60 100   60   378 wantarray ? @_ : join ' ', @_;
200             }
201              
202              
203             sub cflags
204             {
205 23     23 1 100 my $self = _self(shift);
206 23         59 my @cflags;
207 23         166 push @cflags, _uniq grep /^-fPIC$/i, $self->shellwords($self->{config}->{cccdlflags});
208 23         109 _context_args @cflags;
209             }
210              
211              
212             sub ldflags
213             {
214 7     7 1 75 my $self = _self(shift);
215 7         24 my @ldflags;
216 7 50 33     70 if($self->osname eq 'cygwin')
    50          
    50          
    50          
217             {
218 10     10   98 no warnings 'qw';
  10         21  
  10         1009  
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   70 no warnings 'qw';
  10         25  
  10         10480  
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         53 push @ldflags, _uniq grep /^-shared$/i, $self->shellwords($self->{config}->{lddlflags});
238             }
239 7         54 _context_args @ldflags;
240             }
241              
242              
243             sub extra_system_inc
244             {
245 23     23 1 69 my $self = _self(shift);
246 23         52 my @dir;
247 23         81 push @dir, _uniq grep /^-I(.*)$/, $self->shellwords(map { $self->{config}->{$_} } qw( ccflags ccflags_nolargefiles cppflags ));
  69         918  
248 23         116 _context_args @dir;
249             }
250              
251              
252             sub extra_system_lib
253             {
254 7     7 1 43 my $self = _self(shift);
255 7         23 my @dir;
256 7         38 push @dir, _uniq grep /^-L(.*)$/, $self->shellwords(map { $self->{config}->{$_} } qw( lddlflags ldflags ldflags_nolargefiles ));
  21         340  
257 7         54 _context_args @dir;
258             }
259              
260              
261             sub cc_mm_works
262             {
263 5     5 1 1475 my $self = _self(shift);
264 5         11 my $verbose = shift;
265            
266 5 50       21 unless(defined $self->{cc_mm_works})
267             {
268 5         1018 require FFI::Build::File::C;
269 5         46 my $c = FFI::Build::File::C->new(\"#include \"foo.h\"\n");
270 5         46 my $dir = File::Temp::tempdir( CLEANUP => 1 );
271             {
272 5         2583 open my $fh, '>', "$dir/foo.h";
  5         293  
273 5         64 print $fh "\n";
274 5         157 close $fh;
275             }
276              
277 5         33 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   5917 print "+ @cmd\n";
288 5         48592 system @cmd;
289 5         309 });
290            
291 5 100       6522 if($verbose)
292             {
293 1         47 print $out;
294             }
295            
296            
297 5 50 33     169 if(!$exit && $out =~ /foo\.h/)
298             {
299 5         233 $self->{cc_mm_works} = '-MM';
300             }
301             else
302             {
303 0         0 $self->{cc_mm_works} = 0;
304             }
305             }
306            
307 5         84 $self->{cc_mm_works};
308             }
309              
310              
311             sub flag_object_output
312             {
313 14     14 1 47 my $self = _self(shift);
314 14         41 my $file = shift;
315 14 50 33     47 if($self->osname eq 'MSWin32' && $self->{config}->{ccname} eq 'cl')
316             {
317 0         0 return ("-Fo$file");
318             }
319             else
320             {
321 14         99 return ('-o' => $file);
322             }
323             }
324              
325              
326             sub flag_library_output
327             {
328 5     5 1 22 my $self = _self(shift);
329 5         18 my $file = shift;
330 5 50 33     18 if($self->osname eq 'MSWin32' && $self->{config}->{ccname} eq 'cl')
331             {
332 0         0 return ("-OUT:$file");
333             }
334             else
335             {
336 5         59 return ('-o' => $file);
337             }
338             }
339              
340              
341             sub which
342             {
343 2     2 1 13 my(undef, $command) = @_;
344 2         1836 require IPC::Cmd;
345 2         112166 IPC::Cmd::can_run($command);
346             }
347              
348              
349             sub diag
350             {
351 2     2 1 860 my $self = _self(shift);
352 2         5 my @diag;
353            
354 2         7 push @diag, "osname : ". join(", ", $self->osname);
355 2         9 push @diag, "cc : ". $self->cc;
356 2   50     5 push @diag, "cxx : ". (eval { $self->cxx } || '???' );
357 2   50     5 push @diag, "for : ". (eval { $self->for } || '???' );
358 2         7 push @diag, "ld : ". $self->ld;
359 2         8 push @diag, "cflags : ". $self->cflags;
360 2         9 push @diag, "ldflags : ". $self->ldflags;
361 2         8 push @diag, "extra system inc : ". $self->extra_system_inc;
362 2         8 push @diag, "extra system lib : ". $self->extra_system_lib;
363 2         8 push @diag, "object suffix : ". join(", ", $self->object_suffix);
364 2         11 push @diag, "library prefix : ". join(", ", $self->library_prefix);
365 2         7 push @diag, "library suffix : ". join(", ", $self->library_suffix);
366 2         6 push @diag, "cc mm works : ". $self->cc_mm_works;
367              
368 2         119 join "\n", @diag;
369             }
370              
371             1;
372              
373             __END__