File Coverage

blib/lib/XS/Install.pm
Criterion Covered Total %
statement 494 848 58.2
branch 143 382 37.4
condition 67 225 29.7
subroutine 66 85 77.6
pod 2 44 4.5
total 772 1584 48.7


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