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