File Coverage

blib/lib/Alien/Base/Wrapper.pm
Criterion Covered Total %
statement 136 153 88.8
branch 40 56 71.4
condition 4 6 66.6
subroutine 19 20 95.0
pod 7 7 100.0
total 206 242 85.1


line stmt bran cond sub pod time code
1             package Alien::Base::Wrapper;
2              
3 2     2   245612 use strict;
  2         14  
  2         63  
4 2     2   10 use warnings;
  2         4  
  2         48  
5 2     2   44 use 5.006;
  2         8  
6 2     2   10 use Config;
  2         4  
  2         68  
7 2     2   521 use Text::ParseWords qw( shellwords );
  2         1504  
  2         3148  
8              
9             # NOTE: Although this module is now distributed with Alien-Build,
10             # it should have NO non-perl-core dependencies for all Perls
11             # 5.6.0-5.30.1 (as of this writing, and any Perl more recent).
12             # You should be able to extract this module from the rest of
13             # Alien-Build and use it by itself. (There is a dzil plugin
14             # for this [AlienBase::Wrapper::Bundle]
15              
16             # ABSTRACT: Compiler and linker wrapper for Alien
17             our $VERSION = '2.46'; # VERSION
18              
19              
20             sub _join
21             {
22             join ' ',
23             map {
24 68     68   131 my $x = $_;
  106         141  
25 106         149 $x =~ s/(\s)/\\$1/g;
26 106         545 $x;
27             } @_;
28             }
29              
30             sub new
31             {
32 16     16 1 9159 my($class, @aliens) = @_;
33              
34 16         37 my $export = 1;
35 16         26 my $writemakefile = 0;
36              
37 16         80 my @cflags_I;
38             my @cflags_other;
39 16         0 my @ldflags_L;
40 16         0 my @ldflags_l;
41 16         0 my @ldflags_other;
42 16         62 my %requires = (
43             'ExtUtils::MakeMaker' => '6.52',
44             'Alien::Base::Wrapper' => '1.97',
45             );
46              
47 16         55 foreach my $alien (@aliens)
48             {
49 13 100       345 if($alien eq '!export')
50             {
51 1         26 $export = 0;
52 1         3 next;
53             }
54 12 100       33 if($alien eq 'WriteMakefile')
55             {
56 1         3 $writemakefile = 1;
57 1         3 next;
58             }
59 11         21 my $version = 0;
60 11 100       52 if($alien =~ s/=(.*)$//)
61             {
62 3         12 $version = $1;
63             }
64 11 100       62 $alien = "Alien::$alien" unless $alien =~ /::/;
65 11         28 $requires{$alien} = $version;
66 11         32 my $alien_pm = $alien . '.pm';
67 11         44 $alien_pm =~ s/::/\//g;
68 11 50 33     26 require $alien_pm unless eval { $alien->can('cflags') } && eval { $alien->can('libs') };
  11         134  
  11         74  
69 11         21 my $cflags;
70             my $libs;
71 11 100 100     75 if($alien->install_type eq 'share' && $alien->can('cflags_static'))
72             {
73 1         22 $cflags = $alien->cflags_static;
74 1         8 $libs = $alien->libs_static;
75             }
76             else
77             {
78 10         106 $cflags = $alien->cflags;
79 10         43 $libs = $alien->libs;
80             }
81              
82 11         65 push @cflags_I, grep /^-I/, shellwords $cflags;
83 11         1204 push @cflags_other, grep !/^-I/, shellwords $cflags;
84              
85 11         699 push @ldflags_L, grep /^-L/, shellwords $libs;
86 11         827 push @ldflags_l, grep /^-l/, shellwords $libs;
87 11         831 push @ldflags_other, grep !/^-[Ll]/, shellwords $libs;
88             }
89              
90 16         560 my @cflags_define = grep /^-D/, @cflags_other;
91 16         44 my @cflags_other2 = grep !/^-D/, @cflags_other;
92              
93 16         28 my @mm;
94              
95 16 100       63 push @mm, INC => _join @cflags_I if @cflags_I;
96 16 50       53 push @mm, CCFLAGS => _join(@cflags_other2) . " $Config{ccflags}" if @cflags_other2;
97 16 100       46 push @mm, DEFINE => _join(@cflags_define) if @cflags_define;
98              
99             # TODO: handle spaces in -L paths
100 16         86 push @mm, LIBS => ["@ldflags_L @ldflags_l"];
101 16         43 my @ldflags = (@ldflags_L, @ldflags_other);
102 16 100       51 push @mm, LDDLFLAGS => _join(@ldflags) . " $Config{lddlflags}" if @ldflags;
103 16 100       57 push @mm, LDFLAGS => _join(@ldflags) . " $Config{ldflags}" if @ldflags;
104              
105 16         27 my @mb;
106              
107 16         45 push @mb, extra_compiler_flags => _join(@cflags_I, @cflags_other);
108 16         39 push @mb, extra_linker_flags => _join(@ldflags_l);
109              
110 16 100       51 if(@ldflags)
111             {
112 6         28 push @mb, config => {
113             lddlflags => _join(@ldflags) . " $Config{lddlflags}",
114             ldflags => _join(@ldflags) . " $Config{ldflags}",
115             },
116             }
117              
118             bless {
119 16         253 cflags_I => \@cflags_I,
120             cflags_other => \@cflags_other,
121             ldflags_L => \@ldflags_L,
122             ldflags_l => \@ldflags_l,
123             ldflags_other => \@ldflags_other,
124             mm => \@mm,
125             mb => \@mb,
126             _export => $export,
127             _writemakefile => $writemakefile,
128             requires => \%requires,
129             }, $class;
130             }
131              
132             my $default_abw = __PACKAGE__->new;
133              
134             # for testing only
135 4     4   23634 sub _reset { __PACKAGE__->new }
136              
137              
138             sub _myexec
139             {
140 0     0   0 my @command = @_;
141 0 0       0 if($^O eq 'MSWin32')
142             {
143             # To handle weird quoting on MSWin32
144             # this logic needs to be improved.
145 0         0 my $command = "@command";
146 0         0 $command =~ s{"}{\\"}g;
147 0         0 system $command;
148              
149 0 0       0 if($? == -1 )
    0          
150             {
151 0         0 die "failed to execute: $!\n";
152             }
153             elsif($? & 127)
154             {
155 0         0 die "child died with signal @{[ $? & 128 ]}";
  0         0  
156             }
157             else
158             {
159 0         0 exit($? >> 8);
160             }
161             }
162             else
163             {
164 0         0 exec @command;
165             }
166             }
167              
168             sub cc
169             {
170             my @command = (
171             shellwords($Config{cc}),
172 4         223 @{ $default_abw->{cflags_I} },
173 4     4 1 1538 @{ $default_abw->{cflags_other} },
  4         17  
174             @ARGV,
175             );
176 4 50       22 print "@command\n" unless $ENV{ALIEN_BASE_WRAPPER_QUIET};
177 4         15 _myexec @command;
178             }
179              
180              
181             sub ld
182             {
183             my @command = (
184             shellwords($Config{ld}),
185 4         395 @{ $default_abw->{ldflags_L} },
186 4         12 @{ $default_abw->{ldflags_other} },
187             @ARGV,
188 4     4 1 8687 @{ $default_abw->{ldflags_l} },
  4         16  
189             );
190 4 50       24 print "@command\n" unless $ENV{ALIEN_BASE_WRAPPER_QUIET};
191 4         15 _myexec @command;
192             }
193              
194              
195             sub mm_args
196             {
197 1 50   1 1 2754 my $self = ref $_[0] ? shift : $default_abw;
198 1         3 @{ $self->{mm} };
  1         15  
199             }
200              
201              
202             sub mm_args2
203             {
204 3     3 1 4715 my $self = shift;
205 3 100       15 $self = $default_abw unless ref $self;
206 3         17 my %args = @_;
207              
208 3         9 my @mm = @{ $self->{mm} };
  3         18  
209              
210 3         12 while(@mm)
211             {
212 15         25 my $key = shift @mm;
213 15         20 my $value = shift @mm;
214 15 100       33 if(defined $args{$key})
215             {
216 3 50       12 if($args{$key} eq 'LIBS')
217             {
218 0         0 require Carp;
219             # Todo: support this maybe?
220 0         0 Carp::croak("please do not specify your own LIBS key with mm_args2");
221             }
222             else
223             {
224 3         16 $args{$key} = join ' ', $value, $args{$key};
225             }
226             }
227             else
228             {
229 12         29 $args{$key} = $value;
230             }
231             }
232              
233 3         7 foreach my $module (keys %{ $self->{requires} })
  3         16  
234             {
235 12         28 $args{CONFIGURE_REQUIRES}->{$module} = $self->{requires}->{$module};
236             }
237              
238 3         22 %args;
239             }
240              
241              
242             sub mb_args
243             {
244 1 50   1 1 6529 my $self = ref $_[0] ? shift : $default_abw;
245 1         2 @{ $self->{mb} };
  1         9  
246             }
247              
248             sub import
249             {
250 6     6   453 shift;
251 6         27 my $abw = $default_abw = __PACKAGE__->new(@_);
252 6 50       26 if($abw->_export)
253             {
254 6         22 my $caller = caller;
255 2     2   22 no strict 'refs';
  2         15  
  2         199  
256 6         13 *{"${caller}::cc"} = \&cc;
  6         44  
257 6         18 *{"${caller}::ld"} = \&ld;
  6         23  
258             }
259 6 100       19 if($abw->_writemakefile)
260             {
261 1         12 my $caller = caller;
262 2     2   15 no strict 'refs';
  2         6  
  2         711  
263 1         4 *{"${caller}::WriteMakefile"} = \&WriteMakefile;
  1         4640  
264             }
265             }
266              
267              
268             sub WriteMakefile
269             {
270 2     2 1 117695 my %args = @_;
271              
272 2         26 require ExtUtils::MakeMaker;
273 2         40 ExtUtils::MakeMaker->VERSION('6.52');
274              
275 2         7 my @aliens;
276              
277 2 50       13 if(my $reqs = delete $args{alien_requires})
278             {
279 2 100       26 if(ref $reqs eq 'HASH')
    50          
280             {
281             @aliens = map {
282 1         10 my $module = $_;
  2         5  
283 2         5 my $version = $reqs->{$module};
284 2 100       13 $version ? "$module=$version" : "$module";
285             } sort keys %$reqs;
286             }
287             elsif(ref $reqs eq 'ARRAY')
288             {
289 1         4 @aliens = @$reqs;
290             }
291             else
292             {
293 0         0 require Carp;
294 0         0 Carp::croak("aliens_require must be either a hash or array reference");
295             }
296             }
297             else
298             {
299 0         0 require Carp;
300 0         0 Carp::croak("You are using Alien::Base::Wrapper::WriteMakefile, but didn't specify any alien requirements");
301             }
302              
303 2         18 ExtUtils::MakeMaker::WriteMakefile(
304             Alien::Base::Wrapper->new(@aliens)->mm_args2(%args),
305             );
306             }
307              
308 8     8   1081 sub _export { shift->{_export} }
309 6     6   55 sub _writemakefile { shift->{_writemakefile} }
310              
311             1;
312              
313             __END__