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   922673 use strict;
  11         120  
  11         384  
3 11     11   58 use warnings;
  11         21  
  11         319  
4 11     11   69 use Config;
  11         21  
  11         558  
5 11     11   66 use Cwd qw/getcwd abs_path/;
  11         21  
  11         773  
6 11     11   83 use Exporter 'import';
  11         30  
  11         379  
7 11     11   11279 use ExtUtils::MakeMaker;
  11         1305089  
  11         1627  
8 11     11   5480 use XS::Loader;
  11         33  
  11         460  
9 11     11   5092 use XS::Install::Deps;
  11         28  
  11         427  
10 11     11   85 use XS::Install::Util;
  11         26  
  11         246  
11 11     11   59 use XS::Install::Payload;
  11         23  
  11         210  
12 11     11   5535 use XS::Install::CMake;
  11         33  
  11         385  
13 11     11   7839 use Data::Dumper;
  11         73609  
  11         102907  
14              
15             our $VERSION = '1.3.5';
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 135536 my $params = ref($_[0]) eq 'HASH' ? $_[0] : {@_};
59 31         289 _sync();
60 31 50       125 die "You must define a NAME param" unless $params->{NAME};
61              
62 31         168 pre_process($params);
63 31         133 process_FROM($params);
64 31         157 process_REQUIRES($params);
65 31         121 process_BIN_DEPS($params);
66 31         117 process_PARSE_XS($params);
67 31         135 process_CPLUS($params);
68 31         120 process_CCFLAGS($params);
69 31         168 $params->{OPTIMIZE} = merge_optimize($Config{optimize}, '-O2', $params->{OPTIMIZE});
70 31         188 process_PKG_CONFIG($params);
71 31         159 process_SANITIZE($params);
72 31         129 process_CLIB($params);
73 31         139 process_binary($params);
74 31         185 process_PM($params);
75 31         152 process_PAYLOAD($params);
76 31         147 process_LD($params);
77              
78 31         93 my $test_mm_args;
79 31 50       112 if ($params->{_XSTEST}) {
80 0         0 process_test_makefile($params);
81             } else {
82 31         128 $test_mm_args = process_test($params);
83 31         160 my $cmake_params = process_cmake_test($params, $params->{CMAKE_PARAMS}, $test_mm_args);
84 31 50       104 run_cmake($params, $cmake_params, $test_mm_args) if ($cmake_params);
85             }
86 31         117 process_BIN_SHARE($params);
87 31         116 attach_BIN_DEPENDENT($params);
88 31         121 warn_BIN_DEPENDENT($params);
89 31         117 fix_flags($params);
90              
91 31         124 process_INSTALL_SKIP($params);
92 31         104 post_process($params);
93              
94 31 100       144 return ($params, $test_mm_args) if wantarray();
95 20         243 return $params;
96             }
97              
98             sub pre_process {
99 31     31 0 75 my $params = shift;
100              
101 31         90 my $postamble = $params->{postamble};
102 31 50       116 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     269 $postamble ||= [];
109 31         86 $params->{postamble} = $postamble;
110              
111 31   50     188 $params->{clean} ||= {};
112 31   50     213 $params->{clean}{FILES} ||= '';
113              
114 31 50 33     234 if (my $comp = ($ENV{COMPILER} || $ENV{CC})) {
115 0         0 $params->{CC} = $comp;
116             }
117              
118 31 50       118 if (my $opt = $ENV{OPTIMIZE}) {
119 31         85 $params->{OPTIMIZE} = $opt;
120             }
121              
122 31         517 canonize_array_split($params->{TYPEMAPS});
123 31         128 canonize_array_split($params->{PARSE_XS});
124              
125 31   50     198 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     515 INSTALL_SKIP => [],
137             };
138              
139 31   33     264 $params->{UNIQUE_LIBNAME} //= $win32;
140 31 50       120 *DynaLoader::mod2fname = \&XS::Loader::mod2fname_unique if delete $params->{UNIQUE_LIBNAME};
141              
142 31 50 66     147 $params->{BIN_SHARE} = {} if $params->{BIN_SHARE} && !ref($params->{BIN_SHARE});
143 31 50 0     140 $params->{BIN_SHARE}{LINK} //= $params->{LINK} if $params->{BIN_SHARE} && $params->{LINK};
      66        
