File Coverage

blib/lib/XS/Install.pm
Criterion Covered Total %
statement 494 844 58.5
branch 143 380 37.6
condition 67 222 30.1
subroutine 66 85 77.6
pod 2 44 4.5
total 772 1575 49.0


line stmt bran cond sub pod time code
1             package XS::Install;
2 11     11   876478 use strict;
  11         111  
  11         332  
3 11     11   59 use warnings;
  11         21  
  11         308  
4 11     11   56 use Config;
  11         19  
  11         531  
5 11     11   63 use Cwd qw/getcwd abs_path/;
  11         30  
  11         687  
6 11     11   77 use Exporter 'import';
  11         19  
  11         417  
7 11     11   9438 use ExtUtils::MakeMaker;
  11         1226842  
  11         1348  
8 11     11   5284 use XS::Loader;
  11         31  
  11         403  
9 11     11   4874 use XS::Install::Deps;
  11         32  
  11         346  
10 11     11   82 use XS::Install::Util;
  11         23  
  11         246  
11 11     11   55 use XS::Install::Payload;
  11         22  
  11         204  
12 11     11   5568 use XS::Install::CMake;
  11         33  
  11         349  
13 11     11   7336 use Data::Dumper;
  11         70071  
  11         100726  
14              
15             our $VERSION = '1.3.3';
16             my $THIS_MODULE = 'XS::Install';
17              
18             our @EXPORT_OK = qw/write_makefile not_available/;
19             our @EXPORT;
20              
21             if ($0 =~ /Makefile.PL$/) {
22             @EXPORT = qw/write_makefile not_available/;
23             _require_makemaker();
24             }
25              
26             my $xs_mask = '*.xs';
27             my $c_mask = '*.c *.cc *.cpp *.cxx';
28             my $h_mask = '*.h *.hh *.hpp *.hxx';
29             my $map_mask = '*.map';
30              
31             my $win32 = $^O eq 'MSWin32';
32             my $linux = $^O eq 'linux';
33             my $freebsd = $^O eq 'freebsd';
34             my $mac = $^O eq 'darwin';
35             my $dragonfly = $^O eq 'dragonfly';
36             my $netbsd = $^O eq 'netbsd';
37             my $openbsd = $^O eq 'openbsd';
38             my $solaris = $^O eq 'solaris';
39              
40             my $native_bsd_make = $freebsd || $dragonfly || $netbsd || $openbsd || $solaris;
41             my $fix_bsd_make_j = $freebsd || $dragonfly || $netbsd;
42              
43             sub write_makefile {
44 0     0 1 0 _require_makemaker();
45              
46 0         0 my ($main_params, $test_params) = makemaker_args(@_);
47              
48 0         0 MY::init_methods();
49 0         0 WriteMakefile(%$main_params);
50              
51 0 0       0 if ($test_params) {
52 0         0 MY::init_methods();
53 0         0 WriteMakefile(%$test_params);
54             }
55             }
56              
57             sub makemaker_args {
58 31 50   31 0 113561 my $params = ref($_[0]) eq 'HASH' ? $_[0] : {@_};
59 31         131 _sync();
60 31 50       114 die "You must define a NAME param" unless $params->{NAME};
61              
62 31         121 pre_process($params);
63 31         110 process_FROM($params);
64 31         127 process_REQUIRES($params);
65 31         100 process_BIN_DEPS($params);
66 31         107 process_PARSE_XS($params);
67 31         110 process_CPLUS($params);
68 31         87 process_CCFLAGS($params);
69 31         138 $params->{OPTIMIZE} = merge_optimize($Config{optimize}, '-O2', $params->{OPTIMIZE});
70 31         139 process_PKG_CONFIG($params);
71 31         116 process_SANITIZE($params);
72 31         95 process_CLIB($params);
73 31         102 process_binary($params);
74 31         116 process_PM($params);
75 31         153 process_PAYLOAD($params);
76 31         106 process_LD($params);
77              
78 31         73 my $test_mm_args;
79 31 50       85 if ($params->{_XSTEST}) {
80 0         0 process_test_makefile($params);
81             } else {
82 31         91 $test_mm_args = process_test($params);
83 31         123 my $cmake_params = process_cmake_test($params, $params->{CMAKE_PARAMS}, $test_mm_args);
84 31 50       137 run_cmake($params, $cmake_params, $test_mm_args) if ($cmake_params);
85             }
86 31         110 process_BIN_SHARE($params);
87 31         106 attach_BIN_DEPENDENT($params);
88 31         99 warn_BIN_DEPENDENT($params);
89 31         93 fix_flags($params);
90              
91 31         108 process_INSTALL_SKIP($params);
92 31         99 post_process($params);
93              
94 31 100       127 return ($params, $test_mm_args) if wantarray();
95 20         169 return $params;
96             }
97              
98             sub pre_process {
99 31     31 0 63 my $params = shift;
100              
101 31         70 my $postamble = $params->{postamble};
102 31 50       85 if ($postamble) {
103 0         0 my $ref = ref $postamble;
104 0 0       0 if (!$ref) { $postamble = [$postamble] }
  0 0       0  
    0          
105 0         0 elsif ($ref eq 'HASH') { $postamble = [values %$postamble] }
106 0         0 elsif ($ref ne 'ARRAY') { die "postamble must be string or array ref" }
107             }
108 31   50     233 $postamble ||= [];
109 31         76 $params->{postamble} = $postamble;
110              
111 31   50     166 $params->{clean} ||= {};
112 31   50     170 $params->{clean}{FILES} ||= '';
113              
114 31 50 33     182 if (my $comp = ($ENV{COMPILER} || $ENV{CC})) {
115 0         0 $params->{CC} = $comp;
116             }
117              
118 31 50       102 if (my $opt = $ENV{OPTIMIZE}) {
119 31         73 $params->{OPTIMIZE} = $opt;
120             }
121              
122 31         137 canonize_array_split($params->{TYPEMAPS});
123 31         127 canonize_array_split($params->{PARSE_XS});
124              
125 31   50     155 my $module_info = XS::Install::Payload::binary_module_info($params->{NAME}) || {};
126             $params->{MODULE_INFO} = {
127             BIN_DEPENDENT => $module_info->{BIN_DEPENDENT},
128             STATIC_LIBS => [],
129             SHARED_LIBS => [],
130             ORIG => {
131             INC => $params->{INC} || '',
132             CCFLAGS => $params->{CCFLAGS},
133             LDDLFLAGS => $params->{LDDLFLAGS},
134             LINK => $params->{LINK},
135             },
136 31   50     428 INSTALL_SKIP => [],
137             };
138              
139 31   33     209 $params->{UNIQUE_LIBNAME} //= $win32;
140 31 50       99 *DynaLoader::mod2fname = \&XS::Loader::mod2fname_unique if delete $params->{UNIQUE_LIBNAME};
141              
142 31 50 66     128 $params->{BIN_SHARE} = {} if $params->{BIN_SHARE} && !ref($params->{BIN_SHARE});
143 31 50 0     139 $params->{BIN_SHARE}{LINK} //= $params->{LINK} if $params->{BIN_SHARE} && $params->{LINK};
      66        
144             }
145              
146             sub process_FROM {
147 31     31 0 56 my $params = shift;
148 31 50       98 my $module = $params->{NAME} or die "You must define a NAME param";
149              
150 31 100       86 if (my $file = delete $params->{ALL_FROM}) {
151 1 50       5 $params->{VERSION_FROM} = $file unless $params->{VERSION};
152 1 50       3 $params->{ABSTRACT_FROM} = $file unless $params->{ABSTRACT};
153             }
154              
155 31         118 my $pm = 'lib/'._pkg_file($module);
156 31         96 my $pod = 'lib/'._pkg_slash($module).'.pod';
157              
158 31 50 66     197 $params->{VERSION_FROM} ||= $pm unless $params->{VERSION};
159 31 50 66     579 $params->{ABSTRACT_FROM} ||= (-f $pod) ? $pod : $pm unless $params->{ABSTRACT};
    50          
160             }
161              
162             sub process_REQUIRES {
163 31     31 0 57 my $params = shift;
164              
165 31   50     173 $params->{CONFIGURE_REQUIRES} ||= {};
166 31   50     165 $params->{BUILD_REQUIRES} ||= {};
167              
168 31   50     151 $params->{TEST_REQUIRES} ||= {};
169 31   50     151 $params->{TEST_REQUIRES}{'Test::Simple'} ||= '0.96';
170 31   50     136 $params->{TEST_REQUIRES}{'Test::More'} ||= 0;
171 31   50     154 $params->{TEST_REQUIRES}{'Test::Deep'} ||= 0;
172              
173 31   50     140 $params->{PREREQ_PM} ||= {};
174              
175 31 50       116 unless ($params->{NAME} eq $THIS_MODULE) { # skip when building XS::Install itself
176 31   33     159 $params->{CONFIGURE_REQUIRES}{$THIS_MODULE} ||= $VERSION;
177 31   33     120 $params->{PREREQ_PM }{$THIS_MODULE} ||= $VERSION;
178             }
179             }
180              
181             sub process_PM {
182 31     31 0 53 my $params = shift;
183 31 50       91 return if $params->{PM}; # user-defined value overrides defaults
184              
185 31         393 my $instroot = _instroot($params);
186 31         139 my @name_parts = split '::', $params->{NAME};
187 31   50     206 $params->{PMLIBDIRS} ||= ['lib', $name_parts[-1]];
188 31         73 my $pm = $params->{PM} = {};
189              
190 31         57 foreach my $dir (@{$params->{PMLIBDIRS}}) {
  31         74  
191 62 100       947 next unless -d $dir;
192 31         129 foreach my $file (_scan_files('*.pm *.pl *.pod', $dir)) {
193 58         119 my $rel = $file;
194 58         387 $rel =~ s/^$dir//;
195 58         177 my $instpath = "$instroot/$rel";
196 58         260 $instpath =~ s#[/\\]{2,}#/#g;
197 58         211 $pm->{$file} = $instpath;
198             }
199             }
200             }
201              
202             sub process_PAYLOAD {
203 31     31 0 61 my $params = shift;
204 31 100       112 my $payload = delete $params->{PAYLOAD} or return;
205 10         26 _process_map($payload, '*');
206 10         32 _install($params, $payload, 'payload');
207             }
208              
209             sub process_BIN_DEPS {
210 31     31 0 57 my $params = shift;
211 31         69 my $bin_deps = delete $params->{BIN_DEPS};
212 31         92 canonize_array_split($bin_deps);
213 31 50       116 push @$bin_deps, $THIS_MODULE unless $params->{NAME} eq $THIS_MODULE;
214              
215 31         67 my $typemaps = $params->{TYPEMAPS};
216 31         61 $params->{TYPEMAPS} = [];
217 31         71 my $seen = {};
218 31         117 _apply_BIN_DEPS($params, $_, $seen) for @$bin_deps;
219 31         62 push @{$params->{TYPEMAPS}}, @$typemaps;
  31         131  
220             }
221              
222             sub _apply_BIN_DEPS {
223 31     31   92 my ($params, $module, $seen) = @_;
224 31         47 my $stop_sharing;
225 31 50       101 $stop_sharing = 1 if $module =~ s/^-//;
226              
227 31 50       144 return if $seen->{$module}++;
228              
229 31         98 my ($installed_version, $failure) = binary_module_version($module);
230 31 50       81 die "[XS::Install] binary dependency '$module' must be installed to proceed (details: $failure)\n"
231             unless $installed_version;
232 31   33     118 $params->{CONFIGURE_REQUIRES}{$module} ||= $installed_version;
233 31   33     90 $params->{PREREQ_PM}{$module} ||= $installed_version;
234 31         102 $params->{MODULE_INFO}{BIN_DEPS}{$module} = $installed_version;
235 31 50 50     91 push @{$params->{MODULE_INFO}{VISIBLE_BIN_DEPS} ||= []}, $module unless $stop_sharing;
  31         233  
236              
237 31 50       136 my $info = XS::Install::Payload::binary_module_info($module)
238             or die "[XS::Install] this module wants '$module' as a binary dependence, however '$module' doesn't provide any binary interface\n";
239              
240             # add so/dll to linker list
241 31         70 my $shared_list = $params->{MODULE_INFO}{SHARED_LIBS};
242 31         58 my $module_path = $module;
243 31         144 $module_path =~ s#::#/#g;
244 31 50       186 die "SHOULDN'T EVER HAPPEN" unless $module =~ /([^:]+)$/;
245 31         94 my $module_last_name = $1;
246 31         80 foreach my $dir (@INC) {
247 341         993 my $lib_path = "$dir/auto/$module_path/";
248 341 50       672 if ($info->{FILE}) {
249 0         0 $lib_path .= $info->{FILE};
250             } else { # DEPRECATED
251 341         2052 $lib_path .= $module_last_name.".".$Config{dlext};
252             }
253              
254 341 50       5202 next unless -f $lib_path;
255 0         0 push @$shared_list, abs_path($lib_path);
256 0         0 last;
257             }
258              
259 31 50       121 if ($info->{INCLUDE}) {
260 31         134 my $incdir = XS::Install::Payload::include_dir($module);
261 31         212 _string_merge($params->{INC}, "-I$incdir");
262             }
263              
264 31         142 _string_merge($params->{INC}, $info->{INC});
265 31         125 _string_merge($params->{CCFLAGS}, $info->{CCFLAGS});
266 31         125 _string_merge($params->{LDDLFLAGS}, $info->{LDDLFLAGS});
267 31         117 _string_merge($params->{LINK}, $info->{LINK});
268 31         115 _string_merge($params->{DEFINE}, $info->{DEFINE});
269 31         108 _string_merge($params->{XSOPT}, $info->{XSOPT});
270              
271 31         157 _merge_libs($params, $info->{LIBS});
272              
273 31 50       101 if (my $passthrough = $info->{PASSTHROUGH}) {
274 0         0 _apply_BIN_DEPS($params, $_, $seen) for @$passthrough;
275             }
276              
277 31 50       87 if (my $typemaps = $info->{TYPEMAPS}) {
278 31         96 my $tm_dir = XS::Install::Payload::typemap_dir($module);
279 31         115 foreach my $typemap (@$typemaps) {
280 31         107 my $tmfile = "$tm_dir/$typemap";
281 31         165 $tmfile =~ s#[/\\]{2,}#/#g;
282 31   50     52 push @{$params->{TYPEMAPS} ||= []}, $tmfile;
  31         161  
283             }
284             }
285              
286 31 0 0     91 $params->{CPLUS} = $info->{CPLUS} if $info->{CPLUS} and (!$params->{CPLUS} or $params->{CPLUS} < $info->{CPLUS});
      33        
287              
288 31 50       94 if (my $parsexs = $info->{PARSE_XS}) {
289 31   50     54 push @{$params->{PARSE_XS}||=[]}, @$parsexs;
  31         152  
290             }
291             }
292              
293             sub process_PARSE_XS { # inject ParseXS plugins into xsubpp
294 31     31 0 57 my $params = shift;
295 31         69 my $list = $params->{PARSE_XS};
296 31 50       77 return unless @$list;
297 31         109 _uniq_list($list);
298 31         83 my $inc = join ' ', map { "-M$_" } @$list;
  31         141  
299 31         53 push @{$params->{postamble}}, "XSUBPPRUN = \$(PERLRUN) -Ilib $inc \$(XSUBPP)";
  31         132  
300             }
301              
302             sub process_binary {
303 31     31 0 56 my $params = shift;
304              
305 31 50 66     224 $params->{XS} ||= $params->{_XSTEST} ? [] : [_scan_files($xs_mask)];
306 31 50 66     213 $params->{C} ||= $params->{_XSTEST} ? [] : [_scan_files($c_mask)];
307              
308 31         162 canonize_array_split($params->{SRC});
309              
310 31 100       139 if (ref($params->{XS}) ne 'HASH') {
311 29         100 canonize_array_files($params->{XS});
312 29         59 $params->{XS} = { map {$_ => undef} @{$params->{XS}} };
  74         206  
  29         80  
313             }
314              
315 31         83 my %xsi;
316 31         52 foreach my $xsfile (keys %{$params->{XS}}, map { _scan_files($xs_mask, $_) } @{$params->{SRC}}) {
  31         119  
  5         15  
  31         102  
317 77         174 my $cfile = $params->{XS}{$xsfile};
318 77         117 my $suffix;
319 77 100       179 unless ($cfile) {
320 76 50       195 my $cext = $params->{CPLUS} ? 'cc' : 'c';
321 76 50       349 if ($xsfile =~ /\.xs$/) {
322 76         185 $cfile = $xsfile;
323 76         456 $cfile =~ s/\.xs$/_xsgen.$cext/;
324 76         1275 $suffix = "_xsgen.$cext";
325             } else {
326 0         0 $cfile = "$xsfile.$cext";
327             }
328 76         315 $params->{XS}{$xsfile} = $cfile;
329             }
330 77 100       171 unless ($suffix) {
331 1         2 $suffix = $cfile;
332 1         7 $suffix =~ s/^[^.]+//;
333             }
334              
335 77   50     335 my $xsi_deps = XS::Install::Deps::find_xsi_deps([$xsfile])->{$xsfile} || [];
336 77         212 map { $xsi{$_} = $xsfile } @$xsi_deps;
  0         0  
337              
338 77         1072 push @{$params->{postamble}}, "$cfile : $xsfile @$xsi_deps \$(FIRST_MAKEFILE)\n".
  77         599  
339             "\t\$(XSUBPPRUN) \$(XSPROTOARG) \$(XSUBPPARGS) -csuffix $suffix \$(XSUBPP_EXTRA_ARGS) $xsfile > ${xsfile}c\n".
340             "\t\$(MV) ${xsfile}c $cfile";
341             }
342              
343 31         131 canonize_array_files($params->{C});
344 31         269 push @{$params->{C}}, _scan_files($c_mask, $_) for @{$params->{SRC}};
  31         114  
  5         16  
345 31         60 my @cdeps_list = (@{$params->{C}}, keys(%{$params->{XS}}), keys(%xsi));
  31         62  
  31         138  
346 31         58 push @{$params->{C}}, values %{$params->{XS}};
  31         65  
  31         115  
347 31         114 _uniq_list($params->{C});
348 31         138 _uniq_list(\@cdeps_list);
349              
350             my $cdeps = XS::Install::Deps::find_header_deps({
351             files => \@cdeps_list,
352             headers => ['./'],
353 31         283 inc => [map { s/^-I//; $_ } split(' ', $params->{MODULE_INFO}{ORIG}{INC})],
  0         0  
  0         0  
354             });
355              
356             # push C to OBJECT and process C files header deps
357 31         199 canonize_array_files($params->{OBJECT});
358 31         67 foreach my $cfile (@{$params->{C}}) {
  31         87  
359 179         337 my $ofile = c2obj_file($cfile);
360 179         240 push @{$params->{OBJECT}}, $ofile;
  179         340  
361              
362 179         332 my $deps = delete $cdeps->{$cfile};
363 179 50 66     573 push @{$params->{postamble}}, "$ofile : @$deps" if $deps && @$deps;
  0         0  
364             }
365 31         104 _uniq_list($params->{OBJECT});
366              
367             # process XS & XSI header deps
368 31         93 foreach my $f (keys %xsi) {
369 0         0 my $deps = delete $cdeps->{$f};
370 0 0 0     0 next unless $deps && @$deps;
371 0   0     0 push @{$cdeps->{$xsi{$f}} ||= []}, @$deps;
  0         0  
372             }
373 31         52 foreach my $xsfile (keys %{$params->{XS}}) {
  31         92  
374 77         133 my $deps = delete $cdeps->{$xsfile};
375 77 50 33     338 next unless $deps && @$deps;
376 0         0 _uniq_list($deps);
377 0         0 my $cfile = $params->{XS}{$xsfile};
378 0         0 my $ofile = c2obj_file($cfile);
379 0         0 push @{$params->{postamble}}, "$ofile : @$deps";
  0         0  
380             }
381              
382 31         73 delete $params->{H}; # prevent MM from making O_FILES depend on all H_FILES
383              
384 31         137 $params->{clean}{FILES} .= ' $(O_FILES)';
385             }
386              
387             sub process_CMAKE {
388 0     0 0 0 my ($target, $params, $info) = @_;
389              
390 0         0 my $bdir = $info->{DIR}.'/build';
391 0         0 my $pdir = $info->{DIR}.'/cmake_props';
392 0         0 my $prefix = 'cmake_prefix';
393 0 0       0 mkdir($bdir) unless -d $bdir;
394 0 0       0 mkdir($pdir) unless -d $pdir;
395 0 0       0 mkdir("$pdir/$prefix") unless -d "$pdir/$prefix";
396              
397 0         0 my $make = '$(MAKE)';
398 0 0 0     0 $make = 'gmake' if $info->{GMAKE} and $native_bsd_make;
399              
400 0         0 my $cflags = $params->{INC};
401 0         0 _string_merge($cflags, $params->{CCFLAGS});
402 0         0 _string_merge($cflags, $params->{DEFINE});
403 0         0 _string_merge($cflags, $params->{OPTIMIZE});
404              
405 0         0 _string_merge($info->{CMAKE_OPTIONS}, "-DCMAKE_INSTALL_PREFIX:PATH=$prefix");
406              
407             $params->{CMAKE_PARAMS} = {
408             BUILD_DIR => $bdir,
409             PROP_DIR => $pdir,
410             MAIN_TARGET => $target,
411             TARGETS => {
412             $target => "-fPIC $cflags",
413             },
414             OPTIONS => $info->{CMAKE_OPTIONS},
415 0         0 };
416              
417 0         0 $info->{DIR} = $bdir;
418 0         0 $info->{TARGET} = $target;
419 0   0     0 $info->{FLAGS} ||= '';
420 0         0 $info->{BUILD_CMD} = "cd ../cmake_props && $make $info->{FLAGS} $info->{TARGET}";
421 0         0 $info->{CLEAN_CMD} = '';
422 0         0 $info->{FORCE_TRACKING} = 1;
423              
424 0         0 $params->{clean}{FILES} .= " $bdir $pdir";
425              
426 0         0 push @{$params->{postamble}}, "cmake_install : dynamic\n".
  0         0  
427             "\tcd $bdir && $make install \$(DEV_NULL)";
428              
429 0         0 my $cmake_share = run_cmake($params, $params->{CMAKE_PARAMS});
430 0         0 $cmake_share->{CMAKE_TMP_INSTALL_DIR} = "$bdir/$prefix";
431 0         0 apply_CMAKE($params, $cmake_share);
432             }
433              
434             sub process_CLIB {
435 31     31 0 45 my $params = shift;
436 31         63 my $clibs = '';
437 31 50       133 my $clib = delete $params->{CLIB} or return;
438 0 0       0 $clib = [$clib] unless ref($clib) eq 'ARRAY';
439 0 0       0 return unless @$clib;
440              
441 0 0       0 my $wa_open = $mac ? '-Wl,-force_load' : '-Wl,--whole-archive';
442 0 0       0 my $wa_close = $mac ? '' : '-Wl,--no-whole-archive';
443              
444 0         0 foreach my $info (@$clib) {
445 0         0 my $cmake_target = $info->{CMAKE_TARGET};
446 0 0       0 if ($cmake_target) {
447 0         0 process_CMAKE($cmake_target, $params, $info);
448             }
449              
450 0         0 my $build_cmd = $info->{BUILD_CMD};
451 0         0 my $clean_cmd = $info->{CLEAN_CMD};
452              
453 0 0       0 unless ($build_cmd) {
454 0         0 my $make = '$(MAKE)';
455 0 0 0     0 $make = 'gmake' if $info->{GMAKE} and $native_bsd_make;
456 0   0     0 $info->{TARGET} ||= '';
457 0   0     0 $info->{FLAGS} ||= '';
458 0         0 $build_cmd = "$make $info->{FLAGS} $info->{TARGET}";
459 0         0 $clean_cmd = "$make clean";
460             }
461 0 0 0     0 $info->{FILE} = [$info->{FILE}] if exists $info->{FILE} && ref $info->{FILE} ne 'ARRAY';
462 0         0 my $path = '';
463 0         0 my $static = 0;
464 0 0       0 for my $f (@{$info->{FILE} || []}) {
  0         0  
465 0 0       0 next unless $f;
466 0 0       0 $static = 1 if $f =~ /\.l?a$/;
467 0         0 $path .= $info->{DIR}.'/'.$f.' ';
468             }
469 0         0 $clibs .= $path;
470              
471 0 0       0 my $force = $info->{FORCE_TRACKING} ? 'FORCE' : '';
472              
473 0         0 push @{$params->{postamble}}, "$path : $force; cd $info->{DIR} && $build_cmd\n";
  0         0  
474 0 0       0 push @{$params->{postamble}}, "clean :: ; cd $info->{DIR} && $clean_cmd\n" if $clean_cmd;
  0         0  
475 0 0       0 if ($static) {
476 0         0 push @{$params->{MODULE_INFO}{STATIC_LIBS}}, "$wa_open $path $wa_close";
  0         0  
477             } else {
478 0         0 push @{$params->{MODULE_INFO}{SHARED_LIBS}}, $path;
  0         0  
479             }
480             }
481 0         0 push @{$params->{postamble}}, "\$(INST_DYNAMIC) : $clibs";
  0         0  
482             }
483              
484             sub process_PKG_CONFIG {
485 31     31 0 54 my $params = shift;
486 31         114 canonize_array_split($params->{PKG_CONFIG});
487 31         68 my $pkgs = $params->{PKG_CONFIG};
488              
489 31         49 my @bin_share_auto;
490 31         71 for my $pkg (@$pkgs) {
491 3 100       28 push @bin_share_auto, $pkg unless $pkg =~ s/^\s*-//;
492             }
493              
494 31         101 set_pkg_config($params, $pkgs);
495              
496 31 100       95 my $bin_share = $params->{BIN_SHARE} or return;
497 4         10 my $bin_share_pkgs = delete $bin_share->{PKG_CONFIG};
498 4         12 canonize_array_split($bin_share_pkgs);
499 4         12 set_pkg_config($bin_share, [@bin_share_auto, @$bin_share_pkgs]);
500             }
501              
502             sub set_pkg_config {
503 35     35 0 83 my ($params, $pkgs) = @_;
504 35 100       133 return unless @$pkgs;
505 6         436 require XS::Install::PkgConfigFixed;
506              
507 6         28 for my $pkg (@$pkgs) {
508 6         45 my $res = PkgConfig->find($pkg);
509 6 50       7143 warn $res->errmsg if $res->errmsg;
510 6         69 my @ccargs = $res->get_cflags;
511              
512 6         585 _string_merge($params->{INC}, join ' ', grep /^-I/, @ccargs);
513 6         44 _string_merge($params->{CCFLAGS}, join ' ', grep !/^-I/, @ccargs);
514 6         31 _string_merge($params->{LINK}, scalar $res->get_ldflags);
515             }
516             }
517              
518             sub process_BIN_SHARE {
519 31     31 0 54 my $params = shift;
520 31 100       98 my $bin_share = delete $params->{BIN_SHARE} or return;
521 4 50       11 return unless %$bin_share;
522 4 50       14 return if $params->{_XSTEST};
523              
524 4   100     23 my $typemaps = delete($bin_share->{TYPEMAPS}) || {};
525 4         19 _process_map($typemaps, $map_mask);
526 4         17 _install($params, $typemaps, 'tm');
527 4 100       15 $bin_share->{TYPEMAPS} = [values %$typemaps] if scalar keys %$typemaps;
528              
529 4   100     23 my $include = delete($bin_share->{INCLUDE}) || {};
530 4 50       13 if ($include == 1) {
531 0         0 $bin_share->{INCLUDE} = 1;
532             } else {
533 4         13 _process_map($include, $h_mask);
534 4         13 _install($params, $include, 'i');
535 4 100       24 $bin_share->{INCLUDE} = 1 if scalar(keys %$include);
536             }
537              
538 4 50 66     28 $bin_share->{LIBS} = [$bin_share->{LIBS}] if $bin_share->{LIBS} and ref($bin_share->{LIBS}) ne 'ARRAY';
539              
540 4 50       16 if (my $list = $params->{MODULE_INFO}{BIN_DEPENDENT}) {
541 0 0       0 $bin_share->{BIN_DEPENDENT} = $list if @$list;
542             }
543              
544 4 50       13 if (my $vinfo = $params->{MODULE_INFO}{BIN_DEPS}) {
545 4 50       15 $bin_share->{BIN_DEPS} = $vinfo if %$vinfo;
546             }
547              
548 4 50 33     13 $bin_share->{PARSE_XS} = [$bin_share->{PARSE_XS}] if $bin_share->{PARSE_XS} and ref($bin_share->{PARSE_XS}) ne 'ARRAY';
549              
550 4 50       11 return unless %$bin_share;
551              
552 4 50       12 if (my $vbd = $params->{MODULE_INFO}{VISIBLE_BIN_DEPS}) {
553 4         11 my $pt =
554             _uniq_list($vbd);
555 4         16 $bin_share->{PASSTHROUGH} = $vbd;
556             }
557              
558 4         10 $bin_share->{LOADABLE} = has_binary($params);
559              
560 4 50 0     12 $bin_share->{CPLUS} //= $params->{CPLUS} if $params->{CPLUS};
561 4         15 $bin_share->{FILE} = module_so_file($params);
562              
563             # generate info file
564 4         160 mkdir 'blib';
565 4         21 my $infopath = 'blib/info';
566 4         33 XS::Install::Util::module_info_write($infopath, $bin_share);
567 4         55 _install($params, {$infopath => 'info'}, '');
568             }
569              
570             sub attach_BIN_DEPENDENT {
571 31     31 0 54 my $params = shift;
572 31 50       47 my @deps = keys %{$params->{MODULE_INFO}{BIN_DEPS} || {}};
  31         185  
573 31 50       92 return unless @deps;
574              
575 31         56 push @{$params->{postamble}}, "sync_bin_deps:\n".
  31         219  
576             "\t\$(PERL) -M${THIS_MODULE}::Util -e '${THIS_MODULE}::Util::cmd_sync_bin_deps()' $params->{NAME} @deps";
577 31         63 push @{$params->{postamble}}, "install :: sync_bin_deps";
  31         119  
578             }
579              
580             sub warn_BIN_DEPENDENT {
581 31     31 0 48 my $params = shift;
582 31 50       90 return unless $params->{VERSION_FROM};
583 31         67 my $module = $params->{NAME};
584 31 50       82 return if $module eq $THIS_MODULE;
585 31 50       128 my $list = $params->{MODULE_INFO}{BIN_DEPENDENT} or return;
586 0 0       0 return unless @$list;
587 0         0 my ($installed_version, $failure) = binary_module_version($module);
588 0 0       0 return unless $installed_version;
589 0 0       0 my $new_version = MM->parse_version($params->{VERSION_FROM}) or return;
590 0 0       0 return if $installed_version eq $new_version;
591 0         0 warn << "EOF";
592             ******************************************************************************
593             $THIS_MODULE: There are XS modules that binary depend on current XS module $module.
594             They were built with currently installed $module version $installed_version.
595             If you install $module version $new_version, you will have to reinstall all XS modules that binary depend on it:
596             cpanm -f @$list
597             ******************************************************************************
598             EOF
599             }
600              
601             sub process_SANITIZE {
602 31     31 0 53 my $params = shift;
603 31 50       97 my $mode = $ENV{SANITIZE} or return;
604              
605 0         0 my @preload;
606              
607 0 0       0 if ($mode =~ /a/i) {
608 0         0 push @preload, _cc_get_so_path($params, 'libasan.so');
609 0         0 _string_merge($params->{CCFLAGS}, '-fsanitize=address -fno-omit-frame-pointer');
610 0         0 _string_merge($params->{LINK}, '-lasan');
611             }
612              
613 0 0       0 if ($mode =~ /u/i) {
614 0         0 push @preload, _cc_get_so_path($params, 'libubsan.so');
615 0         0 _string_merge($params->{CCFLAGS}, '-fsanitize=undefined');
616 0         0 _string_merge($params->{LINK}, '-lubsan');
617             }
618              
619 0         0 @preload = grep {$_} @preload;
  0         0  
620              
621 0 0 0     0 if (@preload and !$win32) {
622 0 0       0 my $preload = 'LD_PRELOAD='.join($win32 ? ';' : ':', @preload);
623 0         0 push @{$params->{postamble}}, "ABSPERL = $preload \$(PERL)";
  0         0  
624 0         0 push @{$params->{postamble}}, "PERLRUN = $preload \$(PERL)";
  0         0  
625 0         0 push @{$params->{postamble}}, "FULLPERLRUN = $preload \$(FULLPERL)";
  0         0  
626             }
627             }
628              
629             sub _cc_get_so_path {
630 0     0   0 my ($params, $so) = @_;
631 0   0     0 my $cc = $params->{CC} || $Config{cc};
632 0         0 my $file = `$cc -print-file-name=$so`;
633 0         0 chomp($file);
634 0 0       0 return if $file eq $so;
635 0         0 return $file;
636             }
637              
638             sub process_CPLUS {
639 31     31 0 55 my $params = shift;
640 31 50       107 my $use_cpp = $params->{CPLUS} or return;
641              
642 0         0 my $cppv = int($use_cpp);
643 0 0       0 $cppv = 11 if $cppv < 11;
644 0         0 _string_merge($params->{CCFLAGS}, "-std=c++$cppv");
645              
646 0         0 $params->{CC} = _get_cplusplus($params->{CC}, $cppv);
647 0   0     0 $params->{LD} ||= '$(CC)';
648 0         0 _string_merge($params->{XSOPT}, '-C++');
649              
650             # prevent C++ from compile errors on perls <= 5.18, as perl had buggy prior to 5.20
651 0 0       0 _string_merge($params->{CCFLAGS}, "-Wno-reserved-user-defined-literal -Wno-literal-suffix -Wno-unknown-warning-option") if $^V < v5.20;
652             }
653              
654             sub process_CCFLAGS {
655 31     31 0 51 my $params = shift;
656 31         145 $params->{CCFLAGS} = string_merge($params->{CCFLAGS}, $Config{ccflags});
657 31 50       120 _string_merge($params->{CCFLAGS}, '-Wno-unused-parameter') if $win32; # on Strawberry's mingw PERL_UNUSED_DECL doesn't work
658             }
659              
660             sub fix_flags {
661 31     31 0 63 my $params = shift;
662 31         112 _string_merge($params->{CCFLAGS}, '-o $@');
663              
664 31 50       133 if ($params->{OPTIMIZE} =~ /(^|\s)-g(\s|$)/) { # remove stripping flag is debug enabled
665 0         0 1 while $params->{OPTIMIZE} =~ s/(^|\s)-s(\s|$)/ /;
666 0         0 $params->{OPTIMIZE} =~ s/\s+/ /g; $params->{OPTIMIZE} =~ s/^\s+//; $params->{OPTIMIZE} =~ s/\s+$//;
  0         0  
  0         0  
667 0         0 1 while $params->{LDDLFLAGS} =~ s/(^|\s)-s(\s|$)/ /;
668             }
669             }
670              
671             sub process_LD {
672 31     31 0 61 my $params = shift;
673              
674 31   50     200 $params->{LDFROM} ||= '$(OBJECT)';
675              
676             {
677 31         47 my $str = join(' ', @{$params->{MODULE_INFO}{STATIC_LIBS}});
  31         49  
  31         104  
678 31 50       88 $params->{LDFROM} .= ' '.$str if $str;
679             }
680              
681             # MacOSX doesn't allow for linking with bundles :(
682             # Linux/Unix does not need them, as .so-files will be loaded by perl
683 31 50       85 if ($win32) {
684 0         0 my %seen;
685 0         0 my @shared_libs = grep {!$seen{$_}++} reverse @{$params->{MODULE_INFO}{SHARED_LIBS}};
  0         0  
  0         0  
686 0         0 my $str = join(' ', @shared_libs);
687 0         0 $params->{MODULE_INFO}{SHARED_LIBS_LINKING} = $str;
688 0 0       0 $params->{LDFROM} .= ' '.$str if $str;
689             }
690              
691 31         296 my $cfg_lddlflags = $Config{lddlflags};
692 31 50 50     300 $params->{LDDLFLAGS} = string_merge($cfg_lddlflags, $params->{LDDLFLAGS}) if index($params->{LDDLFLAGS} || '', $cfg_lddlflags) == -1;
693             }
694              
695             sub process_test {
696 31     31 0 55 my $params = shift;
697 31 50       178 my $tp = $params->{test} or return;
698 0 0 0     0 return unless $tp->{SRC} or $tp->{XS} or $tp->{CLIB};
      0        
699              
700 0         0 canonize_array_split($tp->{$_}) for qw/TYPEMAPS BIN_DEPS/;
701              
702             my $array_merge = sub {
703 0   0 0   0 my $a1 = shift || [];
704 0   0     0 my $a2 = shift || [];
705 0         0 return [@$a1, @$a2];
706 0         0 };
707              
708 0         0 my $ldfrom = '$(OBJECT)';
709 0 0       0 $ldfrom .= ' '.module_so($params) unless $mac; # MacOSX doesn't allow for linking with bundles :(
710            
711 0   0     0 my $test_module_name = $tp->{NAME} || 'MyTest';
712              
713             my %args = (
714             NAME => $test_module_name,
715             VERSION => $tp->{VERSION} || '0.0.0',
716             ABSTRACT => "test module",
717             SRC => $tp->{SRC},
718             XS => $tp->{XS},
719 0 0       0 BIN_DEPS => $array_merge->([keys %{$params->{MODULE_INFO}{BIN_DEPS}||{}}], $tp->{BIN_DEPS}),
720             TYPEMAPS => $array_merge->($params->{TYPEMAPS}, $tp->{TYPEMAPS}),
721             CPLUS => $tp->{CPLUS} // $params->{CPLUS},
722             CC => $tp->{CC} || $params->{CC},
723             LD => $tp->{LD} || $params->{LD},
724             LDFROM => $ldfrom,
725             INC => string_merge($params->{MODULE_INFO}{ORIG}{INC}, $tp->{INC}),
726             CCFLAGS => string_merge($params->{MODULE_INFO}{ORIG}{CCFLAGS}, $tp->{CCFLAGS}),
727             DEFINE => string_merge($params->{DEFINE}, $tp->{DEFINE}),
728             LDDLFLAGS => string_merge($params->{MODULE_INFO}{ORIG}{LDDLFLAGS}, $tp->{LDDLFLAGS}),
729             LINK => string_merge($params->{MODULE_INFO}{ORIG}{LINK}, $tp->{LINK}),
730             XSOPT => string_merge($params->{XSOPT}, $tp->{XSOPT}),
731             PKG_CONFIG => $array_merge->($params->{PKG_CONFIG}, $tp->{PKG_CONFIG}),
732             LIBS => $params->{LIBS},
733             CLIB => $tp->{CLIB},
734             MAKEFILE => 'Makefile.test',
735             OPTIMIZE => merge_optimize($params->{OPTIMIZE}, "-O0", $tp->{OPTIMIZE}, $ENV{TEST_OPTIMIZE}),
736             PARSE_XS => $tp->{PARSE_XS} || $params->{PARSE_XS},
737 0   0     0 NO_MYMETA => 1,
      0        
      0        
      0        
      0        
738             _XSTEST => 1,
739             );
740              
741 0         0 my $mm_args = makemaker_args(%args);
742 0 0 0     0 return undef unless has_binary($mm_args) || $tp->{CLIB};
743            
744 0         0 push @{$params->{MODULE_INFO}{INSTALL_SKIP}}, "${test_module_name}[\\\\/]$test_module_name\\..+";
  0         0  
745              
746 0         0 my $make_params = '';
747 0 0       0 $make_params .= ' --no-print-directory' if $linux;
748 0         0 my $cmd = "\@\$(MAKE)$make_params -f Makefile.test";
749              
750 0         0 push @{$params->{postamble}},
  0         0  
751             '# --- XS::Install tests compilation section',
752             "ctest_object : ; $cmd object",
753             "ctest_ld : ctest_object \$(INST_DYNAMIC); $cmd",
754             'subdirs-test_dynamic :: ctest_object ctest_ld',
755             'ctest :: ctest_object ctest_ld',
756             "clean :: ; $cmd veryclean",
757             ;
758              
759             # can't transfer requirements to only TEST_REQUIRES because on target machine "perl Makefile.PL" will run before they get installed,
760             # and thus test's makemaker_args() will fail without binary dependency installed. We need to install it before Makefile.PL runs.
761 0 0       0 if (my $prereq = $mm_args->{PREREQ_PM}) {
762 0         0 my $creq = $params->{CONFIGURE_REQUIRES};
763 0         0 my $treq = $params->{TEST_REQUIRES};
764 0         0 foreach my $k (keys %$prereq) {
765 0 0       0 next if $k eq $THIS_MODULE;
766 0   0     0 $creq->{$k} //= $prereq->{$k};
767 0   0     0 $treq->{$k} //= $prereq->{$k};
768             }
769             }
770              
771 0         0 return $mm_args;
772             }
773              
774             sub process_test_makefile {
775 0     0 0 0 my $params = shift;
776 0         0 push @{$params->{postamble}}, 'object : $(OBJECT)';
  0         0  
777             }
778              
779             sub process_cmake_test {
780 31     31 0 108 my ($params, $cmake_params, $test) = @_;
781              
782 31         64 my $clibs = '';
783 31 50       150 my $clib = $params->{test}{CLIB} or return $cmake_params;
784 0 0       0 $clib = [$clib] unless ref($clib) eq 'ARRAY';
785 0 0       0 return $cmake_params unless @$clib;
786              
787 0   0     0 my $cflags = $test->{INC} || '';
788 0         0 _string_merge($cflags, $test->{CCFLAGS});
789 0         0 _string_merge($cflags, $test->{DEFINE});
790 0         0 _string_merge($cflags, $test->{OPTIMIZE});
791 0         0 $cflags =~ s/-o \$@//;
792              
793 0         0 foreach my $info (@$clib) {
794 0         0 my $cmake_target = $info->{CMAKE_TARGET};
795 0 0       0 next unless ($cmake_target);
796              
797 0         0 $cmake_params->{TARGETS}{$cmake_target} = "-fPIC $cflags";
798             }
799              
800 0         0 return $cmake_params;
801             }
802              
803             sub run_cmake {
804 0     0 0 0 my ($params, $cmake_params) = @_;
805              
806 0         0 my @options;
807 0         0 while (my ($target, $opts) = each(%{$cmake_params->{TARGETS}})) {
  0         0  
808 0         0 push @options, qq(-D${target}_COMP_OPTIONS="$opts");
809             }
810              
811 0         0 my $targets = join(';', keys %{$cmake_params->{TARGETS}});
  0         0  
812 0 0       0 push(@options, $cmake_params->{OPTIONS}) if $cmake_params->{OPTIONS};
813 0         0 my $options = join(' ', @options);
814              
815 0         0 return XS::Install::CMake::configure($cmake_params->{BUILD_DIR}, $cmake_params->{PROP_DIR}, $cmake_params->{MAIN_TARGET}, qq(-DCONF_TARGETS="$targets" $options));
816             }
817              
818             sub apply_CMAKE {
819 0     0 0 0 my ($params, $props) = @_;
820 0         0 my $bs = $params->{BIN_SHARE};
821 0         0 my $cmake = $props->{CMAKE_BIN};
822 0         0 my $make = '$(MAKE)';
823 0   0     0 $params->{INC} ||= '';
824 0         0 my $make_copy = "cmake_inc_copy :: cmake_install\n";
825 0         0 for my $i (@{$props->{INSTALL_INCLUDE}}) {
  0         0  
826 0   0     0 $bs->{INCLUDE} //= 1;
827 0         0 $make_copy .= "\t$cmake -E copy_directory $props->{CMAKE_TMP_INSTALL_DIR}/$i \$(INST_ARCHLIB)/\$(FULLEXT).x/i/\n";
828             }
829 0         0 for my $i (@{$props->{BUILD_INCLUDE}}) {
  0         0  
830 0         0 _string_merge($params->{INC}, "-I$i");
831 0         0 _string_merge($params->{MODULE_INFO}{ORIG}{INC}, "-I$i");
832 0 0       0 _string_merge($params->{test}{INC}, "-I$i") if $params->{test};
833             }
834 0         0 _uniq_list($props->{INC});
835 0         0 my @incs = map {"-I$_"} @{$props->{INC}};
  0         0  
  0         0  
836 0         0 _string_merge($params->{INC}, @incs);
837 0         0 _string_merge($params->{MODULE_INFO}{ORIG}{INC}, @incs);
838 0 0       0 _string_merge($params->{test}{INC}, @incs) if $params->{test};
839              
840 0 0       0 if ($bs) {
841 0         0 _string_merge($bs->{CCFLAGS}, @{$props->{CCFLAGS}});
  0         0  
842 0         0 _string_merge($bs->{DEFINE}, @{$props->{DEFINE}});
  0         0  
843 0         0 _string_merge($bs->{INC}, @incs);
844 0         0 _string_merge($bs->{LINK}, @{$props->{LIBS}});
  0         0  
845             }
846              
847 0         0 $params->{CCFLAGS} = string_merge($params->{CCFLAGS}, @{$props->{CCFLAGS}});
  0         0  
848 0         0 $params->{DEFINE} = string_merge($params->{DEFINE}, @{$props->{DEFINE}});
  0         0  
849 0         0 $params->{LINK} = string_merge($params->{LINK}, @{$props->{LIBS}});
  0         0  
850              
851 0         0 push @{$params->{postamble}}, $make_copy;
  0         0  
852 0         0 push @{$params->{postamble}}, "pm_to_blib : cmake_inc_copy";
  0         0  
853             }
854              
855             sub process_INSTALL_SKIP {
856 31     31 0 69 my $params = shift;
857 31         73 my $list = $params->{MODULE_INFO}{INSTALL_SKIP};
858 31 50 33     147 return unless $list && @$list;
859 0         0 my %hash = map {$_ => 1} @$list;
  0         0  
860 0         0 my $file = "INSTALL.SKIP";
861 0         0 my $lastc;
862 0 0       0 if (open my $fh, '<', $file) {
863 0         0 my @lines = <$fh>;
864 0 0       0 $lastc = substr($lines[-1], -1, 1) if @lines;
865 0         0 map {chomp} @lines;
  0         0  
866 0         0 delete $hash{$_} for @lines;
867 0         0 close $fh;
868             }
869 0 0       0 return unless %hash;
870 0 0       0 if (open my $fh, '>>', $file) {
871 0 0 0     0 print $fh "\n" if defined($lastc) && $lastc ne "\n" && $lastc ne "\r";
      0        
872 0         0 print $fh join("\n", keys %hash);
873 0         0 print $fh "\n";
874 0         0 close $fh;
875             }
876             }
877              
878             sub post_process {
879 31     31 0 49 my $params = shift;
880 31         53 my $postamble = $params->{postamble};
881 31         59 my $mi = $params->{MODULE_INFO};
882              
883 31 100       96 if (my $link = $params->{LINK}) {
884 3   50     31 my $dl = $params->{dynamic_lib} ||= {};
885 3         15 _string_merge($dl->{OTHERLDFLAGS}, $link);
886 3         16 $dl->{OTHERLDFLAGS} = _uniq_link($dl->{OTHERLDFLAGS});
887             }
888              
889 31 100       73 delete @$params{qw/C H OBJECT XS CCFLAGS LDFROM OPTIMIZE XSOPT/} unless has_binary($params);
890 31         189 delete @$params{qw/CPLUS PARSE_XS SRC MODULE_INFO _XSTEST CMAKE_PARAMS PKG_CONFIG LINK/};
891              
892             # convert array to hash for postamble
893 31         67 $params->{postamble} = {};
894 31         51 my $i = 0;
895 31         378 $params->{postamble}{++$i} = $_ for @$postamble;
896             }
897              
898             sub _merge_libs {
899 31     31   103 my ($params, $add_libs) = @_;
900 31 50 33     107 return unless $add_libs and @$add_libs;
901 0   0     0 my $libs = $params->{LIBS} || [];
902 0 0       0 $libs = [$libs] unless ref($libs) eq 'ARRAY';
903 0 0 0     0 if ($libs and @$libs) {
904 0         0 my @result;
905 0         0 foreach my $l1 (@$libs) {
906 0         0 foreach my $l2 (@$add_libs) {
907 0 0       0 push @result, $l2 ? "$l1 $l2" : $l1;
908             }
909             }
910 0         0 $params->{LIBS} = \@result;
911             }
912             else {
913 0         0 $params->{LIBS} = $add_libs;
914             }
915             }
916              
917             sub canonize_array {
918 250 100   250 0 804 if (!$_[0]) { $_[0] = [] }
  182 100       810  
919 9         23 elsif (ref($_[0]) ne 'ARRAY') { $_[0] = [$_[0]] }
920             }
921              
922             sub canonize_array_split {
923 250     250 0 647 canonize_array($_[0]);
924 250         393 @{$_[0]} = map { split ' ' } @{$_[0]};
  250         513  
  173         370  
  250         686  
925             }
926              
927             sub canonize_array_files {
928 91     91 0 263 canonize_array_split($_[0]);
929 91         148 @{$_[0]} = map { glob } @{$_[0]};
  91         269  
  166         2991  
  91         171  
930             }
931              
932             # returns version of binary module which was installed with XS::Install without loading it
933             sub binary_module_version {
934 31     31 0 69 my $module = shift;
935             # user might use his own module for it's Makefile.PL (very rare case but possible, for example this module does it)
936             # to avoid finding it, and find only installed pm, we must se if it has data dir (Module.x) in the same folder
937             # so we will just find the data folder and get the pm from there
938 31 50       120 my $ddir = XS::Install::Payload::data_dir($module) or return (0, "data dir for $module not found");
939 31         106 my $pm = $ddir;
940 31         193 $pm =~ s#\.x$#.pm#;
941 31 50       512 return (0, "no $pm found") unless -f $pm;
942 31         388 my $version = MM->parse_version($pm);
943 31 50       13326 return (0, "version from $pm cannot be parsed") unless $version;
944 31         122 return ($version, undef);
945             }
946              
947 86 100 50 86 0 238 sub has_c { return $_[0]->{C} && scalar(@{$_[0]->{C}}) ? 1 : 0 }
948 2 50 50 2 0 6 sub has_object { return $_[0]->{OBJECT} && scalar(@{$_[0]->{OBJECT}}) ? 1 : 0 }
949 2 50 50 2 0 18 sub has_xs { return $_[0]->{XS} && scalar(keys %{$_[0]->{XS}}) ? 1 : 0 }
950 2 50 50 2 0 10 sub has_ext { return $_[0]->{MODULE_INFO} && $_[0]->{MODULE_INFO}{STATIC_LIBS} && scalar(@{$_[0]->{MODULE_INFO}{STATIC_LIBS}}) ? 1 : 0 }
951 86   33 86 0 188 sub has_binary { return has_c($_[0]) || has_object($_[0]) || has_xs($_[0]) || has_ext($_[0]) }
952              
953             sub merge_optimize {
954 31     31 0 142 my $to = shift;
955 31   50     87 $to ||= '';
956 31         251 my @singleton = (qr/-O[0-9]/, qr/-g[0-9]?/);
957 31         78 foreach my $from (@_) {
958 62 50       135 next unless $from;
959 62         172 foreach my $tok (split ' ', $from) {
960 124         198 foreach my $qr (@singleton) {
961 248 100       2955 next unless $tok =~ /^$qr$/;
962 62         638 $to =~ s/(^|\s)$qr(\s|$)/ /g;
963             }
964 124         356 $to .= " $tok";
965             }
966             }
967 31         143 $to =~ s/^\s+//;
968 31         133 $to =~ s/\s+$//;
969 31         81 $to =~ s/\s{2,}/ /g;
970 31         135 return $to;
971             }
972              
973             sub _install {
974 22     22   87 my ($params, $map, $path) = @_;
975 22 100       52 return unless %$map;
976 16         34 my $instroot = _instroot($params);
977 16   50     51 my $pm = $params->{PM} ||= {};
978 16         74 while (my ($source, $dest) = each %$map) {
979 33         97 my $instpath = "$instroot/\$(FULLEXT).x/$path/$dest";
980 33         101 $instpath =~ s#[/\\]{2,}#/#g;
981 33         133 $pm->{$source} = $instpath;
982             }
983             }
984              
985 47 100   47   151 sub _instroot { return has_binary($_[0]) ? '$(INST_ARCHLIB)' : '$(INST_LIB)' }
986              
987             sub module_so {
988 0     0 0 0 my $params = shift;
989 0 0       0 return undef unless has_binary($params);
990 0         0 return _instroot($params).'/auto/'._pkg_slash($params->{NAME}).'/'.module_so_file($params);
991             }
992              
993             sub module_so_file {
994 4     4 0 7 my $params = shift;
995 4 50       9 return undef unless has_binary($params);
996 4         18 my @modparts = split(/::/, $params->{NAME});
997 4         8 my $modfname = $modparts[-1];
998 4 50       12 $modfname = DynaLoader::mod2fname(\@modparts) if defined &DynaLoader::mod2fname;
999 4   33     69 return $modfname.'.'.($params->{DLEXT} || $Config{dlext});
1000             }
1001              
1002             sub _sync {
1003 11     11   129 no strict 'refs';
  11         57  
  11         10879  
1004 31     31   75 my $from = 'MYSOURCE';
1005 31         64 my $to = 'MY';
1006 31         51 foreach my $method (keys %{"${from}::"}) {
  31         193  
1007 0 0       0 next unless defined &{"${from}::$method"};
  0         0  
1008 0         0 *{"${to}::$method"} = \&{"${from}::$method"};
  0         0  
  0         0  
1009             }
1010             }
1011              
1012             sub _scan_files {
1013 131     131   369 my ($mask, $dir) = @_;
1014 131 100       8474 return grep {_is_file_ok($_)} glob($mask) unless $dir;
  156         395  
1015              
1016 78         288 my @list = grep {_is_file_ok($_)} glob(join(' ', map {"$dir/$_"} split(' ', $mask)));
  89         318  
  215         9358  
1017              
1018 78 50       2185 opendir(my $dh, $dir) or die "Could not open dir '$dir' for scanning: $!";
1019 78         1161 while (my $entry = readdir $dh) {
1020 315 100       1581 next if $entry =~ /^\./;
1021 159         386 my $path = "$dir/$entry";
1022 159 100       2390 next unless -d $path;
1023 30         159 push @list, _scan_files($mask, $path);
1024             }
1025 78         821 closedir $dh;
1026              
1027 78         580 return @list;
1028             }
1029              
1030             sub _is_file_ok {
1031 245     245   442 my $file = shift;
1032 245 100       2883 return unless -f $file;
1033 242 50       821 return if $file =~ /\#/;
1034 242 50       451 return if $file =~ /~$/; # emacs temp files
1035 242 50       444 return if $file =~ /,v$/; # RCS files
1036 242 50       435 return if $file =~ m{\.swp$}; # vim swap files
1037 242         1024 return 1;
1038             }
1039              
1040             sub _process_map {
1041 18     18   42 my ($map, $mask) = @_;
1042 18         76 foreach my $source (keys %$map) {
1043 18   66     57 my $dest = $map->{$source} || $source;
1044 18 100       236 if (-f $source) {
1045 11 100       55 $dest .= $source if $dest =~ m#[/\\]$#;
1046 11         26 $dest =~ s#[/\\]{2,}#/#g;
1047 11         36 $dest =~ s#^[/\\]+##;
1048 11         28 $map->{$source} = $dest;
1049 11         25 next;
1050             }
1051 7 50       89 next unless -d $source;
1052              
1053 7         21 delete $map->{$source};
1054 7         18 my @files = _scan_files($mask, $source);
1055 7         20 foreach my $file (@files) {
1056 18         29 my $dest_file = $file;
1057 18         109 $dest_file =~ s/^$source//;
1058 18         42 $dest_file = "$dest/$dest_file";
1059 18         63 $dest_file =~ s#[/\\]{2,}#/#g;
1060 18         38 $dest_file =~ s#^[/\\]+##;
1061 18         55 $map->{$file} = $dest_file;
1062             }
1063             }
1064             }
1065              
1066             sub _uniq_list {
1067 128     128   203 my $list = shift;
1068 128         178 my %uniq;
1069 128         243 @$list = grep { !$uniq{$_}++ } @$list;
  572         1603  
1070             }
1071              
1072             sub _string_merge {
1073 269 100   269   1828 return unless $_[1];
1074 113   100     586 $_[0] ||= '';
1075 113 100       457 $_[0] .= $_[0] ? " $_[1]" : $_[1];
1076             }
1077              
1078             sub string_merge {
1079 62     62 0 137 my $s = shift;
1080 62   100     276 $s //= '';
1081 62         137 for my $val (@_) {
1082 62 100 66     395 next unless defined($val) && length($val);
1083 31 50       111 if (!$s) { $s = $val }
  31         73  
1084 0         0 else { $s .= " $val"; }
1085             }
1086 62         199 return $s;
1087             }
1088              
1089             sub c2obj_file {
1090 179     179 0 272 my $file = shift;
1091 179         581 $file =~ s/\.[^.]+$//;
1092 179         411 return $file.'$(OBJ_EXT)';
1093             }
1094              
1095             {
1096             package
1097             MY;
1098 11     11   164 use Config;
  11         42  
  11         1164  
1099              
1100             my $gcc_compliant = $Config{cc} =~ /\b(gcc|clang)\b/i ? 1 : 0;
1101              
1102             sub init_methods {
1103 11     11   113 no warnings 'redefine';
  11         48  
  11         16475  
1104              
1105             # change "subdirs-test*" rule type from "::" to ":" as GNU make has a bug and can't do its deps in parallel
1106             sub _fix_subdirs {
1107 0     0   0 my $s = shift;
1108 0         0 $s =~ s/^((subdirs-test(?:_dynamic|_static)?\s*)+)::/$1:/mg;
1109 0         0 return $s;
1110             }
1111              
1112             *postamble = sub {
1113 0     0   0 my $self = shift;
1114 0         0 my %args = @_;
1115              
1116 0         0 my @list;
1117 0         0 my $i = 1;
1118 0         0 while (1) {
1119 0 0       0 last unless exists $args{$i};
1120 0         0 push @list, $args{$i};
1121 0         0 ++$i;
1122             }
1123              
1124 0         0 return _fix_subdirs(join("\n\n", @list));
1125 0     0   0 };
1126              
1127 0     0   0 *test = sub { return _fix_subdirs(shift->SUPER::test(@_)) };
  0         0  
1128              
1129 0 0       0 if ($fix_bsd_make_j) { # bsd's make has a bug: wrong value of $* when building in parallel, we use $< instead
1130             *c_o = sub {
1131 0     0   0 my $self = shift;
1132 0         0 my $ret = $self->SUPER::c_o(@_);
1133 0         0 $ret =~ s/\$\*\.c(c|pp|xx)?[ \t]*$/\$
1134 0         0 return $ret;
1135 0         0 };
1136             }
1137              
1138 0 0       0 if ($win32) {
1139             *dynamic_lib = sub {
1140 0     0   0 my ($self, %attribs) = @_;
1141 0         0 my $code = $self->SUPER::dynamic_lib(%attribs);
1142              
1143 0 0       0 unless ($gcc_compliant) {
1144 0         0 warn(
1145             "$THIS_MODULE: to maintain UNIX-like shared library behaviour on windows (export all symbols by default), we need gcc-compliant linker. ".
1146             "$THIS_MODULE-dependant modules should only be installed on perls with MinGW shell (like strawberry perl), or at least having gcc compiler. ".
1147             "I will continue, but this module's binary dependencies may not work."
1148             );
1149 0         0 return $code;
1150             }
1151 0 0       0 return $code unless $code;
1152              
1153             # remove .def-related from code, remove double DLL build, remove dll.exp from params, add export all symbols param.
1154 0   0     0 my $DLLTOOL = $Config{dlltool} || 'dlltool';
1155 0         0 my (@out, $last_ld);
1156 0 0       0 map { $last_ld = $_ if /\$\(LD\)\s/ } split /\n/, $code;
  0         0  
1157 0         0 foreach my $line (split /\n/, $code) {
1158 0 0       0 next if $line =~ /$DLLTOOL/; # drop dlltool calls (we dont need .def file)
1159 0 0       0 if ($line =~ /\$\(LD\)\s/) {
1160 0 0       0 next if $line ne $last_ld;
1161 0         0 $line =~ s/\$\(LD\)\s/\$(LD) -Wl,--export-all-symbols /;
1162 0         0 $line =~ s/\bdll\.exp\b//;
1163             }
1164 0         0 $line =~ s/\$\(EXPORT_LIST\)//g; # remove .def from target dependency
1165 0         0 push @out, $line;
1166             }
1167              
1168 0         0 $code = join("\n", @out);
1169 0         0 return $code;
1170 0         0 };
1171              
1172             *dlsyms = sub {
1173 0     0   0 my ($self, %attribs) = @_;
1174 0 0       0 return '' if $gcc_compliant; # our dynamic_lib target doesn't need any .def files with gcc
1175 0         0 return $self->SUPER::dlsyms(%attribs);
1176 0         0 };
1177             };
1178             }
1179             }
1180              
1181             sub _require_makemaker {
1182 0 0   0   0 unless ($INC{'ExtUtils/MakeMaker.pm'}) {
1183 0         0 require ExtUtils::MakeMaker;
1184 0         0 ExtUtils::MakeMaker->import();
1185             }
1186             }
1187              
1188             sub not_available {
1189 0     0 1 0 my $msg = shift;
1190 0         0 die "OS unsupported: $msg\n";
1191             }
1192              
1193             sub _get_cplusplus {
1194 0     0   0 my ($cpp, $minstd) = @_;
1195 0   0     0 $cpp ||= 'c++'; # exists on most platforms/compilers
1196              
1197             # check compiler existance
1198 0         0 my $v_out = `$cpp -v 2>&1`;
1199 0 0       0 not_available("C++ compiler not available") unless defined $v_out;
1200              
1201             #check if C++ compiler supports -std=XXX
1202 0         0 mkdir 'tmp';
1203 0         0 my $tmpfile = 'tmp/__xs_install_check_cpp.cc';
1204 0         0 my $outfile = 'tmp/__xs_install_check_cpp.out';
1205 0 0       0 if (open my $fh, '>', $tmpfile) {
1206 0         0 print $fh "int main () { return 0; }\n";
1207 0         0 close $fh;
1208 0         0 unlink $outfile;
1209 0         0 `$cpp -c -std=c++$minstd -o $outfile $tmpfile 2>&1`;
1210 0         0 my $success = -f $outfile;
1211 0         0 unlink $tmpfile, $outfile;
1212 0         0 rmdir 'tmp';
1213 0 0       0 not_available("C++ compiler does not support -std=c++$minstd") unless $success;
1214             }
1215              
1216             #check exceptions
1217             not_available(
1218 0 0       0 "SJLJ compiler detected\n".
1219             "***************************************************************\n".
1220             "You are using c++ compiler with SJLJ exceptions enabled.\n".
1221             "It makes it impossible to use C++ exceptions and perl together.\n".
1222             "You need to use compiler with DWARF2 or SEH exceptions configured.\n".
1223             "If you are using Strawberry Perl, install Strawberry 5.26 or higher\n".
1224             "where they use mingw with SEH exceptions.\n".
1225             "***************************************************************"
1226             ) if $v_out =~ /--enable-sjlj-exceptions/;
1227              
1228 0         0 return $cpp;
1229             }
1230              
1231             sub _pkg_slash {
1232 62     62   101 my $pkg = shift;
1233 62         138 $pkg =~ s#::#/#g;
1234 62         250 return $pkg;
1235             }
1236              
1237             sub _pkg_last {
1238 0     0   0 my $pkg = shift;
1239 0 0       0 return unless $pkg =~ /([^:]+)$/;
1240 0         0 return $1;
1241             }
1242              
1243 31     31   266 sub _pkg_file { return _pkg_slash(shift).'.pm' }
1244              
1245             sub _split_path_args {
1246 3     3   6 my $str = shift;
1247              
1248 3         16 my $simple_arg = qr/[^"' \t]+/;
1249 3         10 my $dquoted_arg = qr/"([^"]+|\\")*"/;
1250 3         9 my $quoted_arg = qr/'([^']+|\\')*'/;
1251              
1252 3         5 my @args;
1253 3         124 push @args, $1 while $str =~ s/^\s*($simple_arg|$dquoted_arg|$quoted_arg)(\s+|$)//g;
1254              
1255 3         18 return @args;
1256             }
1257              
1258             sub _uniq_link {
1259 3     3   7 my $link = shift;
1260 3         10 my @args = _split_path_args($link);
1261 3         6 my %uniq;
1262 3         8 @args = grep { !$uniq{$_}++ } @args;
  8         39  
1263 3         17 return join ' ', @args;
1264             }
1265              
1266             1;