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   253555 use strict;
  2         15  
  2         65  
4 2     2   12 use warnings;
  2         4  
  2         51  
5 2     2   44 use 5.006;
  2         7  
6 2     2   11 use Config;
  2         3  
  2         107  
7 2     2   519 use Text::ParseWords qw( shellwords );
  2         1521  
  2         3144  
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.45'; # VERSION
18              
19              
20             sub _join
21             {
22             join ' ',
23             map {
24 68     68   133 my $x = $_;
  106         142  
25 106         145 $x =~ s/(\s)/\\$1/g;
26 106         449 $x;
27             } @_;
28             }
29              
30             sub new
31             {
32 16     16 1 12349 my($class, @aliens) = @_;
33              
34 16         29 my $export = 1;
35 16         28 my $writemakefile = 0;
36              
37 16         71 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         50 my %requires = (
43             'ExtUtils::MakeMaker' => '6.52',
44             'Alien::Base::Wrapper' => '1.97',
45             );
46              
47 16         38 foreach my $alien (@aliens)
48             {
49 13 100       318 if($alien eq '!export')
50             {
51 1         25 $export = 0;
52 1         3 next;
53             }
54 12 100       30 if($alien eq 'WriteMakefile')
55             {
56 1         1 $writemakefile = 1;
57 1         4 next;
58             }
59 11         16 my $version = 0;
60 11 100       45 if($alien =~ s/=(.*)$//)
61             {
62 3         10 $version = $1;
63             }
64 11 100       39 $alien = "Alien::$alien" unless $alien =~ /::/;
65 11         26 $requires{$alien} = $version;
66 11         27 my $alien_pm = $alien . '.pm';
67 11         34 $alien_pm =~ s/::/\//g;
68 11 50 33     23 require $alien_pm unless eval { $alien->can('cflags') } && eval { $alien->can('libs') };
  11         130  
  11         91  
69 11         25 my $cflags;
70             my $libs;
71 11 100 100     40 if($alien->install_type eq 'share' && $alien->can('cflags_static'))
72             {
73 1         16 $cflags = $alien->cflags_static;
74 1         7 $libs = $alien->libs_static;
75             }
76             else
77             {
78 10         93 $cflags = $alien->cflags;
79 10         42 $libs = $alien->libs;
80             }
81              
82 11         48 push @cflags_I, grep /^-I/, shellwords $cflags;
83 11         1052 push @cflags_other, grep !/^-I/, shellwords $cflags;
84              
85 11         690 push @ldflags_L, grep /^-L/, shellwords $libs;
86 11         844 push @ldflags_l, grep /^-l/, shellwords $libs;
87 11         797 push @ldflags_other, grep !/^-[Ll]/, shellwords $libs;
88             }
89              
90 16         535 my @cflags_define = grep /^-D/, @cflags_other;
91 16         31 my @cflags_other2 = grep !/^-D/, @cflags_other;
92              
93 16         27 my @mm;
94              
95 16 100       47 push @mm, INC => _join @cflags_I if @cflags_I;
96 16 50       46 push @mm, CCFLAGS => _join(@cflags_other2) . " $Config{ccflags}" if @cflags_other2;
97 16 100       40 push @mm, DEFINE => _join(@cflags_define) if @cflags_define;
98              
99             # TODO: handle spaces in -L paths
100 16         84 push @mm, LIBS => ["@ldflags_L @ldflags_l"];
101 16         37 my @ldflags = (@ldflags_L, @ldflags_other);
102 16 100       44 push @mm, LDDLFLAGS => _join(@ldflags) . " $Config{lddlflags}" if @ldflags;
103 16 100       48 push @mm, LDFLAGS => _join(@ldflags) . " $Config{ldflags}" if @ldflags;
104              
105 16         30 my @mb;
106              
107 16         37 push @mb, extra_compiler_flags => _join(@cflags_I, @cflags_other);
108 16         36 push @mb, extra_linker_flags => _join(@ldflags_l);
109              
110 16 100       42 if(@ldflags)
111             {
112 6         11 push @mb, config => {
113             lddlflags => _join(@ldflags) . " $Config{lddlflags}",
114             ldflags => _join(@ldflags) . " $Config{ldflags}",
115             },
116             }
117              
118             bless {
119 16         211 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   19986 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         214 @{ $default_abw->{cflags_I} },
173 4     4 1 1116 @{ $default_abw->{cflags_other} },
  4         13  
174             @ARGV,
175             );
176 4 50       16 print "@command\n" unless $ENV{ALIEN_BASE_WRAPPER_QUIET};
177 4         11 _myexec @command;
178             }
179              
180              
181             sub ld
182             {
183             my @command = (
184             shellwords($Config{ld}),
185 4         286 @{ $default_abw->{ldflags_L} },
186 4         10 @{ $default_abw->{ldflags_other} },
187             @ARGV,
188 4     4 1 7047 @{ $default_abw->{ldflags_l} },
  4         12  
189             );
190 4 50       17 print "@command\n" unless $ENV{ALIEN_BASE_WRAPPER_QUIET};
191 4         12 _myexec @command;
192             }
193              
194              
195             sub mm_args
196             {
197 1 50   1 1 2183 my $self = ref $_[0] ? shift : $default_abw;
198 1         2 @{ $self->{mm} };
  1         11  
199             }
200              
201              
202             sub mm_args2
203             {
204 3     3 1 4009 my $self = shift;
205 3 100       12 $self = $default_abw unless ref $self;
206 3         12 my %args = @_;
207              
208 3         7 my @mm = @{ $self->{mm} };
  3         13  
209              
210 3         8 while(@mm)
211             {
212 15         27 my $key = shift @mm;
213 15         18 my $value = shift @mm;
214 15 100       31 if(defined $args{$key})
215             {
216 3 50       7 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         14 $args{$key} = join ' ', $value, $args{$key};
225             }
226             }
227             else
228             {
229 12         26 $args{$key} = $value;
230             }
231             }
232              
233 3         6 foreach my $module (keys %{ $self->{requires} })
  3         13  
234             {
235 12         26 $args{CONFIGURE_REQUIRES}->{$module} = $self->{requires}->{$module};
236             }
237              
238 3         20 %args;
239             }
240              
241              
242             sub mb_args
243             {
244 1 50   1 1 5809 my $self = ref $_[0] ? shift : $default_abw;
245 1         3 @{ $self->{mb} };
  1         7  
246             }
247              
248             sub import
249             {
250 6     6   456 shift;
251 6         29 my $abw = $default_abw = __PACKAGE__->new(@_);
252 6 50       20 if($abw->_export)
253             {
254 6         13 my $caller = caller;
255 2     2   22 no strict 'refs';
  2         5  
  2         210  
256 6         14 *{"${caller}::cc"} = \&cc;
  6         29  
257 6         13 *{"${caller}::ld"} = \&ld;
  6         19  
258             }
259 6 100       22 if($abw->_writemakefile)
260             {
261 1         2 my $caller = caller;
262 2     2   16 no strict 'refs';
  2         5  
  2         774  
263 1         3 *{"${caller}::WriteMakefile"} = \&WriteMakefile;
  1         4801  
264             }
265             }
266              
267              
268             sub WriteMakefile
269             {
270 2     2 1 110481 my %args = @_;
271              
272 2         14 require ExtUtils::MakeMaker;
273 2         25 ExtUtils::MakeMaker->VERSION('6.52');
274              
275 2         8 my @aliens;
276              
277 2 50       9 if(my $reqs = delete $args{alien_requires})
278             {
279 2 100       9 if(ref $reqs eq 'HASH')
    50          
280             {
281             @aliens = map {
282 1         9 my $module = $_;
  2         5  
283 2         3 my $version = $reqs->{$module};
284 2 100       10 $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         14 ExtUtils::MakeMaker::WriteMakefile(
304             Alien::Base::Wrapper->new(@aliens)->mm_args2(%args),
305             );
306             }
307              
308 8     8   1036 sub _export { shift->{_export} }
309 6     6   58 sub _writemakefile { shift->{_writemakefile} }
310              
311             1;
312              
313             __END__