144             }
145              
146             sub process_FROM {
147 31     31 0 66 my $params = shift;
148 31 50       112 my $module = $params->{NAME} or die "You must define a NAME param";
149              
150 31 100       106 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         115 my $pm = 'lib/'._pkg_file($module);
156 31         98 my $pod = 'lib/'._pkg_slash($module).'.pod';
157              
158 31 50 66     261 $params->{VERSION_FROM} ||= $pm unless $params->{VERSION};
159 31 50 66     2101 $params->{ABSTRACT_FROM} ||= (-f $pod) ? $pod : $pm unless $params->{ABSTRACT};
    50          
160             }
161              
162             sub process_REQUIRES {
163 31     31 0 70 my $params = shift;
164              
165 31   50     200 $params->{CONFIGURE_REQUIRES} ||= {};
166 31   50     200 $params->{BUILD_REQUIRES} ||= {};
167              
168 31   50     156 $params->{TEST_REQUIRES} ||= {};
169 31   50     171 $params->{TEST_REQUIRES}{'Test::Simple'} ||= '0.96';
170 31   50     181 $params->{TEST_REQUIRES}{'Test::More'} ||= 0;
171 31   50     159 $params->{TEST_REQUIRES}{'Test::Deep'} ||= 0;
172              
173 31   50     233 $params->{PREREQ_PM} ||= {};
174              
175 31 50       114 unless ($params->{NAME} eq $THIS_MODULE) { # skip when building XS::Install itself
176 31   33     213 $params->{CONFIGURE_REQUIRES}{$THIS_MODULE} ||= $VERSION;
177 31   33     149 $params->{PREREQ_PM }{$THIS_MODULE} ||= $VERSION;
178             }
179             }
180              
181             sub process_PM {
182 31     31 0 66 my $params = shift;
183 31 50       100 return if $params->{PM}; # user-defined value overrides defaults
184              
185 31         107 my $instroot = _instroot($params);
186 31         143 my @name_parts = split '::', $params->{NAME};
187 31   50     241 $params->{PMLIBDIRS} ||= ['lib', $name_parts[-1]];
188 31         81 my $pm = $params->{PM} = {};
189              
190 31         59 foreach my $dir (@{$params->{PMLIBDIRS}}) {
  31         152  
191 62 100       941 next unless -d $dir;
192 31         149 foreach my $file (_scan_files('*.pm *.pl *.pod', $dir)) {
193 58         125 my $rel = $file;
194 58         499 $rel =~ s/^$dir//;
195 58         181 my $instpath = "$instroot/$rel";
196 58         269 $instpath =~ s#[/\\]{2,}#/#g;
197 58         259 $pm->{$file} = $instpath;
198             }
199             }
200             }
201              
202             sub process_PAYLOAD {
203 31     31 0 84 my $params = shift;
204 31 100       137 my $payload = delete $params->{PAYLOAD} or return;
205 10         28 _process_map($payload, '*');
206 10         32 _install($params, $payload, 'payload');
207             }
208              
209             sub process_BIN_DEPS {
210 31     31 0 69 my $params = shift;
211 31         91 my $bin_deps = delete $params->{BIN_DEPS};
212 31         92 canonize_array_split($bin_deps);
213 31 50       128 push @$bin_deps, $THIS_MODULE unless $params->{NAME} eq $THIS_MODULE;
214              
215 31         64 my $typemaps = $params->{TYPEMAPS};
216 31         68 $params->{TYPEMAPS} = [];
217 31         63 my $seen = {};
218 31         138 _apply_BIN_DEPS($params, $_, $seen) for @$bin_deps;
219 31         75 push @{$params->{TYPEMAPS}}, @$typemaps;
  31         129  
220             }
221              
222             sub _apply_BIN_DEPS {
223 31     31   89 my ($params, $module, $seen) = @_;
224 31         59 my $stop_sharing;
225 31 50       126 $stop_sharing = 1 if $module =~ s/^-//;
226              
227 31 50       138 return if $seen->{$module}++;
228              
229 31         150 my ($installed_version, $failure) = binary_module_version($module);
230 31 50       91 die "[XS::Install] binary dependency '$module' must be installed to proceed (details: $failure)\n"
231             unless $installed_version;
232 31   33     128 $params->{CONFIGURE_REQUIRES}{$module} ||= $installed_version;
233 31   33     107 $params->{PREREQ_PM}{$module} ||= $installed_version;
234 31         117 $params->{MODULE_INFO}{BIN_DEPS}{$module} = $installed_version;
235 31 50 50     100 push @{$params->{MODULE_INFO}{VISIBLE_BIN_DEPS} ||= []}, $module unless $stop_sharing;
  31         247  
236              
237 31 50       128 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         77 my $shared_list = $params->{MODULE_INFO}{SHARED_LIBS};
242 31         70 my $module_path = $module;
243 31         150 $module_path =~ s#::#/#g;
244 31 50       224 die "SHOULDN'T EVER HAPPEN" unless $module =~ /([^:]+)$/;
245 31         99 my $module_last_name = $1;
246 31         127 foreach my $dir (@INC) {
247 341         1052 my $lib_path = "$dir/auto/$module_path/";
248 341 50       748 if ($info->{FILE}) {
249 0         0 $lib_path .= $info->{FILE};
250             } else { # DEPRECATED
251 341         2001 $lib_path .= $module_last_name.".".$Config{dlext};
252             }
253              
254 341 50       7633 next unless -f $lib_path;
255 0         0 push @$shared_list, abs_path($lib_path);
256 0         0 last;
257             }
258              
259 31 50       137 if ($info->{INCLUDE}) {
260 31         168 my $incdir = XS::Install::Payload::include_dir($module);
261 31         243 _string_merge($params->{INC}, "-I$incdir");
262             }
263              
264 31         152 _string_merge($params->{INC}, $info->{INC});
265 31         138 _string_merge($params->{CCFLAGS}, $info->{CCFLAGS});
266 31         130 _string_merge($params->{LDDLFLAGS}, $info->{LDDLFLAGS});
267 31         121 _string_merge($params->{LINK}, $info->{LINK});
268 31         132 _string_merge($params->{DEFINE}, $info->{DEFINE});
269 31         116 _string_merge($params->{XSOPT}, $info->{XSOPT});
270              
271 31         159 _merge_libs($params, $info->{LIBS});
272              
273 31 50       110 if (my $passthrough = $info->{PASSTHROUGH}) {
274 0         0 _apply_BIN_DEPS($params, $_, $seen) for @$passthrough;
275             }
276              
277 31 50       95 if (my $typemaps = $info->{TYPEMAPS}) {
278 31         109 my $tm_dir = XS::Install::Payload::typemap_dir($module);
279 31         123 foreach my $typemap (@$typemaps) {
280 31         155 my $tmfile = "$tm_dir/$typemap";
281 31         167 $tmfile =~ s#[/\\]{2,}#/#g;
282 31   50     59 push @{$params->{TYPEMAPS} ||= []}, $tmfile;
  31         190  
283             }
284             }
285              
286 31 0 0     93 $params->{CPLUS} = $info->{CPLUS} if $info->{CPLUS} and (!$params->{CPLUS} or $params->{CPLUS} < $info->{CPLUS});
      33        
287              
288 31 50       121 if (my $parsexs = $info->{PARSE_XS}) {
289 31   50     72 push @{$params->{PARSE_XS}||=[]}, @$parsexs;
  31         168  
290             }
291             }
292              
293             sub process_PARSE_XS { # inject ParseXS plugins into xsubpp
294 31     31 0 72 my $params = shift;
295 31         89 my $list = $params->{PARSE_XS};
296 31 50       94 return unless @$list;
297 31         119 _uniq_list($list);
298 31         85 my $inc = join ' ', map { "-M$_" } @$list;
  31         161  
299 31         86 push @{$params->{postamble}}, "XSUBPPRUN = \$(PERLRUN) -Ilib $inc \$(XSUBPP)";
  31         129  
300             }
301              
302             sub process_binary {
303 31     31 0 67 my $params = shift;
304              
305 31 50 66     304 $params->{XS} ||= $params->{_XSTEST} ? [] : [_scan_files($xs_mask)];
306 31 50 66     266 $params->{C} ||= $params->{_XSTEST} ? [] : [_scan_files($c_mask)];
307              
308 31         191 canonize_array_split($params->{SRC});
309              
310 31 100       151 if (ref($params->{XS}) ne 'HASH') {
311 29         151 canonize_array_files($params->{XS});
312 29         58 $params->{XS} = { map {$_ => undef} @{$params->{XS}} };
  74         259  
  29         93  
313             }
314              
315 31         119 my %xsi;
316 31         107 foreach my $xsfile (keys %{$params->{XS}}, map { _scan_files($xs_mask, $_) } @{$params->{SRC}}) {
  31         140  
  5         15  
  31         115  
317 77         182 my $cfile = $params->{XS}{$xsfile};
318 77         116 my $suffix;
319 77 100       188 unless ($cfile) {
320 76 50       205 my $cext = $params->{CPLUS} ? 'cc' : 'c';
321 76 50       349 if ($xsfile =~ /\.xs$/) {
322 76         285 $cfile = $xsfile;
323 76         413 $cfile =~ s/\.xs$/_xsgen.$cext/;
324 76         170 $suffix = "_xsgen.$cext";
325             } else {
326 0         0 $cfile = "$xsfile.$cext";
327             }
328 76         176 $params->{XS}{$xsfile} = $cfile;
329             }
330 77 100       182 unless ($suffix) {
331 1         3 $suffix = $cfile;
332 1         8 $suffix =~ s/^[^.]+//;
333             }
334              
335 77   50     345 my $xsi_deps = XS::Install::Deps::find_xsi_deps([$xsfile])->{$xsfile} || [];
336 77         233 map { $xsi{$_} = $xsfile } @$xsi_deps;
  0         0  
337              
338 77         393 push @{$params->{postamble}}, "$cfile : $xsfile @$xsi_deps \$(FIRST_MAKEFILE)\n".
  77         657  
339             "\t\$(XSUBPPRUN) \$(XSPROTOARG) \$(XSUBPPARGS) -csuffix $suffix \$(XSUBPP_EXTRA_ARGS) $xsfile > ${xsfile}c\n".
340             "\t\$(MV) ${xsfile}c $cfile";
341             }
342              
343 31         143 canonize_array_files($params->{C});
344 31         65 push @{$params->{C}}, _scan_files($c_mask, $_) for @{$params->{SRC}};
  31         126  
  5         16  
345 31         65 my @cdeps_list = (@{$params->{C}}, keys(%{$params->{XS}}), keys(%xsi));
  31         79  
  31         176  
346 31         65 push @{$params->{C}}, values %{$params->{XS}};
  31         98  
  31         122  
347 31         133 _uniq_list($params->{C});
348 31         99 _uniq_list(\@cdeps_list);
349              
350             my $cdeps = XS::Install::Deps::find_header_deps({
351             files => \@cdeps_list,
352             headers => ['./'],
353 31         398 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         253 canonize_array_files($params->{OBJECT});
358 31         72 foreach my $cfile (@{$params->{C}}) {
  31         91  
359 179         348 my $ofile = c2obj_file($cfile);
360 179         271 push @{$params->{OBJECT}}, $ofile;
  179         359  
361              
362 179         335 my $deps = delete $cdeps->{$cfile};
363 179 50 66     659 push @{$params->{postamble}}, "$ofile : @$deps" if $deps && @$deps;
  0         0  
364             }
365 31         107 _uniq_list($params->{OBJECT});
366              
367             # process XS & XSI header deps
368 31         114 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         55 foreach my $xsfile (keys %{$params->{XS}}) {
  31         105  
374 77         134 my $deps = delete $cdeps->{$xsfile};
375 77 50 33     357 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         72 delete $params->{H}; # prevent MM from making O_FILES depend on all H_FILES
383              
384 31         172 $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 67 my $params = shift;
436 31         74 my $clibs = '';
437 31 50       105 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 68 my $params = shift;
486 31         148 canonize_array_split($params->{PKG_CONFIG});
487 31         85 my $pkgs = $params->{PKG_CONFIG};
488              
489 31         66 my @bin_share_auto;
490 31         85 for my $pkg (@$pkgs) {
491 3 100       17 push @bin_share_auto, $pkg unless $pkg =~ s/^\s*-//;
492             }
493              
494 31         116 set_pkg_config($params, $pkgs);
495              
496 31 100       119 my $bin_share = $params->{BIN_SHARE} or return;
497 4         15 my $bin_share_pkgs = delete $bin_share->{PKG_CONFIG};
498 4         30 canonize_array_split($bin_share_pkgs);
499 4         20 set_pkg_config($bin_share, [@bin_share_auto, @$bin_share_pkgs]);
500             }
501              
502             sub set_pkg_config {
503 35     35 0 93 my ($params, $pkgs) = @_;
504 35 100       111 return unless @$pkgs;
505 6         929 require XS::Install::PkgConfigFixed;
506              
507 6         32 for my $pkg (@$pkgs) {
508 6         62 my $res = PkgConfig->find($pkg);
509 6 50       7803 warn $res->errmsg if $res->errmsg;
510 6         78 my @ccargs = $res->get_cflags;
511              
512 6         685 _string_merge($params->{INC}, join ' ', grep /^-I/, @ccargs);
513 6         70 _string_merge($params->{CCFLAGS}, join ' ', grep !/^-I/, @ccargs);
514 6         50 _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       113 my $bin_share = delete $params->{BIN_SHARE} or return;
521 4 50       17 return unless %$bin_share;
522 4 50       25 return if $params->{_XSTEST};
523              
524 4   100     32 my $typemaps = delete($bin_share->{TYPEMAPS}) || {};
525 4         21 _process_map($typemaps, $map_mask);
526 4         22 _install($params, $typemaps, 'tm');
527 4 100       19 $bin_share->{TYPEMAPS} = [values %$typemaps] if scalar keys %$typemaps;
528              
529 4   100     19 my $include = delete($bin_share->{INCLUDE}) || {};
530 4 50       22 if ($include == 1) {
531 0         0 $bin_share->{INCLUDE} = 1;
532             } else {
533 4         15 _process_map($include, $h_mask);
534 4         13 _install($params, $include, 'i');
535 4 100       16 $bin_share->{INCLUDE} = 1 if scalar(keys %$include);
536             }
537              
538 4 50 66     26 $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       16 if (my $vinfo = $params->{MODULE_INFO}{BIN_DEPS}) {
545 4 50       61 $bin_share->{BIN_DEPS} = $vinfo if %$vinfo;
546             }
547              
548 4 50 33     20 $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       17 return unless %$bin_share;
551              
552 4 50       16 if (my $vbd = $params->{MODULE_INFO}{VISIBLE_BIN_DEPS}) {
553 4         12 my $pt =
554             _uniq_list($vbd);
555 4         19 $bin_share->{PASSTHROUGH} = $vbd;
556             }
557              
558 4         13 $bin_share->{LOADABLE} = has_binary($params);
559              
560 4 50 0     28 $bin_share->{CPLUS} //= $params->{CPLUS} if $params->{CPLUS};
561 4         17 $bin_share->{FILE} = module_so_file($params);
562              
563             # generate info file
564 4         275 mkdir 'blib';
565 4         23 my $infopath = 'blib/info';
566 4         38 XS::Install::Util::module_info_write($infopath, $bin_share);
567 4         34 _install($params, {$infopath => 'info'}, '');
568             }
569              
570             sub attach_BIN_DEPENDENT {
571 31     31 0 79 my $params = shift;
572 31 50       61 my @deps = keys %{$params->{MODULE_INFO}{BIN_DEPS} || {}};
  31         211  
573 31 50       93 return unless @deps;
574              
575 31         58 push @{$params->{postamble}}, "sync_bin_deps:\n".
  31         242  
576             "\t\$(PERL) -M${THIS_MODULE}::Util -e '${THIS_MODULE}::Util::cmd_sync_bin_deps()' $params->{NAME} @deps";
577 31         54 push @{$params->{postamble}}, "install :: sync_bin_deps";
  31         100  
578             }
579              
580             sub warn_BIN_DEPENDENT {
581 31     31 0 72 my $params = shift;
582 31 50       95 return unless $params->{VERSION_FROM};
583 31         70 my $module = $params->{NAME};
584 31 50       96 return if $module eq $THIS_MODULE;
585 31 50       103 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 64 my $params = shift;
603 31 50       138 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 66 my $params = shift;
640 31 50       96 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 81 my $params = shift;
656 31         188 $params->{CCFLAGS} = string_merge($params->{CCFLAGS}, $Config{ccflags});
657 31 50       118 _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 59 my $params = shift;
662 31         136 _string_merge($params->{CCFLAGS}, '-o $@');
663              
664 31 50       147 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 67 my $params = shift;
673              
674 31   50     212 $params->{LDFROM} ||= '$(OBJECT)';
675              
676             {
677 31         65 my $str = join(' ', @{$params->{MODULE_INFO}{STATIC_LIBS}});
  31         56  
  31         144  
678 31 50       96 $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       92 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         381 my $cfg_lddlflags = $Config{lddlflags};
692 31 50 50     334 $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 57 my $params = shift;
697 31 50       121 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 116 my ($params, $cmake_params, $test) = @_;
781              
782 31         71 my $clibs = '';
783 31 50       163 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 76 my $params = shift;
857 31         90 my $list = $params->{MODULE_INFO}{INSTALL_SKIP};
858 31 50 33     174 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 56 my $params = shift;
880 31         61 my $postamble = $params->{postamble};
881 31         59 my $mi = $params->{MODULE_INFO};
882              
883 31 100       99 if (my $link = $params->{LINK}) {
884 3   50     30 my $dl = $params->{dynamic_lib} ||= {};
885 3         18 _string_merge($dl->{OTHERLDFLAGS}, $link);
886 3         22 $dl->{OTHERLDFLAGS} = _uniq_link($dl->{OTHERLDFLAGS});
887             }
888              
889 31 100       81 delete @$params{qw/C H OBJECT XS CCFLAGS LDFROM OPTIMIZE XSOPT/} unless has_binary($params);
890 31         235 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         84 $params->{postamble} = {};
894 31         64 my $i = 0;
895 31         477 $params->{postamble}{++$i} = $_ for @$postamble;
896             }
897              
898             sub _merge_libs {
899 31     31   115 my ($params, $add_libs) = @_;
900 31 50 33     119 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 834 if (!$_[0]) { $_[0] = [] }
  182 100       582  
919 9         42 elsif (ref($_[0]) ne 'ARRAY') { $_[0] = [$_[0]] }
920             }
921              
922             sub canonize_array_split {
923 250     250 0 668 canonize_array($_[0]);
924 250         433 @{$_[0]} = map { split ' ' } @{$_[0]};
  250         547  
  173         396  
  250         651  
925             }
926              
927             sub canonize_array_files {
928 91     91 0 269 canonize_array_split($_[0]);
929 91         176 @{$_[0]} = map { glob } @{$_[0]};
  91         298  
  166         2962  
  91         1174  
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 71 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       119 my $ddir = XS::Install::Payload::data_dir($module) or return (0, "data dir for $module not found");
939 31         122 my $pm = $ddir;
940 31         208 $pm =~ s#\.x$#.pm#;
941 31 50       459 return (0, "no $pm found") unless -f $pm;
942 31         519 my $version = MM->parse_version($pm);
943 31 50       14783 return (0, "version from $pm cannot be parsed") unless $version;
944 31         134 return ($version, undef);
945             }
946              
947 86 100 50 86 0 244 sub has_c { return $_[0]->{C} && scalar(@{$_[0]->{C}}) ? 1 : 0 }
948 2 50 50 2 0 15 sub has_object { return $_[0]->{OBJECT} && scalar(@{$_[0]->{OBJECT}}) ? 1 : 0 }
949 2 50 50 2 0 72 sub has_xs { return $_[0]->{XS} && scalar(keys %{$_[0]->{XS}}) ? 1 : 0 }
950 2 50 50 2 0 21 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 224 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 175 my $to = shift;
955 31   50     110 $to ||= '';
956 31         290 my @singleton = (qr/-O[0-9]/, qr/-g[0-9]?/);
957 31         99 foreach my $from (@_) {
958 62 50       194 next unless $from;
959 62         206 foreach my $tok (split ' ', $from) {
960 124         231 foreach my $qr (@singleton) {
961 248 100       3166 next unless $tok =~ /^$qr$/;
962 62         679 $to =~ s/(^|\s)$qr(\s|$)/ /g;
963             }
964 124         333 $to .= " $tok";
965             }
966             }
967 31         139 $to =~ s/^\s+//;
968 31         137 $to =~ s/\s+$//;
969 31         81 $to =~ s/\s{2,}/ /g;
970 31         154 return $to;
971             }
972              
973             sub _install {
974 22     22   61 my ($params, $map, $path) = @_;
975 22 100       62 return unless %$map;
976 16         38 my $instroot = _instroot($params);
977 16   50     73 my $pm = $params->{PM} ||= {};
978 16         74 while (my ($source, $dest) = each %$map) {
979 33         95 my $instpath = "$instroot/\$(FULLEXT).x/$path/$dest";
980 33         110 $instpath =~ s#[/\\]{2,}#/#g;
981 33         133 $pm->{$source} = $instpath;
982             }
983             }
984              
985 47 100   47   156 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 10 my $params = shift;
995 4 50       10 return undef unless has_binary($params);
996 4         20 my @modparts = split(/::/, $params->{NAME});
997 4         10 my $modfname = $modparts[-1];
998 4 50       19 $modfname = DynaLoader::mod2fname(\@modparts) if defined &DynaLoader::mod2fname;
999 4   33     65 return $modfname.'.'.($params->{DLEXT} || $Config{dlext});
1000             }
1001              
1002             sub _sync {
1003 11     11   170 no strict 'refs';
  11         34  
  11         11633  
1004 31     31   86 my $from = 'MYSOURCE';
1005 31         75 my $to = 'MY';
1006 31         69 foreach my $method (keys %{"${from}::"}) {
  31         220  
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   371 my ($mask, $dir) = @_;
1014 131 100       8293 return grep {_is_file_ok($_)} glob($mask) unless $dir;
  156         409  
1015              
1016 78         336 my @list = grep {_is_file_ok($_)} glob(join(' ', map {"$dir/$_"} split(' ', $mask)));
  89         384  
  215         15990  
1017              
1018 78 50       2160 opendir(my $dh, $dir) or die "Could not open dir '$dir' for scanning: $!";
1019 78         1217 while (my $entry = readdir $dh) {
1020 315 100       1640 next if $entry =~ /^\./;
1021 159         414 my $path = "$dir/$entry";
1022 159 100       2451 next unless -d $path;
1023 30         189 push @list, _scan_files($mask, $path);
1024             }
1025 78         764 closedir $dh;
1026              
1027 78         605 return @list;
1028             }
1029              
1030             sub _is_file_ok {
1031 245     245   514 my $file = shift;
1032 245 100       2716 return unless -f $file;
1033 242 50       908 return if $file =~ /\#/;
1034 242 50       476 return if $file =~ /~$/; # emacs temp files
1035 242 50       458 return if $file =~ /,v$/; # RCS files
1036 242 50       511 return if $file =~ m{\.swp$}; # vim swap files
1037 242         1113 return 1;
1038             }
1039              
1040             sub _process_map {
1041 18     18   52 my ($map, $mask) = @_;
1042 18         84 foreach my $source (keys %$map) {
1043 18   66     58 my $dest = $map->{$source} || $source;
1044 18 100       369 if (-f $source) {
1045 11 100       57 $dest .= $source if $dest =~ m#[/\\]$#;
1046 11         30 $dest =~ s#[/\\]{2,}#/#g;
1047 11         26 $dest =~ s#^[/\\]+##;
1048 11         27 $map->{$source} = $dest;
1049 11         44 next;
1050             }
1051 7 50       80 next unless -d $source;
1052              
1053 7         22 delete $map->{$source};
1054 7         20 my @files = _scan_files($mask, $source);
1055 7         22 foreach my $file (@files) {
1056 18         32 my $dest_file = $file;
1057 18         168 $dest_file =~ s/^$source//;
1058 18         44 $dest_file = "$dest/$dest_file";
1059 18         65 $dest_file =~ s#[/\\]{2,}#/#g;
1060 18         39 $dest_file =~ s#^[/\\]+##;
1061 18         73 $map->{$file} = $dest_file;
1062             }
1063             }
1064             }
1065              
1066             sub _uniq_list {
1067 128     128   209 my $list = shift;
1068 128         190 my %uniq;
1069 128         256 @$list = grep { !$uniq{$_}++ } @$list;
  572         1635  
1070             }
1071              
1072             sub _string_merge {
1073 269 100   269   1962 return unless $_[1];
1074 113   100     699 $_[0] ||= '';
1075 113 100       531 $_[0] .= $_[0] ? " $_[1]" : $_[1];
1076             }
1077              
1078             sub string_merge {
1079 62     62 0 194 my $s = shift;
1080 62   100     272 $s //= '';
1081 62         163 for my $val (@_) {
1082 62 100 66     434 next unless defined($val) && length($val);
1083 31 50       109 if (!$s) { $s = $val }
  31         74  
1084 0         0 else { $s .= " $val"; }
1085             }
1086 62         223 return $s;
1087             }
1088              
1089             sub c2obj_file {
1090 179     179 0 280 my $file = shift;
1091 179         626 $file =~ s/\.[^.]+$//;
1092 179         448 return $file.'$(OBJ_EXT)';
1093             }
1094              
1095             {
1096             package
1097             MY;
1098 11     11   108 use Config;
  11         79  
  11         1250  
1099              
1100             my $gcc_compliant = $Config{cc} =~ /\b(gcc|clang)\b/i ? 1 : 0;
1101              
1102             sub init_methods {
1103 11     11   102 no warnings 'redefine';
  11         38  
  11         17665  
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   109 my $pkg = shift;
1233 62         137 $pkg =~ s#::#/#g;
1234 62         193 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   108 sub _pkg_file { return _pkg_slash(shift).'.pm' }
1244              
1245             sub _split_path_args {
1246 3     3   6 my $str = shift;
1247              
1248 3         21 my $simple_arg = qr/[^"' \t]+/;
1249 3         12 my $dquoted_arg = qr/"([^"]+|\\")*"/;
1250 3         8 my $quoted_arg = qr/'([^']+|\\')*'/;
1251              
1252 3         6 my @args;
1253 3         146 push @args, $1 while $str =~ s/^\s*($simple_arg|$dquoted_arg|$quoted_arg)(\s+|$)//g;
1254              
1255 3         20 return @args;
1256             }
1257              
1258             sub _uniq_link {
1259 3     3   8 my $link = shift;
1260 3         14 my @args = _split_path_args($link);
1261 3         7 my %uniq;
1262 3         7 @args = grep { !$uniq{$_}++ } @args;
  8         32  
1263 3         17 return join ' ', @args;
1264             }
1265              
1266             1;