File Coverage

blib/lib/ExtUtils/Depends.pm
Criterion Covered Total %
statement 172 215 80.0
branch 21 62 33.8
condition 8 27 29.6
subroutine 32 39 82.0
pod 15 21 71.4
total 248 364 68.1


line stmt bran cond sub pod time code
1             package ExtUtils::Depends;
2              
3 4     4   294419 use strict;
  4         37  
  4         118  
4 4     4   37 use warnings;
  4         8  
  4         120  
5 4     4   20 use Carp;
  4         9  
  4         235  
6 4     4   24 use Config;
  4         9  
  4         151  
7 4     4   21 use File::Find;
  4         16  
  4         186  
8 4     4   22 use File::Spec;
  4         6  
  4         118  
9 4     4   2440 use Data::Dumper;
  4         27387  
  4         2609  
10              
11             our $VERSION = '0.8000';
12              
13             sub import {
14 4     4   40 my $class = shift;
15 4 50       3352 return unless @_;
16 0 0       0 die "$class version $_[0] is required--this is only version $VERSION"
17             if $VERSION < $_[0];
18             }
19              
20             sub new {
21 4     4 1 2506 my ($class, $name, @deps) = @_;
22 4         35 my $self = bless {
23             name => $name,
24             deps => {},
25             inc => [],
26             libs => '',
27              
28             pm => {},
29             typemaps => [],
30             xs => [],
31             c => [],
32             }, $class;
33              
34 4         16 $self->add_deps (@deps);
35              
36             # attempt to load these now, so we'll find out as soon as possible
37             # whether the dependencies are valid. we'll load them again in
38             # get_makefile_vars to catch any added between now and then.
39 4         13 $self->load_deps;
40              
41 4         15 return $self;
42             }
43              
44             sub add_deps {
45 5     5 1 12 my $self = shift;
46 5         11 foreach my $d (@_) {
47             $self->{deps}{$d} = undef
48 2 50       9 unless $self->{deps}{$d};
49             }
50             }
51              
52             sub get_deps {
53 2     2 1 9 my $self = shift;
54 2         6 $self->load_deps; # just in case
55              
56 2         4 return %{$self->{deps}};
  2         11  
57             }
58              
59             sub set_inc {
60 1     1 1 7 my $self = shift;
61 1         1 push @{ $self->{inc} }, @_;
  1         4  
62             }
63              
64             sub set_libs {
65 1     1 1 6 my ($self, $newlibs) = @_;
66 1         3 $self->{libs} = $newlibs;
67             }
68              
69             sub add_pm {
70 7     7 1 29 my ($self, %pm) = @_;
71 7         24 while (my ($key, $value) = each %pm) {
72 8         45 $self->{pm}{$key} = $value;
73             }
74             }
75              
76             sub _listkey_add_list {
77 3     3   8 my ($self, $key, @list) = @_;
78 3 50       8 $self->{$key} = [] unless $self->{$key};
79 3         3 push @{ $self->{$key} }, @list;
  3         11  
80             }
81              
82 1     1 1 10 sub add_xs { shift->_listkey_add_list ('xs', @_) }
83 1     1 1 8 sub add_c { shift->_listkey_add_list ('c', @_) }
84             sub add_typemaps {
85 1     1 1 8 my $self = shift;
86 1         3 $self->_listkey_add_list ('typemaps', @_);
87 1         4 $self->install (@_);
88             }
89              
90             # no-op, only used for source back-compat
91 0     0 1 0 sub add_headers { carp "add_headers() is a no-op" }
92              
93             ####### PRIVATE
94 8     8 0 57 sub basename { (File::Spec->splitdir ($_[0]))[-1] }
95             # get the name in Makefile syntax.
96             sub installed_filename {
97 6     6 0 12 my $self = shift;
98 6         15 return '$(INST_ARCHLIB)/$(FULLEXT)/Install/'.basename ($_[0]);
99             }
100              
101             sub install {
102             # install things by adding them to the hash of pm files that gets
103             # passed through WriteMakefile's PM key.
104 2     2 1 19 my $self = shift;
105 2         6 foreach my $f (@_) {
106 4         11 $self->add_pm ($f, $self->installed_filename ($f));
107             }
108             }
109              
110             sub save_config {
111 4     4   35 use Data::Dumper;
  4         10  
  4         255  
112 2     2 1 22 local $Data::Dumper::Terse = 0;
113 2         6 local $Data::Dumper::Sortkeys = 1;
114 4     4   1860 use IO::File;
  4         11450  
  4         1867  
115              
116 2         6 my ($self, $filename) = @_;
117              
118 2 50       18 my $file = IO::File->new (">".$filename)
119             or croak "can't open '$filename' for writing: $!\n";
120              
121 2         288 print $file "package $self->{name}\::Install::Files;\n\n";
122             print $file "".Data::Dumper->Dump([{
123 2         10 inc => join (" ", @{ $self->{inc} }),
124             libs => $self->{libs},
125 2         14 typemaps => [ map { basename $_ } @{ $self->{typemaps} } ],
  2         8  
126 2         11 deps => [sort keys %{ $self->{deps} }],
  2         25  
127             }], ['self']);
128 2         198 print $file <<'EOF';
129              
130             @deps = @{ $self->{deps} };
131             @typemaps = @{ $self->{typemaps} };
132             $libs = $self->{libs};
133             $inc = $self->{inc};
134             EOF
135             # this is ridiculous, but old versions of ExtUtils::Depends take
136             # first $loadedmodule::CORE and then $INC{$file} --- the fallback
137             # includes the Filename.pm, which is not useful. so we must add
138             # this crappy code. we don't worry about portable pathnames,
139             # as the old code didn't either.
140 2         10 (my $mdir = $self->{name}) =~ s{::}{/}g;
141 2         9 print $file <<"EOT";
142              
143             \$CORE = undef;
144             foreach (\@INC) {
145             if ( -f \$_ . "/$mdir/Install/Files.pm") {
146             \$CORE = \$_ . "/$mdir/Install/";
147             last;
148             }
149             }
150              
151             sub deps { \@{ \$self->{deps} }; }
152              
153             sub Inline {
154             my (\$class, \$lang) = \@_;
155             if (\$lang ne 'C') {
156             warn "Warning: Inline hints not available for \$lang language\n";
157             return;
158             }
159             +{ map { (uc(\$_) => \$self->{\$_}) } qw(inc libs typemaps) };
160             }
161             EOT
162              
163 2         4 print $file "\n1;\n";
164              
165 2         90 close $file;
166              
167             # we need to ensure that the file we just created gets put into
168             # the install dir with everything else.
169             #$self->install ($filename);
170 2         15 $self->add_pm ($filename, $self->installed_filename ('Files.pm'));
171             }
172              
173             sub load {
174 5     5 1 9608 my $dep = shift;
175 5         19 my @pieces = split /::/, $dep;
176 5         14 my @suffix = qw/ Install Files /;
177             # not File::Spec - see perldoc -f require
178 5         19 my $relpath = join('/', @pieces, @suffix) . '.pm';
179 5         12 my $depinstallfiles = join "::", @pieces, @suffix;
180 5 50       8 eval {
181 5         2302 require $relpath
182             } or die " *** Can't load dependency information for $dep:\n $@\n";
183             #print Dumper(\%INC);
184              
185             # effectively $instpath = dirname($INC{$relpath})
186 5         48 @pieces = File::Spec->splitdir ($INC{$relpath});
187 5         10 pop @pieces;
188 5         37 my $instpath = File::Spec->catdir (@pieces);
189              
190 4     4   36 no strict;
  4         9  
  4         6330  
191              
192 5 50       19 croak "No dependency information found for $dep"
193             unless $instpath;
194              
195 5 50       41 if (not File::Spec->file_name_is_absolute ($instpath)) {
196 0         0 $instpath = File::Spec->rel2abs ($instpath);
197             }
198              
199 5         14 my (@typemaps, $inc, $libs, @deps);
200              
201             # this will not exist when loading files from old versions
202             # of ExtUtils::Depends.
203 5         10 @deps = eval { $depinstallfiles->deps };
  5         34  
204 1         5 @deps = @{"$depinstallfiles\::deps"}
205 5 50 66     17 if $@ and exists ${"$depinstallfiles\::"}{deps};
  1         7  
206              
207 5         19 my $inline = eval { $depinstallfiles->Inline('C') };
  5         19  
208 5 100       15 if (!$@) {
209 4   100     16 $inc = $inline->{INC} || '';
210 4   100     17 $libs = $inline->{LIBS} || '';
211 4 100       7 @typemaps = @{ $inline->{TYPEMAPS} || [] };
  4         14  
212             } else {
213 1   50     3 $inc = ${"$depinstallfiles\::inc"} || '';
214 1   50     2 $libs = ${"$depinstallfiles\::libs"} || '';
215 1         2 @typemaps = @{"$depinstallfiles\::typemaps"};
  1         4  
216             }
217 5         11 @typemaps = map { File::Spec->rel2abs ($_, $instpath) } @typemaps;
  2         36  
218              
219             {
220 5         15 instpath => $instpath,
221             typemaps => \@typemaps,
222             inc => "-I". _quote_if_space($instpath) ." $inc",
223             libs => $libs,
224             deps => \@deps,
225             }
226             }
227              
228 5 50   5   54 sub _quote_if_space { $_[0] =~ / / ? qq{"$_[0]"} : $_[0] }
229              
230             sub load_deps {
231 8     8 1 15 my $self = shift;
232 8         12 my @load = grep { not $self->{deps}{$_} } keys %{ $self->{deps} };
  4         13  
  8         34  
233 8         20 foreach my $d (@load) {
234 2         6 my $dep = load ($d);
235 2         5 $self->{deps}{$d} = $dep;
236 2 50       5 if ($dep->{deps}) {
237 2         4 foreach my $childdep (@{ $dep->{deps} }) {
  2         7  
238             push @load, $childdep
239             unless
240             $self->{deps}{$childdep}
241             or
242 0 0 0     0 grep {$_ eq $childdep} @load;
  0         0  
243             }
244             }
245             }
246             }
247              
248             sub uniquify {
249 2     2 0 4 my %seen;
250             # we use a seen hash, but also keep indices to preserve
251             # first-seen order.
252 2         2 my $i = 0;
253 2         5 foreach (@_) {
254             $seen{$_} = ++$i
255 8 50       20 unless exists $seen{$_};
256             }
257             #warn "stripped ".(@_ - (keys %seen))." redundant elements\n";
258 2         9 sort { $seen{$a} <=> $seen{$b} } keys %seen;
  10         28  
259             }
260              
261              
262             sub get_makefile_vars {
263 1     1 1 87 my $self = shift;
264              
265             # collect and uniquify things from the dependencies.
266             # first, ensure they are completely loaded.
267 1         4 $self->load_deps;
268              
269             ##my @defbits = map { split } @{ $self->{defines} };
270 1         2 my @incbits = map { split } @{ $self->{inc} };
  1         8  
  1         3  
271 1         7 my @libsbits = split /\s+/, $self->{libs};
272 1         2 my @typemaps = @{ $self->{typemaps} };
  1         4  
273 1         3 foreach my $d (sort keys %{ $self->{deps} }) {
  1         3  
274 0         0 my $dep = $self->{deps}{$d};
275             #push @defbits, @{ $dep->{defines} };
276 0 0       0 push @incbits, @{ $dep->{defines} } if $dep->{defines};
  0         0  
277 0 0       0 push @incbits, split /\s+/, $dep->{inc} if $dep->{inc};
278 0 0       0 push @libsbits, split /\s+/, $dep->{libs} if $dep->{libs};
279 0 0       0 push @typemaps, @{ $dep->{typemaps} } if $dep->{typemaps};
  0         0  
280             }
281              
282             # we have a fair bit of work to do for the xs files...
283 1         3 my @clean = ();
284 1         2 my @OBJECT = ();
285 1         2 my %XS = ();
286 1         2 foreach my $xs (@{ $self->{xs} }) {
  1         3  
287 2         9 (my $c = $xs) =~ s/\.xs$/\.c/i;
288 2         7 (my $o = $xs) =~ s/\.xs$/\$(OBJ_EXT)/i;
289 2         6 $XS{$xs} = $c;
290 2         4 push @OBJECT, $o;
291             # according to the MakeMaker manpage, the C files listed in
292             # XS will be added automatically to the list of cleanfiles.
293 2         4 push @clean, $o;
294             }
295              
296             # we may have C files, as well:
297 1         2 foreach my $c (@{ $self->{c} }) {
  1         3  
298 2         7 (my $o = $c) =~ s/\.c$/\$(OBJ_EXT)/i;
299 2         4 push @OBJECT, $o;
300 2         4 push @clean, $o;
301             }
302              
303 1         7 my %vars = (
304             INC => join (' ', uniquify @incbits),
305             LIBS => join (' ', uniquify $self->find_extra_libs, @libsbits),
306             TYPEMAPS => [@typemaps],
307             );
308              
309 1 50       7 $self->build_dll_lib(\%vars) if $^O =~ /MSWin32/;
310              
311             # we don't want to provide these if there is no data in them;
312             # that way, the caller can still get default behavior out of
313             # MakeMaker when INC, LIBS and TYPEMAPS are all that are required.
314             $vars{PM} = $self->{pm}
315 1 50       4 if %{ $self->{pm} };
  1         6  
316 1 50       6 $vars{clean} = { FILES => join (" ", @clean), }
317             if @clean;
318 1 50       5 $vars{OBJECT} = join (" ", @OBJECT)
319             if @OBJECT;
320 1 50       4 $vars{XS} = \%XS
321             if %XS;
322              
323 1         24 %vars;
324             }
325              
326             sub build_dll_lib {
327 0     0 0 0 my ($self, $vars) = @_;
328 0   0     0 $vars->{macro} ||= {};
329 0         0 $vars->{macro}{'INST_DYNAMIC_LIB'} =
330             '$(INST_ARCHAUTODIR)/$(DLBASE)$(LIB_EXT)';
331             }
332              
333             # Search for extra library files to link against on Windows (either native
334             # Windows library # files, or Cygwin library files)
335             # NOTE: not meant to be called publicly, so no POD documentation
336             sub find_extra_libs {
337 1     1 0 2 my $self = shift;
338              
339             my %mappers = (
340 0     0   0 MSWin32 => sub { $_[0] . '\.(?:lib|a)' },
341 0     0   0 cygwin => sub { $_[0] . '\.dll'},
342 0     0   0 android => sub { $_[0] . '\.' . $Config{dlext} },
343 1         10 );
344 1         3 my $mapper = $mappers{$^O};
345 1 50       9 return () unless defined $mapper;
346              
347 0           my @found_libs = ();
348 0           foreach my $name (keys %{ $self->{deps} }) {
  0            
349 0           (my $stem = $name) =~ s/^.*:://;
350 0 0         if ( defined &DynaLoader::mod2fname ) {
351 0           my @parts = split /::/, $name;
352 0           $stem = DynaLoader::mod2fname([@parts]);
353             }
354 0           my $lib = $mapper->($stem);
355 0           my $pattern = qr/$lib$/;
356              
357 0           my $matching_dir;
358             my $matching_file;
359             find (sub {
360 0 0 0 0     if ((not $matching_file) && /$pattern/) {;
361 0           $matching_dir = $File::Find::dir;
362 0           $matching_file = $File::Find::name;
363             }
364 0 0         }, map { -d $_ ? ($_) : () } @INC); # only extant dirs
  0            
365              
366 0 0 0       if ($matching_file && -f $matching_file) {
367 0           push @found_libs,
368             '-L' . _quote_if_space($matching_dir),
369             '-l' . $stem;
370             # Android's linker ignores the RTLD_GLOBAL flag
371             # and loads everything as if under RTLD_LOCAL.
372             # What this means in practice is that modules need
373             # to explicitly link to their dependencies,
374             # because otherwise they won't be able to locate any
375             # functions they define.
376             # We use the -l:foo.so flag to indicate that the
377             # actual library name to look for is foo.so, not
378             # libfoo.so
379 0 0         if ( $^O eq 'android' ) {
380 0           $found_libs[-1] = "-l:$stem.$Config{dlext}";
381             }
382 0           next;
383             }
384             }
385              
386 0           return @found_libs;
387             }
388              
389             # Hook into ExtUtils::MakeMaker to create an import library on MSWin32 when gcc
390             # is used. FIXME: Ideally, this should be done in EU::MM itself.
391             package # wrap to fool the CPAN indexer
392             ExtUtils::MM;
393 4     4   34 use Config;
  4         16  
  4         655  
394             sub static_lib {
395 0     0 0   my $base = shift->SUPER::static_lib(@_);
396              
397 0 0 0       return $base unless $^O =~ /MSWin32/ && $Config{cc} =~ /\bgcc\b/i;
398              
399 0   0       my $DLLTOOL = $Config{'dlltool'} || 'dlltool';
400              
401             return <<"__EOM__"
402             # This isn't actually a static lib, it just has the same name on Win32.
403             \$(INST_DYNAMIC_LIB): \$(INST_DYNAMIC)
404             $DLLTOOL --def \$(EXPORT_LIST) --output-lib \$\@ --dllname \$(DLBASE).\$(DLEXT) \$(INST_DYNAMIC)
405              
406             dynamic:: \$(INST_DYNAMIC_LIB)
407             __EOM__
408 0           }
409              
410             1;
411              
412             __END__