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