File Coverage

blib/lib/Panda/Install.pm
Criterion Covered Total %
statement 283 404 70.0
branch 83 184 45.1
condition 60 145 41.3
subroutine 31 36 86.1
pod 0 15 0.0
total 457 784 58.2


line stmt bran cond sub pod time code
1             package Panda::Install;
2 12     12   739433 use strict;
  12         104  
  12         285  
3 12     12   53 use warnings;
  12         17  
  12         245  
4 12     12   46 use Config;
  12         17  
  12         379  
5 12     12   48 use Cwd 'abs_path';
  12         19  
  12         515  
6 12     12   65 use Exporter 'import';
  12         18  
  12         287  
7 12     12   3985 use Panda::Install::Payload;
  12         28  
  12         36773  
8              
9             our $VERSION = '1.2.17';
10              
11             our @EXPORT_OK = qw/write_makefile makemaker_args/;
12             our @EXPORT;
13              
14             if ($0 =~ /Makefile.PL$/) {
15             @EXPORT = qw/write_makefile makemaker_args/;
16             _require_makemaker();
17             }
18              
19             my $xs_mask = '*.xs';
20             my $xsi_mask = '*.xsi';
21             my $c_mask = '*.c *.cc *.cpp *.cxx';
22             my $h_mask = '*.h *.hh *.hpp *.hxx';
23             my $map_mask = '*.map';
24             my $win32 = $^O eq 'MSWin32';
25              
26             sub write_makefile {
27 0     0 0 0 _require_makemaker();
28 0         0 WriteMakefile(makemaker_args(@_));
29             }
30              
31             sub makemaker_args {
32 34     34 0 88416 my %params = @_;
33 34         101 _sync();
34            
35 34   50     186 $params{MIN_PERL_VERSION} ||= '5.10.0';
36            
37 34         53 my $postamble = $params{postamble};
38 34 50 33     88 $postamble = {my => $postamble} if $postamble and !ref($postamble);
39 34   50     182 $postamble ||= {};
40 34 50       110 $postamble->{my} = '' unless defined $postamble->{my};
41 34         56 $params{postamble} = $postamble;
42            
43 34         117 _string_merge($params{CCFLAGS}, '-o $@');
44              
45 34 50       94 die "You must define a NAME param" unless $params{NAME};
46 34 50 66     174 unless ($params{ALL_FROM} || $params{VERSION_FROM} || $params{ABSTRACT_FROM}) {
      33        
47 33         53 my $name = $params{NAME};
48 33         83 $name =~ s#::#/#g;
49 33         91 $params{ALL_FROM} = "lib/$name.pm";
50             }
51            
52 34 50       84 if (my $package_file = delete $params{ALL_FROM}) {
53 34         59 $params{VERSION_FROM} = $package_file;
54 34         47 $params{ABSTRACT_FROM} = $package_file;
55             }
56              
57 34   50     131 $params{CONFIGURE_REQUIRES} ||= {};
58 34   50     133 $params{CONFIGURE_REQUIRES}{'ExtUtils::MakeMaker'} ||= '6.76';
59 34   33     124 $params{CONFIGURE_REQUIRES}{'Panda::Install'} ||= $VERSION;
60            
61 34   50     129 $params{BUILD_REQUIRES} ||= {};
62 34   50     123 $params{BUILD_REQUIRES}{'ExtUtils::MakeMaker'} ||= '6.76';
63 34   50     123 $params{BUILD_REQUIRES}{'ExtUtils::ParseXS'} ||= '3.24';
64            
65 34   50     123 $params{TEST_REQUIRES} ||= {};
66 34   50     129 $params{TEST_REQUIRES}{'Test::Simple'} ||= '0.96';
67 34   50     123 $params{TEST_REQUIRES}{'Test::More'} ||= 0;
68 34   50     150 $params{TEST_REQUIRES}{'Test::Deep'} ||= 0;
69            
70 34   50     117 $params{PREREQ_PM} ||= {};
71 34   33     145 $params{PREREQ_PM}{'Panda::Install'} ||= $VERSION; # needed at runtime because it has payload_dir and xsloader
72            
73 34   50     125 $params{clean} ||= {};
74 34   50     129 $params{clean}{FILES} ||= '';
75            
76 34 50 66     84 delete $params{BIN_SHARE} if $params{BIN_SHARE} and !%{$params{BIN_SHARE}};
  1         4  
77            
78             {
79 34         49 my $val = $params{SRC};
80 34 100 100     101 $val = [$val] if $val and ref($val) ne 'ARRAY';
81 34         86 $params{SRC} = $val;
82             }
83             {
84 34         38 my $val = $params{XS};
  34         51  
  34         48  
85 34 100 100     97 $val = [$val] if $val and ref($val) ne 'ARRAY' and ref($val) ne 'HASH';
      100        
86 34         57 $params{XS} = $val;
87             }
88            
89 34 50 33     91 $params{TYPEMAPS} = [$params{TYPEMAPS}] if $params{TYPEMAPS} and ref($params{TYPEMAPS}) ne 'ARRAY';
90            
91 34   50     113 my $module_info = Panda::Install::Payload::module_info($params{NAME}) || {};
92 34         111 $params{MODULE_INFO} = {BIN_DEPENDENT => $module_info->{BIN_DEPENDENT}};
93            
94 34         115 process_XS(\%params);
95 34         93 process_PM(\%params);
96 34         128 process_C(\%params);
97 34         89 process_OBJECT(\%params);
98 34         85 process_H(\%params);
99 34         95 process_XSI(\%params);
100 34         109 process_CLIB(\%params);
101 34         85 process_PAYLOAD(\%params);
102 34         100 process_BIN_DEPS(\%params);
103 34         95 process_BIN_SHARE(\%params);
104 34         113 attach_BIN_DEPENDENT(\%params);
105 34         96 warn_BIN_DEPENDENT(\%params);
106              
107 34 100       78 if (my $use_cpp = delete $params{CPLUS}) {
108 3   100     12 $params{CC} ||= 'c++';
109 3   50     11 $params{LD} ||= '$(CC)';
110 3         10 _string_merge($params{XSOPT}, '-C++');
111            
112 3         6 my $cppv = int($use_cpp);
113 3 100       14 _string_merge($params{CCFLAGS}, "-std=c++$cppv") if $cppv > 1;
114             }
115            
116             # inject Panda::Install::ParseXS into xsubpp
117 34         74 $postamble->{xsubpprun} = 'XSUBPPRUN = $(PERLRUN) -MPanda::Install::ParseXS $(XSUBPP)';
118 34   50     144 $params{LDFROM} ||= '$(OBJECT)';
119            
120 34         106 delete $params{$_} for qw/SRC/;
121 34 50       66 $params{OBJECT} = '$(O_FILES)' unless defined $params{OBJECT};
122            
123 34 50 33     110 if (my $shared_libs = $params{MODULE_INFO}{SHARED_LIBS} and $^O ne 'darwin') { # MacOSX doesn't allow for linking with bundles :(
124 0         0 my %seen;
125 0         0 @$shared_libs = grep {!$seen{$_}++} reverse @$shared_libs;
  0         0  
126 0 0       0 $params{LDFROM} .= ' '.join(' ', @$shared_libs) if @$shared_libs;
127             }
128            
129 34         71 delete $params{MODULE_INFO};
130              
131 34         759 $params{CCFLAGS} = "$Config{ccflags} $params{CCFLAGS}";
132              
133 34 50 66     134 if (!$params{C} || !@{$params{C}} and !$params{OBJECT} || !@{$params{OBJECT}} and !$params{XS} || !scalar(keys %{$params{XS}})) {
  34   33     117  
  1   66     5  
  1   33     4  
      33        
134 1         4 delete $params{$_} for qw/C H OBJECT XS CCFLAGS LDFROM/;
135             }
136            
137 34         457 return %params;
138             }
139              
140             sub process_PM {
141 34     34 0 58 my $params = shift;
142 34 50       96 return if $params->{PM}; # user-defined value overrides defaults
143            
144 34         74 my $instroot = _instroot($params);
145 34         113 my @name_parts = split '::', $params->{NAME};
146 34   50     208 $params->{PMLIBDIRS} ||= ['lib', $name_parts[-1]];
147 34         77 my $pm = $params->{PM} = {};
148            
149 34         50 foreach my $dir (@{$params->{PMLIBDIRS}}) {
  34         74  
150 68 100       754 next unless -d $dir;
151 34         108 foreach my $file (_scan_files('*.pm *.pl', $dir)) {
152 68         111 my $rel = $file;
153 68         339 $rel =~ s/^$dir//;
154 68         183 my $instpath = "$instroot/$rel";
155 68         228 $instpath =~ s#[/\\]{2,}#/#g;
156 68         198 $pm->{$file} = $instpath;
157             }
158             }
159             }
160              
161             sub process_XS {
162 34     34 0 50 my $params = shift;
163 34         54 my ($xs_files, @xs_list);
164 34 100       88 if ($params->{XS}) {
165 6 100       19 if (ref($params->{XS}) eq 'HASH') {
166 2         4 $xs_files = $params->{XS};
167             } else {
168 4         7 push @xs_list, @{_string_split_array($_)} for @{$params->{XS}};
  4         9  
  6         11  
169             }
170             } else {
171 28         69 @xs_list = _scan_files($xs_mask);
172             }
173 34         66 push @xs_list, _scan_files($xs_mask, $_) for @{$params->{SRC}};
  34         119  
174 34   100     158 $params->{XS} = $xs_files ||= {};
175 34         77 foreach my $xsfile (@xs_list) {
176 94 100       193 next if $xs_files->{$xsfile};
177 93         120 my $cfile = $xsfile;
178 93 50       351 $cfile =~ s/\.xs$/.c/ or next;
179 93         245 $xs_files->{$xsfile} = $cfile;
180             }
181             }
182              
183             sub process_C {
184 34     34 0 55 my $params = shift;
185 34 100       107 my $c_files = $params->{C} ? _string_split_array(delete $params->{C}) : [_scan_files($c_mask)];
186 34         84 push @$c_files, grep { !_includes($c_files, $_) } values %{$params->{XS}};
  94         153  
  34         112  
187 34         61 push @$c_files, grep { !_includes($c_files, $_) } _scan_files($c_mask, $_) for @{$params->{SRC}};
  34         66  
  7         14  
188 34         72 $params->{C} = $c_files;
189             }
190              
191             sub process_OBJECT {
192 34     34 0 51 my $params = shift;
193 34         77 my $o_files = _string_split_array(delete $params->{OBJECT});
194 34         57 foreach my $c_file (@{$params->{C}}) {
  34         83  
195 224         250 my $o_file = $c_file;
196 224         605 $o_file =~ s/\.[^.]+$//;
197 224         463 push @$o_files, $o_file.'$(OBJ_EXT)';
198             }
199 34         65 $params->{OBJECT} = $o_files;
200 34         98 $params->{clean}{FILES} .= ' $(O_FILES)';
201             }
202              
203             sub process_H {
204 34     34 0 45 my $params = shift;
205 34 100       96 my $h_files = $params->{H} ? _string_split_array(delete $params->{H}) : [_scan_files($h_mask)];
206 34         76 push @$h_files, _scan_files($h_mask, $_) for @{$params->{SRC}};
  34         91  
207 34         64 $params->{H} = $h_files;
208             }
209              
210             sub process_XSI { # make XS files rebuild if an XSI file changes
211 34     34 0 47 my $params = shift;
212 34         1285 my @xsi_files = glob($xsi_mask);
213 34         88 push @xsi_files, _scan_files($xsi_mask, $_) for @{$params->{SRC}};
  34         92  
214 34 50       111 $params->{postamble}{xsi} = '$(XS_FILES):: '.join(' ', @xsi_files).'; $(TOUCH) $(XS_FILES)'."\n" if @xsi_files;
215             }
216              
217             sub process_CLIB {
218 34     34 0 50 my $params = shift;
219 34         52 my $clibs = '';
220 34 50       106 my $clib = delete $params->{CLIB} or return;
221 0 0       0 $clib = [$clib] unless ref($clib) eq 'ARRAY';
222 0 0       0 return unless @$clib;
223            
224 0         0 foreach my $info (@$clib) {
225 0         0 my $build_cmd = $info->{BUILD_CMD};
226 0         0 my $clean_cmd = $info->{CLEAN_CMD};
227            
228 0 0       0 unless ($build_cmd) {
229 0         0 my $make = '$(MAKE)';
230 0 0 0     0 $make = 'gmake' if $info->{GMAKE} and $^O eq 'freebsd';
231 0   0     0 $info->{TARGET} ||= '';
232 0   0     0 $info->{FLAGS} ||= '';
233 0         0 $build_cmd = "$make $info->{FLAGS} $info->{TARGET}";
234 0         0 $clean_cmd = "$make clean";
235             }
236            
237 0         0 my $path = $info->{DIR}.'/'.$info->{FILE};
238 0         0 $clibs .= "$path ";
239            
240 0         0 $params->{postamble}{clib_build} .= "$path : ; cd $info->{DIR} && $build_cmd\n";
241 0 0       0 $params->{postamble}{clib_clean} .= "clean :: ; cd $info->{DIR} && $clean_cmd\n" if $clean_cmd;
242 0         0 push @{$params->{OBJECT}}, $path;
  0         0  
243             }
244 0         0 $params->{postamble}{clib_ldep} = "linkext:: $clibs";
245             }
246              
247             sub process_PAYLOAD {
248 34     34 0 47 my $params = shift;
249 34 100       86 my $payload = delete $params->{PAYLOAD} or return;
250 10         24 _process_map($payload, '*');
251 10         20 _install($params, $payload, 'payload');
252             }
253              
254             sub process_BIN_DEPS {
255 34     34 0 47 my $params = shift;
256 34 50       90 my $bin_deps = delete $params->{BIN_DEPS} or return;
257 0 0       0 $bin_deps = [$bin_deps] unless ref($bin_deps) eq 'ARRAY';
258 0   0     0 my $typemaps = $params->{TYPEMAPS} ||= [];
259 0         0 $params->{TYPEMAPS} = [];
260 0         0 _apply_BIN_DEPS($params, $_, {}) for @$bin_deps;
261 0         0 push @{$params->{TYPEMAPS}}, @{$typemaps};
  0         0  
  0         0  
262             }
263              
264             sub _apply_BIN_DEPS {
265 0     0   0 my ($params, $module, $seen) = @_;
266 0         0 my $stop_sharing;
267 0 0       0 $stop_sharing = 1 if $module =~ s/^-//;
268            
269 0 0       0 return if $seen->{$module}++;
270            
271 0         0 my $installed_version = Panda::Install::Payload::module_version($module);
272 0   0     0 $params->{CONFIGURE_REQUIRES}{$module} ||= $installed_version;
273 0   0     0 $params->{PREREQ_PM}{$module} ||= $installed_version;
274 0         0 $params->{MODULE_INFO}{BIN_DEPS}{$module} = $installed_version;
275            
276             # add so/dll to linker list
277 0   0     0 my $shared_list = $params->{MODULE_INFO}{SHARED_LIBS} ||= [];
278 0         0 my $module_path = $module;
279 0         0 $module_path =~ s#::#/#g;
280 0 0       0 die "SHOULDN'T EVER HAPPEN" unless $module =~ /([^:]+)$/;
281 0         0 my $module_last_name = $1;
282 0         0 foreach my $dir (@INC) {
283 0         0 my $lib_path = "$dir/auto/$module_path/$module_last_name.$Config{dlext}";
284 0 0       0 next unless -f $lib_path;
285 0         0 push @$shared_list, abs_path($lib_path);
286 0         0 last;
287             }
288            
289 0         0 my $info = Panda::Install::Payload::module_info($module);
290            
291 0 0       0 if ($info->{INCLUDE}) {
292 0         0 my $incdir = Panda::Install::Payload::include_dir($module);
293 0         0 _string_merge($params->{INC}, "-I$incdir");
294             }
295            
296 0         0 _string_merge($params->{INC}, $info->{INC});
297 0         0 _string_merge($params->{CCFLAGS}, $info->{CCFLAGS});
298 0         0 _string_merge($params->{DEFINE}, $info->{DEFINE});
299 0         0 _string_merge($params->{XSOPT}, $info->{XSOPT});
300            
301 0 0       0 if (my $add_libs = $info->{LIBS}) {{
302 0 0       0 last unless @$add_libs;
  0         0  
303 0 0       0 my $libs = $params->{LIBS} or last;
304 0 0       0 $libs = [$libs] unless ref($libs) eq 'ARRAY';
305 0 0 0     0 if ($libs and @$libs) {
306 0         0 my @result;
307 0         0 foreach my $l1 (@$libs) {
308 0         0 foreach my $l2 (@$add_libs) {
309 0         0 push @result, "$l1 $l2";
310             }
311             }
312 0         0 $params->{LIBS} = \@result;
313             }
314             else {
315 0         0 $params->{LIBS} = $add_libs;
316             }
317             }}
318            
319 0 0       0 if (my $passthrough = $info->{PASSTHROUGH}) {
320 0         0 _apply_BIN_DEPS($params, $_, $seen) for @$passthrough;
321             }
322            
323 0 0       0 if (my $typemaps = $info->{TYPEMAPS}) {
324 0         0 my $tm_dir = Panda::Install::Payload::typemap_dir($module);
325 0         0 foreach my $typemap (@$typemaps) {
326 0         0 my $tmfile = "$tm_dir/$typemap";
327 0         0 $tmfile =~ s#[/\\]{2,}#/#g;
328 0   0     0 push @{$params->{TYPEMAPS} ||= []}, $tmfile;
  0         0  
329             }
330             }
331            
332 0 0 0     0 $params->{CPLUS} = $info->{CPLUS} if $info->{CPLUS} and (!$params->{CPLUS} or $params->{CPLUS} < $info->{CPLUS});
      0        
333            
334 0 0 0     0 if (my $bin_share = $params->{BIN_SHARE} and !$stop_sharing) {
335 0   0     0 push @{$bin_share->{PASSTHROUGH} ||= []}, $module;
  0         0  
336             }
337             }
338              
339             sub process_BIN_SHARE {
340 34     34 0 46 my $params = shift;
341 34 100       89 my $bin_share = delete $params->{BIN_SHARE} or return;
342            
343 1   50     4 my $typemaps = delete($bin_share->{TYPEMAPS}) || {};
344 1         3 _process_map($typemaps, $map_mask);
345 1         5 _install($params, $typemaps, 'tm');
346 1 50       5 $bin_share->{TYPEMAPS} = [values %$typemaps] if scalar keys %$typemaps;
347            
348 1   50     4 my $include = delete($bin_share->{INCLUDE}) || {};
349 1         3 _process_map($include, $h_mask);
350 1         3 _install($params, $include, 'i');
351 1 50       4 $bin_share->{INCLUDE} = 1 if scalar(keys %$include);
352            
353 1 50 33     6 $bin_share->{LIBS} = [$bin_share->{LIBS}] if $bin_share->{LIBS} and ref($bin_share->{LIBS}) ne 'ARRAY';
354 1 50 33     4 $bin_share->{PASSTHROUGH} = [$bin_share->{PASSTHROUGH}] if $bin_share->{PASSTHROUGH} and ref($bin_share->{PASSTHROUGH}) ne 'ARRAY';
355            
356 1 50       3 if (my $list = $params->{MODULE_INFO}{BIN_DEPENDENT}) {
357 0 0       0 $bin_share->{BIN_DEPENDENT} = $list if @$list;
358             }
359            
360 1 50       12 if (my $vinfo = $params->{MODULE_INFO}{BIN_DEPS}) {
361 0 0       0 $bin_share->{BIN_DEPS} = $vinfo if %$vinfo;
362             }
363            
364 1 50       3 return unless %$bin_share;
365            
366             # generate info file
367 1         89 mkdir 'blib';
368 1         4 my $infopath = 'blib/info';
369 1         4 _module_info_write($infopath, $bin_share);
370            
371 1   50     5 my $pm = $params->{PM} ||= {};
372 1         3 $pm->{$infopath} = '$(INST_ARCHLIB)/$(FULLEXT).x/info';
373             }
374              
375             sub attach_BIN_DEPENDENT {
376 34     34 0 52 my $params = shift;
377 34 50       66 my @deps = keys %{$params->{MODULE_INFO}{BIN_DEPS} || {}};
  34         582  
378 34 50       113 return unless @deps;
379            
380             $params->{postamble}{sync_bin_deps} =
381 0         0 "sync_bin_deps:\n".
382             "\t\$(PERL) -MPanda::Install -e 'Panda::Install::cmd_sync_bin_deps()' $params->{NAME} @deps\n".
383             "install :: sync_bin_deps";
384             }
385              
386             sub warn_BIN_DEPENDENT {
387 34     34 0 44 my $params = shift;
388 34 50       74 return unless $params->{VERSION_FROM};
389 34         54 my $module = $params->{NAME};
390 34 50       76 my $list = $params->{MODULE_INFO}{BIN_DEPENDENT} or return;
391 0 0       0 return unless @$list;
392 0 0       0 my $installed_version = Panda::Install::Payload::module_version($module) or return;
393 0         0 my $mm = bless {}, 'MM';
394 0 0       0 my $new_version = $mm->parse_version($params->{VERSION_FROM}) or return;
395 0 0       0 return if $installed_version eq $new_version;
396 0         0 warn << "EOF";
397             ******************************************************************************
398             Panda::Install: There are XS modules that binary depend on current XS module $module.
399             They were built with currently installed $module version $installed_version.
400             If you install $module version $new_version, you will have to reinstall all XS modules that binary depend on it:
401             cpanm -f @$list
402             ******************************************************************************
403             EOF
404             }
405              
406             sub cmd_sync_bin_deps {
407 0     0 0 0 my $myself = shift @ARGV;
408 0         0 my @modules = @ARGV;
409 0         0 foreach my $module (@modules) {
410 0 0       0 my $info = Panda::Install::Payload::module_info($module) or next;
411 0   0     0 my $dependent = $info->{BIN_DEPENDENT} || [];
412 0         0 my %tmp = map {$_ => 1} grep {$_ ne $module} @$dependent;
  0         0  
  0         0  
413 0         0 $tmp{$myself} = 1;
414 0         0 $info->{BIN_DEPENDENT} = [sort keys %tmp];
415 0 0       0 delete $info->{BIN_DEPENDENT} unless @{$info->{BIN_DEPENDENT}};
  0         0  
416 0         0 my $file = Panda::Install::Payload::module_info_file($module);
417 0         0 _module_info_write($file, $info);
418             }
419             }
420              
421             sub _install {
422 12     12   26 my ($params, $map, $path) = @_;
423 12 50       30 return unless %$map;
424 12         18 my $xs = $params->{XS};
425 12         31 my $instroot = _instroot($params);
426 12   50     32 my $pm = $params->{PM} ||= {};
427 12         40 while (my ($source, $dest) = each %$map) {
428 29         61 my $instpath = "$instroot/\$(FULLEXT).x/$path/$dest";
429 29         56 $instpath =~ s#[/\\]{2,}#/#g;
430 29         82 $pm->{$source} = $instpath;
431             }
432             }
433              
434             sub _instroot {
435 46     46   61 my $params = shift;
436 46         82 my $xs = $params->{XS};
437 46 100 66     193 my $instroot = ($xs and %$xs) ? '$(INST_ARCHLIB)' : '$(INST_LIB)';
438 46         84 return $instroot;
439             }
440              
441             sub _sync {
442 12     12   94 no strict 'refs';
  12         21  
  12         9529  
443 34     34   67 my $from = 'MYSOURCE';
444 34         52 my $to = 'MY';
445 34         49 foreach my $method (keys %{"${from}::"}) {
  34         147  
446 34 50       51 next unless defined &{"${from}::$method"};
  34         124  
447 34         47 *{"${to}::$method"} = \&{"${from}::$method"};
  34         153  
  34         103  
448             }
449             }
450              
451             sub _scan_files {
452 188     188   362 my ($mask, $dir) = @_;
453 188 100       11864 return grep {_is_file_ok($_)} glob($mask) unless $dir;
  321         618  
454            
455 98         296 my @list = grep {_is_file_ok($_)} glob(join(' ', map {"$dir/$_"} split(' ', $mask)));
  106         298  
  202         6998  
456            
457 98 50       1983 opendir(my $dh, $dir) or die "Could not open dir '$dir' for scanning: $!";
458 98         1125 while (my $entry = readdir $dh) {
459 416 100       1473 next if $entry =~ /^\./;
460 220         385 my $path = "$dir/$entry";
461 220 100       2390 next unless -d $path;
462 37         355 push @list, _scan_files($mask, $path);
463             }
464 98         752 closedir $dh;
465            
466 98         553 return @list;
467             }
468              
469             sub _is_file_ok {
470 427     427   575 my $file = shift;
471 427 100       3553 return unless -f $file;
472 424 50       1101 return if $file =~ /\#/;
473 424 50       609 return if $file =~ /~$/; # emacs temp files
474 424 50       622 return if $file =~ /,v$/; # RCS files
475 424 50       602 return if $file =~ m{\.swp$}; # vim swap files
476 424         1230 return 1;
477             }
478              
479             sub _process_map {
480 12     12   21 my ($map, $mask) = @_;
481 12         33 foreach my $source (keys %$map) {
482 18   66     46 my $dest = $map->{$source} || $source;
483 18 100       199 if (-f $source) {
484 11 100       80 $dest .= $source if $dest =~ m#[/\\]$#;
485 11         26 $dest =~ s#[/\\]{2,}#/#g;
486 11         24 $dest =~ s#^[/\\]+##;
487 11         22 $map->{$source} = $dest;
488 11         22 next;
489             }
490 7 50       68 next unless -d $source;
491            
492 7         16 delete $map->{$source};
493 7         15 my @files = _scan_files($mask, $source);
494 7         14 foreach my $file (@files) {
495 18         24 my $dest_file = $file;
496 18         107 $dest_file =~ s/^$source//;
497 18         33 $dest_file = "$dest/$dest_file";
498 18         51 $dest_file =~ s#[/\\]{2,}#/#g;
499 18         50 $dest_file =~ s#^[/\\]+##;
500 18         48 $map->{$file} = $dest_file;
501             }
502             }
503             }
504              
505             sub _includes {
506 101     101   154 my ($arr, $val) = @_;
507 101 50       147 for (@$arr) { return 1 if $_ eq $val }
  396         565  
508 101         231 return;
509             }
510              
511             sub _string_split_array {
512 46     46   71 my $list = shift;
513 46         52 my @result;
514 46 100       86 if ($list) {
515 12 100       35 $list = [$list] unless ref($list) eq 'ARRAY';
516 12         34 push @result, map { glob } split(' ') for @$list;
  12         348  
517             }
518 46         122 return \@result;
519             }
520              
521             sub _string_merge {
522 38 50   38   82 return unless $_[1];
523 38   100     198 $_[0] ||= '';
524 38 100       121 $_[0] .= $_[0] ? " $_[1]" : $_[1];
525             }
526              
527             {
528             package
529             MYSOURCE;
530            
531             sub postamble {
532 0     0   0 my $self = shift;
533 0         0 my %args = @_;
534              
535 0         0 $args{'.xs.cc'} = '
536             .xs.cc:
537             $(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $(XSUBPP_EXTRA_ARGS) $*.xs > $*.xsc
538             $(MV) $*.xsc $*.cc
539             ';
540              
541 0         0 return join("\n", values %args);
542             }
543             }
544              
545             {
546             package
547             MY;
548 12     12   91 use Config;
  12         28  
  12         6990  
549              
550             if ($win32) {
551             my $gcc_compliant = $Config{cc} =~ /\b(gcc|clang)\b/i ? 1 : 0;
552            
553             *dynamic_lib = sub {
554             my ($self, %attribs) = @_;
555             my $code = $self->SUPER::dynamic_lib(%attribs);
556            
557             unless ($gcc_compliant) {
558             warn(
559             "Panda::Install: to maintain UNIX-like shared library behaviour on windows (export all symbols by default), we need gcc-compliant linker. ".
560             "Panda::Install-dependant modules should only be installed on perls with MinGW shell (like strawberry perl), or at least having gcc compiler. ".
561             "I will continue, but this module's binary dependencies may not work."
562             );
563             return $code;
564             }
565             return $code unless $code;
566            
567             # remove .def-related from code, remove double DLL build, remove dll.exp from params, add export all symbols param.
568             my $DLLTOOL = $Config{dlltool} || 'dlltool';
569             my (@out, $last_ld);
570             map { $last_ld = $_ if /\$\(LD\)\s/ } split /\n/, $code;
571             foreach my $line (split /\n/, $code) {
572             next if $line =~ /$DLLTOOL/; # drop dlltool calls (we dont need .def file)
573             if ($line =~ /\$\(LD\)\s/) {
574             next if $line ne $last_ld;
575             $line =~ s/\$\(LD\)\s/\$(LD) -Wl,--export-all-symbols /;
576             $line =~ s/\bdll\.exp\b//;
577             }
578             $line =~ s/\$\(EXPORT_LIST\)//g; # remove .def from target dependency
579             push @out, $line;
580             }
581            
582             $code = join("\n", @out);
583             return $code;
584             };
585            
586             *dlsyms = sub {
587             my ($self, %attribs) = @_;
588             return '' if $gcc_compliant; # our dynamic_lib target doesn't need any .def files with gcc
589             return $self->SUPER::dlsyms(%attribs);
590             };
591             }
592             }
593              
594              
595             # dlsyms
596            
597             # generate DLL file containing all symbols, like default behaviour on UNIX.
598              
599              
600             sub _require_makemaker {
601 0 0   0   0 unless ($INC{'ExtUtils/MakeMaker.pm'}) {
602 0         0 require ExtUtils::MakeMaker;
603 0         0 ExtUtils::MakeMaker->import();
604             }
605             }
606              
607             sub _module_info_write {
608 1     1   3 my ($file, $info) = @_;
609 1         474 require Data::Dumper;
610 1         5450 local $Data::Dumper::Terse = 1;
611 1         1 local $Data::Dumper::Indent = 0;
612 1         4 my $content = Data::Dumper::Dumper($info);
613 1         70 my $restore_mode;
614 1 50       19 if (-e $file) { # make sure we have permissions to write, because perl installs files with 444 perms
615 0         0 my $mode = (stat $file)[2];
616 0 0       0 unless ($mode & 0200) { # if not, temporary enable write permissions
617 0         0 $restore_mode = $mode;
618 0         0 $mode |= 0200;
619 0         0 chmod $mode, $file;
620             }
621             }
622 1 50       53 open my $fh, '>', $file or do {
623 0         0 warn "Cannot open $file for writing: $!, \033[1;31mbinary deps info won't be synced!\033[0m\n";
624 0         0 sleep 2;
625 0         0 return;
626             };
627 1         10 print $fh $content;
628 1         34 close $fh;
629            
630 1 50       8 chmod $restore_mode, $file if $restore_mode; # restore old perms if we changed it
631             }
632              
633             1;