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 2 15 13.3
total 459 784 58.5


line stmt bran cond sub pod time code
1             package Panda::Install;
2 12     12   717820 use strict;
  12         96  
  12         288  
3 12     12   44 use warnings;
  12         18  
  12         209  
4 12     12   43 use Config;
  12         16  
  12         344  
5 12     12   41 use Cwd 'abs_path';
  12         17  
  12         459  
6 12     12   58 use Exporter 'import';
  12         17  
  12         290  
7 12     12   3930 use Panda::Install::Payload;
  12         24  
  12         35477  
8              
9             our $VERSION = '1.2.16';
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 1 0 _require_makemaker();
28 0         0 WriteMakefile(makemaker_args(@_));
29             }
30              
31             sub makemaker_args {
32 34     34 1 90822 my %params = @_;
33 34         101 _sync();
34            
35 34   50     191 $params{MIN_PERL_VERSION} ||= '5.10.0';
36            
37 34         56 my $postamble = $params{postamble};
38 34 50 33     90 $postamble = {my => $postamble} if $postamble and !ref($postamble);
39 34   50     150 $postamble ||= {};
40 34 50       114 $postamble->{my} = '' unless defined $postamble->{my};
41 34         58 $params{postamble} = $postamble;
42            
43 34         121 _string_merge($params{CCFLAGS}, '-o $@');
44              
45 34 50       83 die "You must define a NAME param" unless $params{NAME};
46 34 50 66     168 unless ($params{ALL_FROM} || $params{VERSION_FROM} || $params{ABSTRACT_FROM}) {
      33        
47 33         68 my $name = $params{NAME};
48 33         69 $name =~ s#::#/#g;
49 33         84 $params{ALL_FROM} = "lib/$name.pm";
50             }
51            
52 34 50       84 if (my $package_file = delete $params{ALL_FROM}) {
53 34         49 $params{VERSION_FROM} = $package_file;
54 34         47 $params{ABSTRACT_FROM} = $package_file;
55             }
56              
57 34   50     137 $params{CONFIGURE_REQUIRES} ||= {};
58 34   50     126 $params{CONFIGURE_REQUIRES}{'ExtUtils::MakeMaker'} ||= '6.76';
59 34   33     120 $params{CONFIGURE_REQUIRES}{'Panda::Install'} ||= $VERSION;
60            
61 34   50     115 $params{BUILD_REQUIRES} ||= {};
62 34   50     119 $params{BUILD_REQUIRES}{'ExtUtils::MakeMaker'} ||= '6.76';
63 34   50     122 $params{BUILD_REQUIRES}{'ExtUtils::ParseXS'} ||= '3.24';
64            
65 34   50     127 $params{TEST_REQUIRES} ||= {};
66 34   50     136 $params{TEST_REQUIRES}{'Test::Simple'} ||= '0.96';
67 34   50     111 $params{TEST_REQUIRES}{'Test::More'} ||= 0;
68 34   50     148 $params{TEST_REQUIRES}{'Test::Deep'} ||= 0;
69            
70 34   50     124 $params{PREREQ_PM} ||= {};
71 34   33     127 $params{PREREQ_PM}{'Panda::Install'} ||= $VERSION; # needed at runtime because it has payload_dir and xsloader
72            
73 34   50     117 $params{clean} ||= {};
74 34   50     131 $params{clean}{FILES} ||= '';
75            
76 34 50 66     97 delete $params{BIN_SHARE} if $params{BIN_SHARE} and !%{$params{BIN_SHARE}};
  1         5  
77            
78             {
79 34         47 my $val = $params{SRC};
80 34 100 100     84 $val = [$val] if $val and ref($val) ne 'ARRAY';
81 34         52 $params{SRC} = $val;
82             }
83             {
84 34         45 my $val = $params{XS};
  34         42  
  34         49  
85 34 100 100     93 $val = [$val] if $val and ref($val) ne 'ARRAY' and ref($val) ne 'HASH';
      100        
86 34         63 $params{XS} = $val;
87             }
88            
89 34 50 33     88 $params{TYPEMAPS} = [$params{TYPEMAPS}] if $params{TYPEMAPS} and ref($params{TYPEMAPS}) ne 'ARRAY';
90            
91 34   50     107 my $module_info = Panda::Install::Payload::module_info($params{NAME}) || {};
92 34         110 $params{MODULE_INFO} = {BIN_DEPENDENT => $module_info->{BIN_DEPENDENT}};
93            
94 34         115 process_XS(\%params);
95 34         125 process_PM(\%params);
96 34         126 process_C(\%params);
97 34         91 process_OBJECT(\%params);
98 34         84 process_H(\%params);
99 34         87 process_XSI(\%params);
100 34         110 process_CLIB(\%params);
101 34         93 process_PAYLOAD(\%params);
102 34         102 process_BIN_DEPS(\%params);
103 34         85 process_BIN_SHARE(\%params);
104 34         142 attach_BIN_DEPENDENT(\%params);
105 34         92 warn_BIN_DEPENDENT(\%params);
106              
107 34 100       82 if (my $use_cpp = delete $params{CPLUS}) {
108 3   100     10 $params{CC} ||= 'c++';
109 3   50     11 $params{LD} ||= '$(CC)';
110 3         9 _string_merge($params{XSOPT}, '-C++');
111            
112 3         4 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         53 $postamble->{xsubpprun} = 'XSUBPPRUN = $(PERLRUN) -MPanda::Install::ParseXS $(XSUBPP)';
118 34   50     155 $params{LDFROM} ||= '$(OBJECT)';
119            
120 34         99 delete $params{$_} for qw/SRC/;
121 34 50       81 $params{OBJECT} = '$(O_FILES)' unless defined $params{OBJECT};
122            
123 34 50 33     106 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         61 delete $params{MODULE_INFO};
130              
131 34         715 $params{CCFLAGS} = "$Config{ccflags} $params{CCFLAGS}";
132              
133 34 50 66     144 if (!$params{C} || !@{$params{C}} and !$params{OBJECT} || !@{$params{OBJECT}} and !$params{XS} || !scalar(keys %{$params{XS}})) {
  34   33     111  
  1   66     5  
  1   33     4  
      33        
134 1         5 delete $params{$_} for qw/C H OBJECT XS CCFLAGS LDFROM/;
135             }
136            
137 34         444 return %params;
138             }
139              
140             sub process_PM {
141 34     34 0 75 my $params = shift;
142 34 50       86 return if $params->{PM}; # user-defined value overrides defaults
143            
144 34         69 my $instroot = _instroot($params);
145 34         107 my @name_parts = split '::', $params->{NAME};
146 34   50     230 $params->{PMLIBDIRS} ||= ['lib', $name_parts[-1]];
147 34         78 my $pm = $params->{PM} = {};
148            
149 34         52 foreach my $dir (@{$params->{PMLIBDIRS}}) {
  34         73  
150 68 100       757 next unless -d $dir;
151 34         118 foreach my $file (_scan_files('*.pm *.pl', $dir)) {
152 68         110 my $rel = $file;
153 68         319 $rel =~ s/^$dir//;
154 68         172 my $instpath = "$instroot/$rel";
155 68         253 $instpath =~ s#[/\\]{2,}#/#g;
156 68         191 $pm->{$file} = $instpath;
157             }
158             }
159             }
160              
161             sub process_XS {
162 34     34 0 55 my $params = shift;
163 34         49 my ($xs_files, @xs_list);
164 34 100       93 if ($params->{XS}) {
165 6 100       17 if (ref($params->{XS}) eq 'HASH') {
166 2         6 $xs_files = $params->{XS};
167             } else {
168 4         5 push @xs_list, @{_string_split_array($_)} for @{$params->{XS}};
  4         10  
  6         11  
169             }
170             } else {
171 28         76 @xs_list = _scan_files($xs_mask);
172             }
173 34         70 push @xs_list, _scan_files($xs_mask, $_) for @{$params->{SRC}};
  34         101  
174 34   100     157 $params->{XS} = $xs_files ||= {};
175 34         68 foreach my $xsfile (@xs_list) {
176 94 100       174 next if $xs_files->{$xsfile};
177 93         111 my $cfile = $xsfile;
178 93 50       400 $cfile =~ s/\.xs$/.c/ or next;
179 93         248 $xs_files->{$xsfile} = $cfile;
180             }
181             }
182              
183             sub process_C {
184 34     34 0 49 my $params = shift;
185 34 100       117 my $c_files = $params->{C} ? _string_split_array(delete $params->{C}) : [_scan_files($c_mask)];
186 34         77 push @$c_files, grep { !_includes($c_files, $_) } values %{$params->{XS}};
  94         150  
  34         108  
187 34         53 push @$c_files, grep { !_includes($c_files, $_) } _scan_files($c_mask, $_) for @{$params->{SRC}};
  34         71  
  7         14  
188 34         77 $params->{C} = $c_files;
189             }
190              
191             sub process_OBJECT {
192 34     34 0 44 my $params = shift;
193 34         74 my $o_files = _string_split_array(delete $params->{OBJECT});
194 34         51 foreach my $c_file (@{$params->{C}}) {
  34         61  
195 224         250 my $o_file = $c_file;
196 224         553 $o_file =~ s/\.[^.]+$//;
197 224         457 push @$o_files, $o_file.'$(OBJ_EXT)';
198             }
199 34         57 $params->{OBJECT} = $o_files;
200 34         70 $params->{clean}{FILES} .= ' $(O_FILES)';
201             }
202              
203             sub process_H {
204 34     34 0 46 my $params = shift;
205 34 100       99 my $h_files = $params->{H} ? _string_split_array(delete $params->{H}) : [_scan_files($h_mask)];
206 34         68 push @$h_files, _scan_files($h_mask, $_) for @{$params->{SRC}};
  34         92  
207 34         77 $params->{H} = $h_files;
208             }
209              
210             sub process_XSI { # make XS files rebuild if an XSI file changes
211 34     34 0 43 my $params = shift;
212 34         1366 my @xsi_files = glob($xsi_mask);
213 34         87 push @xsi_files, _scan_files($xsi_mask, $_) for @{$params->{SRC}};
  34         86  
214 34 50       129 $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 47 my $params = shift;
219 34         53 my $clibs = '';
220 34 50       96 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 48 my $params = shift;
249 34 100       87 my $payload = delete $params->{PAYLOAD} or return;
250 10         21 _process_map($payload, '*');
251 10         22 _install($params, $payload, 'payload');
252             }
253              
254             sub process_BIN_DEPS {
255 34     34 0 45 my $params = shift;
256 34 50       81 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 44 my $params = shift;
341 34 100       78 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     3 my $include = delete($bin_share->{INCLUDE}) || {};
349 1         3 _process_map($include, $h_mask);
350 1         3 _install($params, $include, 'i');
351 1 50       3 $bin_share->{INCLUDE} = 1 if scalar(keys %$include);
352            
353 1 50 33     7 $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       10 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         79 mkdir 'blib';
368 1         4 my $infopath = 'blib/info';
369 1         4 _module_info_write($infopath, $bin_share);
370            
371 1   50     4 my $pm = $params->{PM} ||= {};
372 1         4 $pm->{$infopath} = '$(INST_ARCHLIB)/$(FULLEXT).x/info';
373             }
374              
375             sub attach_BIN_DEPENDENT {
376 34     34 0 61 my $params = shift;
377 34 50       63 my @deps = keys %{$params->{MODULE_INFO}{BIN_DEPS} || {}};
  34         182  
378 34 50       122 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 46 my $params = shift;
388 34 50       72 return unless $params->{VERSION_FROM};
389 34         54 my $module = $params->{NAME};
390 34 50       70 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   25 my ($params, $map, $path) = @_;
423 12 50       27 return unless %$map;
424 12         18 my $xs = $params->{XS};
425 12         32 my $instroot = _instroot($params);
426 12   50     37 my $pm = $params->{PM} ||= {};
427 12         36 while (my ($source, $dest) = each %$map) {
428 29         58 my $instpath = "$instroot/\$(FULLEXT).x/$path/$dest";
429 29         56 $instpath =~ s#[/\\]{2,}#/#g;
430 29         83 $pm->{$source} = $instpath;
431             }
432             }
433              
434             sub _instroot {
435 46     46   81 my $params = shift;
436 46         74 my $xs = $params->{XS};
437 46 100 66     196 my $instroot = ($xs and %$xs) ? '$(INST_ARCHLIB)' : '$(INST_LIB)';
438 46         82 return $instroot;
439             }
440              
441             sub _sync {
442 12     12   101 no strict 'refs';
  12         20  
  12         9237  
443 34     34   70 my $from = 'MYSOURCE';
444 34         47 my $to = 'MY';
445 34         63 foreach my $method (keys %{"${from}::"}) {
  34         156  
446 34 50       48 next unless defined &{"${from}::$method"};
  34         122  
447 34         45 *{"${to}::$method"} = \&{"${from}::$method"};
  34         136  
  34         83  
448             }
449             }
450              
451             sub _scan_files {
452 188     188   376 my ($mask, $dir) = @_;
453 188 100       12656 return grep {_is_file_ok($_)} glob($mask) unless $dir;
  321         598  
454            
455 98         277 my @list = grep {_is_file_ok($_)} glob(join(' ', map {"$dir/$_"} split(' ', $mask)));
  106         311  
  202         7752  
456            
457 98 50       2064 opendir(my $dh, $dir) or die "Could not open dir '$dir' for scanning: $!";
458 98         1175 while (my $entry = readdir $dh) {
459 416 100       1591 next if $entry =~ /^\./;
460 220         366 my $path = "$dir/$entry";
461 220 100       2442 next unless -d $path;
462 37         329 push @list, _scan_files($mask, $path);
463             }
464 98         766 closedir $dh;
465            
466 98         562 return @list;
467             }
468              
469             sub _is_file_ok {
470 427     427   577 my $file = shift;
471 427 100       3651 return unless -f $file;
472 424 50       1100 return if $file =~ /\#/;
473 424 50       605 return if $file =~ /~$/; # emacs temp files
474 424 50       588 return if $file =~ /,v$/; # RCS files
475 424 50       594 return if $file =~ m{\.swp$}; # vim swap files
476 424         1260 return 1;
477             }
478              
479             sub _process_map {
480 12     12   18 my ($map, $mask) = @_;
481 12         35 foreach my $source (keys %$map) {
482 18   66     41 my $dest = $map->{$source} || $source;
483 18 100       203 if (-f $source) {
484 11 100       45 $dest .= $source if $dest =~ m#[/\\]$#;
485 11         23 $dest =~ s#[/\\]{2,}#/#g;
486 11         18 $dest =~ s#^[/\\]+##;
487 11         22 $map->{$source} = $dest;
488 11         23 next;
489             }
490 7 50       65 next unless -d $source;
491            
492 7         20 delete $map->{$source};
493 7         13 my @files = _scan_files($mask, $source);
494 7         13 foreach my $file (@files) {
495 18         23 my $dest_file = $file;
496 18         94 $dest_file =~ s/^$source//;
497 18         36 $dest_file = "$dest/$dest_file";
498 18         46 $dest_file =~ s#[/\\]{2,}#/#g;
499 18         32 $dest_file =~ s#^[/\\]+##;
500 18         44 $map->{$file} = $dest_file;
501             }
502             }
503             }
504              
505             sub _includes {
506 101     101   153 my ($arr, $val) = @_;
507 101 50       148 for (@$arr) { return 1 if $_ eq $val }
  396         554  
508 101         244 return;
509             }
510              
511             sub _string_split_array {
512 46     46   59 my $list = shift;
513 46         69 my @result;
514 46 100       78 if ($list) {
515 12 100       38 $list = [$list] unless ref($list) eq 'ARRAY';
516 12         33 push @result, map { glob } split(' ') for @$list;
  12         372  
517             }
518 46         98 return \@result;
519             }
520              
521             sub _string_merge {
522 38 50   38   117 return unless $_[1];
523 38   100     197 $_[0] ||= '';
524 38 100       115 $_[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   76 use Config;
  12         20  
  12         6674  
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   2 my ($file, $info) = @_;
609 1         489 require Data::Dumper;
610 1         5164 local $Data::Dumper::Terse = 1;
611 1         2 local $Data::Dumper::Indent = 0;
612 1         3 my $content = Data::Dumper::Dumper($info);
613 1         64 my $restore_mode;
614 1 50       21 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       51 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         9 print $fh $content;
628 1         32 close $fh;
629            
630 1 50       7 chmod $restore_mode, $file if $restore_mode; # restore old perms if we changed it
631             }
632              
633             1;