File Coverage

blib/lib/Alien/Base/ModuleBuild.pm
Criterion Covered Total %
statement 525 673 78.0
branch 153 262 58.4
condition 49 102 48.0
subroutine 69 76 90.7
pod 8 31 25.8
total 804 1144 70.2


line stmt bran cond sub pod time code
1             package Alien::Base::ModuleBuild;
2              
3 3     3   188390 use strict;
  3         10  
  3         109  
4 3     3   15 use warnings;
  3         4  
  3         70  
5 3     3   57 use 5.008001;
  3         9  
6 3     3   374 use parent 'Module::Build';
  3         247  
  3         19  
7 3     3   193657 use Capture::Tiny 0.17 qw/capture tee/;
  3         23621  
  3         184  
8 3     3   389 use File::chdir;
  3         2648  
  3         269  
9 3     3   20 use File::Spec;
  3         6  
  3         68  
10 3     3   12 use File::Basename qw/fileparse/;
  3         6  
  3         153  
11 3     3   16 use Carp;
  3         6  
  3         163  
12 3     3   17 no warnings;
  3         7  
  3         144  
13 3     3   1734 use Archive::Extract;
  3         369454  
  3         125  
14 3     3   25 use warnings;
  3         6  
  3         92  
15 3     3   1261 use Sort::Versions;
  3         1806  
  3         299  
16 3     3   20 use List::Util qw( uniq any );
  3         7  
  3         173  
17 3     3   1928 use ExtUtils::Installed;
  3         13638  
  3         116  
18 3     3   24 use File::Copy qw/move/;
  3         5  
  3         185  
19 3     3   2355 use Env qw( @PATH );
  3         7029  
  3         19  
20 3     3   1759 use Shell::Guess;
  3         6366  
  3         87  
21 3     3   1433 use Shell::Config::Generate;
  3         8144  
  3         146  
22 3     3   49 use File::Path qw/mkpath/;
  3         6  
  3         130  
23 3     3   16 use Config;
  3         7  
  3         100  
24 3     3   23 use Text::ParseWords qw( shellwords );
  3         5  
  3         167  
25 3     3   1305 use Alien::Base::PkgConfig;
  3         14497  
  3         93  
26 3     3   1415 use Alien::Base::ModuleBuild::Cabinet;
  3         8  
  3         90  
27 3     3   403 use Alien::Base::ModuleBuild::Repository;
  3         6  
  3         69  
28 3     3   837 use Alien::Base::ModuleBuild::Repository::HTTP;
  3         8  
  3         91  
29 3     3   1229 use Alien::Base::ModuleBuild::Repository::FTP;
  3         9  
  3         103  
30 3     3   1356 use Alien::Base::ModuleBuild::Repository::Local;
  3         7  
  3         20497  
31              
32             # ABSTRACT: A Module::Build subclass for building Alien:: modules and their libraries
33             our $VERSION = '1.16_01'; # TRIAL VERSION
34             $VERSION = eval $VERSION; ## no critic (BuiltinFunctions::ProhibitStringyEval)
35              
36             # setup protocol specific classes
37             # Alien:: author can override these defaults using alien_repository_class property
38             my %default_repository_class = (
39             default => 'Alien::Base::ModuleBuild::Repository',
40             http => 'Alien::Base::ModuleBuild::Repository::HTTP',
41             https => 'Alien::Base::ModuleBuild::Repository::HTTP',
42             ftp => 'Alien::Base::ModuleBuild::Repository::FTP',
43             local => 'Alien::Base::ModuleBuild::Repository::Local',
44             );
45              
46             our $Verbose;
47             $Verbose = $ENV{ALIEN_VERBOSE} if defined $ENV{ALIEN_VERBOSE};
48              
49             our $Force;
50             our $ForceSystem;
51             _compute_force();
52              
53             sub _compute_force
54             {
55 14     14   51329 undef $Force;
56 14         27 undef $ForceSystem;
57              
58 14 100       115 if(defined $ENV{ALIEN_INSTALL_TYPE})
    100          
59             {
60 9 100       71 if($ENV{ALIEN_INSTALL_TYPE} eq 'share')
    100          
61             {
62 3         22 $Force = 1;
63 3         14 $ForceSystem = 0;
64             }
65             elsif($ENV{ALIEN_INSTALL_TYPE} eq 'system')
66             {
67 3         17 $Force = 0;
68 3         15 $ForceSystem = 1;
69             }
70             else # anything else, including 'default'
71             {
72 3         31 $Force = 0;
73 3         23 $ForceSystem = 0;
74             }
75             }
76             elsif(defined $ENV{ALIEN_FORCE})
77             {
78 2         25 $Force = $ENV{ALIEN_FORCE};
79             }
80             }
81              
82             ################
83             # Parameters #
84             ################
85              
86             ## Extra parameters in A::B::MB objects (all (toplevel) should start with 'alien_')
87              
88             # alien_name: name of library (pkg-config)
89             __PACKAGE__->add_property('alien_name');
90              
91             # alien_ffi_name: name of library (the "foo" in libfoo)
92             __PACKAGE__->add_property('alien_ffi_name');
93              
94             # alien_temp_dir: folder name for download/build
95             __PACKAGE__->add_property( alien_temp_dir => '_alien' );
96              
97             # alien_install_type: allow to override alien install type
98             __PACKAGE__->add_property( alien_install_type => undef );
99              
100             # alien_share_dir: folder name for the "install" of the library
101             # this is added (unshifted) to the @{share_dir->{dist}}
102             # N.B. is reset during constructor to be full folder name
103             __PACKAGE__->add_property('alien_share_dir' => '_share' );
104              
105             # alien_selection_method: name of method for selecting file: (todo: newest, manual)
106             # default is specified later, when this is undef (see alien_check_installed_version)
107             __PACKAGE__->add_property( alien_selection_method => 'newest' );
108              
109             # alien_build_commands: arrayref of commands for building
110             __PACKAGE__->add_property(
111             alien_build_commands =>
112             default => [ '%c --prefix=%s', 'make' ],
113             );
114              
115             # alien_test_commands: arrayref of commands for testing the library
116             # note that this might be better tacked onto the build-time commands
117             __PACKAGE__->add_property(
118             alien_test_commands =>
119             default => [ ],
120             );
121              
122             # alien_build_commands: arrayref of commands for installing the library
123             __PACKAGE__->add_property(
124             alien_install_commands =>
125             default => [ 'make install' ],
126             );
127              
128             # alien_version_check: command to execute to check if install/version
129             __PACKAGE__->add_property( alien_version_check => '%{pkg_config} --modversion %n' );
130              
131             # pkgconfig-esque info, author provides these by hand for now, will parse .pc file eventually
132             __PACKAGE__->add_property( 'alien_provides_cflags' );
133             __PACKAGE__->add_property( 'alien_provides_libs' );
134              
135             # alien_repository: hash (or arrayref of hashes) of information about source repo on ftp
136             # |-- protocol: ftp or http
137             # |-- protocol_class: holder for class type (defaults to 'Net::FTP' or 'HTTP::Tiny')
138             # |-- host: ftp server for source
139             # |-- location: ftp folder containing source, http addr to page with links
140             # |-- pattern: qr regex matching acceptable files, if has capture group those are version numbers
141             # |-- platform: src or platform, matching os_type M::B method
142             # |
143             # |-- (non-api) connection: holder for Net::FTP-like object (needs cwd, ls, and get methods)
144             __PACKAGE__->add_property( 'alien_repository' => [] );
145             __PACKAGE__->add_property( 'alien_repository_default' => {} );
146             __PACKAGE__->add_property( 'alien_repository_class' => {} );
147              
148             # alien_isolate_dynamic
149             __PACKAGE__->add_property( 'alien_isolate_dynamic' => 0 );
150             __PACKAGE__->add_property( 'alien_autoconf_with_pic' => 1 );
151              
152             # alien_inline_auto_include
153             __PACKAGE__->add_property( 'alien_inline_auto_include' => [] );
154              
155             # use MSYS even if %c isn't found
156             __PACKAGE__->add_property( 'alien_msys' => 0 );
157              
158             # Alien packages that provide build dependencies
159             __PACKAGE__->add_property( 'alien_bin_requires' => {} );
160              
161             # Do a staged install to blib instead of trying to install to the final location.
162             __PACKAGE__->add_property( 'alien_stage_install' => 1 );
163              
164             # Should modules be installed into arch specific directory?
165             # Most alien dists will have arch specific files in their share so it makes sense to install
166             # the module in the arch specific location. If you are alienizing something that isn't arch
167             # specific, like javascript source or java byte code, then you'd want to set this to 0.
168             # For now this will default to off. See gh#119 for a discussion.
169             __PACKAGE__->add_property( 'alien_arch' => defined $ENV{ALIEN_ARCH} ? $ENV{ALIEN_ARCH} : 0 );
170              
171             __PACKAGE__->add_property( 'alien_helper' => {} );
172              
173             __PACKAGE__->add_property( 'alien_env' => {} );
174              
175             # Extra enviroment variable to effect to "configure"
176             __PACKAGE__->add_property( 'alien_extra_site_config' => {} );
177              
178             ################
179             # ConfigData #
180             ################
181              
182             # working_directory: full path to the extracted source or binary of the library
183             # pkgconfig: hashref of A::B::PkgConfig objects created from .pc file found in working_directory
184             # install_type: either system or share
185             # version: version number installed or available
186             # Cflags: holder for cflags if manually specified
187             # Libs: same but libs
188             # name: holder for name as needed by pkg-config
189             # finished_installing: set to true once ACTION_install is finished, this helps testing now and real checks later
190              
191             ############################
192             # Initialization Methods #
193             ############################
194              
195             sub new {
196 38     38 0 224804 my $class = shift;
197 38         202 my %args = @_;
198              
199             # merge default and user-defined repository classes
200             $args{alien_repository_class}{$_} ||= $default_repository_class{$_}
201 38   33     930 for keys %default_repository_class;
202              
203 38         402 my $self = $class->SUPER::new(%args);
204              
205             ## Recheck Force System
206 38 100 100     413917 if(!defined($ENV{ALIEN_INSTALL_TYPE}) && !defined($ENV{ALIEN_FORCE}) && defined($self->alien_install_type)) {
      100        
207 2 100       47 if ($self->alien_install_type eq 'share' ) { $Force = 1; $ForceSystem = 0; }
  1 50       25  
  1         7  
208 1         47 elsif($self->alien_install_type eq 'system') { $Force = 0; $ForceSystem = 1; }
  1         9  
209             }
210              
211 38         561 $self->config_data("Force" => $Force);
212 38         5573 $self->config_data("ForceSystem" => $ForceSystem);
213              
214             $self->alien_helper->{pkg_config} = 'Alien::Base::PkgConfig->pkg_config_command'
215 38 50       2629 unless defined $self->alien_helper->{pkg_config};
216              
217 38         873 my $ab_version = eval {
218 38         1203 require Alien::Base;
219 38         6159 Alien::Base->VERSION;
220             };
221 38   50     182 $ab_version ||= 0;
222              
223             # setup additional temporary directories, and yes we have to add File::ShareDir manually
224 38 50       377 if($ab_version < 0.77) {
225 0         0 $self->_add_prereq( 'requires', 'File::ShareDir', '1.00' );
226             }
227              
228             # this just gets passed from the Build.PL to the config so that it can
229             # be used by the auto_include method
230 38         301 $self->config_data( 'inline_auto_include' => $self->alien_inline_auto_include );
231              
232 38 100 100     3520 if($Force || !$self->alien_check_installed_version) {
233 36 100   43   554 if (any { /(?alien_build_commands }) {
  43 100       625  
  63         1332  
  4         70  
  36         599  
234 29         455 $self->config_data( 'autoconf' => 1 );
235             }
236              
237 36 50 0     7039 if ($^O eq 'MSWin32' && ($self->config_data( 'autoconf') || $self->alien_msys)) {
      33        
238 0         0 $self->_add_prereq( 'build_requires', 'Alien::MSYS', '0' );
239 0         0 $self->config_data( 'msys' => 1 );
240             } else {
241 36         486 $self->config_data( 'msys' => 0 );
242             }
243              
244 36         4584 foreach my $tool (keys %{ $self->alien_bin_requires }) {
  36         794  
245 7         234 my $version = $self->alien_bin_requires->{$tool};
246 7 100 100     200 if($tool eq 'Alien::CMake' && $version < 0.07) {
247 1         24 $version = '0.07';
248             }
249 7         156 $self->_add_prereq( 'build_requires', $tool, $version );
250             }
251              
252             my @repos = ref $args{alien_repository} eq 'ARRAY'
253 1         18 ? @{ $args{alien_repository} }
254 36 100       1461 : ( $args{alien_repository} );
255              
256 36         147 foreach my $repo (@repos)
257             {
258 36 100       171 next unless defined $repo;
259 5 100 50     49 if(($repo->{protocol}||'') eq 'https')
260             {
261 2         57 $self->_add_prereq( 'build_requires', 'IO::Socket::SSL', '1.56' );
262 2         90 $self->_add_prereq( 'build_requires', 'Net::SSLeay', '1.49' );
263             }
264             }
265              
266             }
267              
268              
269             # force newest for all automated testing
270             #TODO (this probably should be checked for "input needed" rather than blindly assigned)
271 38 50       377 if ($ENV{AUTOMATED_TESTING}) {
272 38         226 $self->alien_selection_method('newest');
273             }
274              
275 38         875 $self->config_data( 'finished_installing' => 0 );
276              
277 38 100   76   3769 if(any { /(?alien_build_commands }) {
  76 50       254  
  67         662  
  4         23  
  38         159  
278 0         0 carp "%p is deprecated, See https://metacpan.org/pod/Alien::Base::ModuleBuild::API#p";
279             }
280              
281 38         2029 return $self;
282             }
283              
284             sub alien_init_temp_dir {
285 6     6 0 4372 my $self = shift;
286 6         66 my $temp_dir = $self->alien_temp_dir;
287 6         89 my $share_dir = $self->alien_share_dir;
288              
289             # make sure we are in base_dir
290 6         137 local $CWD = $self->base_dir;
291              
292 6 50       543 unless ( -d $temp_dir ) {
293 6 50       392 mkdir $temp_dir or croak "Could not create temporary directory $temp_dir";
294             }
295 6         146 $self->add_to_cleanup( $temp_dir );
296              
297 6 50       668 unless ( -d $share_dir ) {
298 6 50       255 mkdir $share_dir or croak "Could not create temporary directory $share_dir";
299             }
300 6         47 $self->add_to_cleanup( $share_dir );
301              
302             # add share dir to share dir list
303 6         476 my $share_dirs = $self->share_dir;
304 6         95 unshift @{ $share_dirs->{dist} }, $share_dir;
  6         62  
305 6         34 $self->share_dir( $share_dirs );
306             {
307 6         181 local $CWD = $share_dir;
  6         30  
308 6 50       594 open my $fh, '>', 'README' or die "Could not open README for writing (in directory $share_dir)\n";
309 6         276 print $fh <<'END';
310             This README file is autogenerated by Alien::Base.
311              
312             Currently it exists for testing purposes, but it might eventually contain information about the file(s) installed.
313             END
314             }
315             }
316              
317             ####################
318             # ACTION methods #
319             ####################
320              
321             sub ACTION_alien_fakebuild {
322 0     0 0 0 my $self = shift;
323              
324             # needed for any helpers provided by alien_bin_requires
325 0         0 $self->_alien_bin_require($_) for keys %{ $self->alien_bin_requires };
  0         0  
326              
327 0         0 print "# Build\n";
328 0         0 foreach my $cmd (@{ $self->alien_build_commands })
  0         0  
329             {
330 0 0       0 my @cmd = map { $self->alien_interpolate($_) } ref($cmd) ? @$cmd : ($cmd);
  0         0  
331 0         0 print "+ @cmd\n";
332             }
333 0         0 print "# Build install\n";
334 0         0 foreach my $cmd (@{ $self->alien_install_commands })
  0         0  
335             {
336 0 0       0 my @cmd = map { $self->alien_interpolate($_) } ref($cmd) ? @$cmd : ($cmd);
  0         0  
337 0         0 print "+ @cmd\n";
338             }
339             }
340              
341             sub ACTION_code {
342 4     4 0 10145 my $self = shift;
343 4         67 $self->notes( 'alien_blib_scheme' => $self->alien_detect_blib_scheme );
344              
345             # PLEASE NOTE, BOTH BRANCHES CALL SUPER::ACTION_code !!!!!!!
346 4 50       345 if ( $self->notes('ACTION_alien_completed') ) {
347              
348 0         0 $self->SUPER::ACTION_code;
349              
350             } else {
351              
352 4         94 $self->depends_on('alien_code');
353 4         229 $self->SUPER::ACTION_code;
354             }
355              
356 4         6454 my $module = $self->module_name;
357 4         48 my $file = File::Spec->catfile($self->blib, 'lib', split /::/, "$module\::Install::Files.pm");
358 4 50       151 unless (-e $file) {
359 4         25 mkpath(File::Spec->catdir($self->blib, 'lib', split /::/, "$module\::Install"), { verbose => 0 });
360 4         802 open my $fh, '>', $file;
361 4         57 print $fh <
362             package $module\::Install::Files;
363             use strict;
364             use warnings;
365             require $module;
366             sub Inline { shift; $module->Inline(\@_) }
367             1;
368              
369             =begin Pod::Coverage
370              
371             Inline
372              
373             =end Pod::Coverage
374              
375             =cut
376             EOF
377 4         122 close $fh;
378             }
379              
380 4 50       63 if($self->alien_arch) {
381 0         0 my @parts = split /::/, $module;
382 0         0 my $arch_dir = File::Spec->catdir($self->blib, 'arch', 'auto', @parts);
383 0 0       0 File::Path::mkpath($arch_dir, 0, oct(777)) unless -d $arch_dir;
384 0         0 open my $fh, '>', File::Spec->catfile($arch_dir, $parts[-1].".txt");
385 0         0 print $fh "Alien based distribution with architecture specific file in share\n";
386 0         0 close $fh;
387             }
388              
389 4 100       74 $self->depends_on('alien_install') if $self->alien_stage_install;
390             }
391              
392             sub process_share_dir_files {
393 4     4 0 2811 my $self = shift;
394 4         30 $self->SUPER::process_share_dir_files(@_);
395              
396             # copy the compiled files into blib if running under blib scheme
397 4 50 66     5300 $self->depends_on('alien_install') if $self->notes('alien_blib_scheme') || $self->alien_stage_install;
398             }
399              
400             sub alien_extract_archive {
401 3     3 1 12 my ($self, $archive) = @_;
402 3         30 print "Extracting Archive ... ";
403 3         90 my $ae = Archive::Extract->new( archive => $archive );
404 3 50       1304 $ae->extract or croak "Archive extraction failed!";
405 3         213035 print "Done\n";
406 3         49 return $ae->extract_path;
407             }
408              
409             sub ACTION_alien_code {
410 4     4 0 277 my $self = shift;
411 4         58 local $| = 1; # don't buffer stdout
412              
413 4         184 $self->alien_init_temp_dir;
414              
415 4         217 $self->config_data( name => $self->alien_name );
416 4         431 $self->config_data( ffi_name => $self->alien_ffi_name );
417              
418 4         318 my $version;
419 4 50       25 $version = $self->alien_check_installed_version
420             unless $self->config_data('Force');
421              
422 4 100       62 if ($version) {
423 1         20 $self->config_data( install_type => 'system' );
424 1         80 $self->config_data( version => $version );
425 1         119 my %system_provides;
426 1 50       16 $system_provides{Cflags} = $self->alien_provides_cflags
427             if defined $self->alien_provides_cflags;
428 1 50       38 $system_provides{Libs} = $self->alien_provides_libs
429             if defined $self->alien_provides_libs;
430 1         30 $self->config_data( system_provides => \%system_provides );
431 1         86 return;
432             }
433              
434 3 50       62 if ($self->config_data('ForceSystem')) {
435 0         0 die "Requested system install, but system package not detected."
436             }
437              
438 3         238 my @repos = $self->alien_create_repositories;
439              
440 3         67 my $cabinet = Alien::Base::ModuleBuild::Cabinet->new;
441              
442 3         21 foreach my $repo (@repos) {
443 3         56 $cabinet->add_files( $repo->probe );
444             }
445              
446 3         13 $cabinet->sort_files;
447              
448             {
449 3         15 local $CWD = $self->alien_temp_dir;
  3         23  
450              
451 3         161 my $file = $cabinet->files->[0];
452              
453 3 50       11 unless (defined $file) {
454 0         0 die "no files found in repository";
455             }
456              
457 3         11 $version = $file->version;
458 3         17 $self->config_data( alien_version => $version ); # Temporary setting, may be overridden later
459              
460 3         686 print "Downloading File: " . $file->filename . " ... ";
461 3         24 my $filename = $file->get;
462 3 50       9 croak "Error downloading file" unless $filename;
463 3         40 print "Done\n";
464              
465 3         41 my $extract_path = _catdir(File::Spec->rel2abs($self->alien_extract_archive($filename)));
466              
467 3         63 $self->config_data( working_directory => $extract_path );
468 3         539 $CWD = $extract_path;
469              
470 3 50       164 if ( $file->platform eq 'src' ) {
471 3         44 print "Building library ... ";
472 3 50       71 unless ($self->alien_do_commands('build')) {
473 0         0 print "Failed\n";
474 0         0 croak "Build not completed";
475             }
476             }
477              
478 3         151 print "Done\n";
479              
480             }
481              
482 3         146 $self->config_data( install_type => 'share' );
483 3         680 $self->config_data( original_prefix => $self->alien_library_destination );
484              
485 3         329 my $pc = $self->alien_load_pkgconfig;
486             my $pc_version = (
487             $pc->{$self->alien_name} || $pc->{_manual}
488 3   33     13 )->keyword('Version');
489              
490 3 50       195 unless (defined $version) {
491 3         10 local $CWD = $self->config_data( 'working_directory' );
492 3         265 $version = $self->alien_check_built_version
493             }
494              
495 3 50 66     255 if (! $version && ! $pc_version) {
496 1         40 print STDERR "If you are the author of this Alien dist, you may need to provide a an\n";
497 1         12 print STDERR "alien_check_built_version method for your Alien::Base::ModuleBuild\n";
498 1         10 print STDERR "class. See:\n";
499 1         10 print STDERR "https://metacpan.org/pod/Alien::Base::ModuleBuild#alien_check_built_version\n";
500 1         395 carp "Library looks like it installed, but no version was determined";
501 1         89 $self->config_data( version => 0 );
502             return
503 1         206 }
504              
505 2 50 33     41 if ( $version and $pc_version and versioncmp($version, $pc_version)) {
      33        
506 0         0 carp "Version information extracted from the file name and pkgconfig data disagree";
507             }
508              
509 2   33     40 $self->config_data( version => $pc_version || $version );
510              
511             # prevent building multiple times (on M::B::dispatch)
512 2         194 $self->notes( 'ACTION_alien_completed' => 1 );
513              
514 2         239 return;
515             }
516              
517             sub ACTION_alien_test {
518 0     0 0 0 my $self = shift;
519 0         0 print "Testing library (if applicable) ... ";
520 0 0       0 if ($self->config_data( 'install_type' ) eq 'share') {
521 0 0       0 if (defined (my $wdir = $self->config_data( 'working_directory' ))) {
522 0         0 local $CWD = $wdir;
523 0 0       0 $self->alien_do_commands('test') or die "Failed\n";
524             }
525             }
526 0         0 print "Done\n";
527             }
528              
529             sub ACTION_test {
530 0     0 0 0 my $self = shift;
531 0         0 $self->depends_on('alien_test');
532 0         0 $self->SUPER::ACTION_test;
533             }
534              
535             sub ACTION_install {
536 1     1 0 66631 my $self = shift;
537 1         22 $self->SUPER::ACTION_install;
538 1 50       49044 if($self->alien_stage_install) {
539 0         0 $self->alien_relocation_fixup;
540             } else {
541 1         54 $self->depends_on('alien_install');
542             }
543             }
544              
545             sub ACTION_alien_install {
546 4     4 0 423 my $self = shift;
547              
548 4         21 local $| = 1; # don't buffer stdout
549              
550 4 100       14 return if $self->config_data( 'install_type' ) eq 'system';
551              
552 3         55 my $destdir = $self->destdir;
553 3         23 my $target = $self->alien_library_destination;
554              
555 3 50 33     11 if(defined $destdir && !$self->alien_stage_install)
556             {
557             # Note: no longer necessary when doing a staged install
558             # prefix the target directory with $destdir so that package builds
559             # can install into a fake root
560 0         0 $target = File::Spec->catdir($destdir, $target);
561             }
562              
563             {
564 3         15 local $CWD = $target;
  3         16  
565              
566             # The only form of introspection that exists is to see that the README file
567             # which was placed in the share_dir (default _share) exists where we expect
568             # after installation.
569 3 50       157 unless ( -e 'README' ) {
570 0         0 die "share_dir mismatch detected ($target)\n"
571             }
572             }
573              
574 3 50       62 if(!$self->config_data( 'finished_installing' ))
575             {
576 3         58 local $CWD = $self->config_data( 'working_directory' );
577 3         180 local $ENV{DESTDIR} = $ENV{DESTDIR};
578 3 50 33     20 $ENV{DESTDIR} = $destdir if defined $destdir && !$self->alien_stage_install;
579 3         12 print "Installing library to $CWD ... ";
580 3 50       117 $self->alien_do_commands('install') or die "Failed\n";
581 3         144 print "Done\n";
582             }
583              
584 3 50       176 if ( $self->alien_isolate_dynamic ) {
585 0         0 local $CWD = $target;
586 0         0 print "Isolating dynamic libraries ... ";
587 0 0       0 mkdir 'dynamic' unless -d 'dynamic';
588 0         0 foreach my $dir (qw( bin lib )) {
589 0 0       0 next unless -d $dir;
590 0         0 opendir(my $dh, $dir);
591 0 0       0 my @dlls = grep { /\.so/ || /\.(dylib|bundle|la|dll|dll\.a)$/ } grep !/^\./, readdir $dh;
  0         0  
592 0         0 closedir $dh;
593 0         0 foreach my $dll (@dlls) {
594 0         0 my $from = File::Spec->catfile($dir, $dll);
595 0         0 my $to = File::Spec->catfile('dynamic', $dll);
596 0 0       0 unlink $to if -e $to;
597 0         0 move($from, $to);
598             }
599             }
600 0         0 print "Done\n";
601             }
602              
603             # refresh metadata after library installation
604 3         85 $self->alien_refresh_manual_pkgconfig( $self->alien_library_destination );
605 3         14 $self->config_data( 'finished_installing' => 1 );
606              
607 3 50 66     278 if ( $self->notes( 'alien_blib_scheme') || $self->alien_stage_install) {
608              
609             ### TODO: empty if should be claned up before 0.017.
610             ### we used to call process_files_by_extension('pm')
611             ### here, but with gh#121 it is unecessary
612             ## reinstall config_data to blib
613             #$self->process_files_by_extension('pm');
614              
615             } else {
616              
617             # to refresh config_data
618 0         0 $self->SUPER::ACTION_config_data;
619              
620             # reinstall config_data
621 0         0 $self->SUPER::ACTION_install;
622              
623             # refresh the packlist
624 0         0 $self->alien_refresh_packlist( $self->alien_library_destination );
625             }
626             }
627              
628             #######################
629             # Pre-build Methods #
630             #######################
631              
632             sub alien_check_installed_version {
633 30     30 1 145 my $self = shift;
634 30         152 my $command = $self->alien_version_check;
635              
636 30         592 my %result = $self->do_system($command, {verbose => 0});
637 30   50     2704 my $version = ($result{success} && $result{stdout}) || 0;
638              
639 30         895 return $version;
640             }
641              
642             sub alien_create_repositories {
643 3     3 0 23 my $self = shift;
644              
645             ## get repository specs
646 3         70 my $repo_default = $self->alien_repository_default;
647 3         103 my $repo_specs = $self->alien_repository;
648              
649             # upconvert to arrayref if a single hashref is passed
650 3 50       61 if (ref $repo_specs eq 'HASH') {
651 3         174 $repo_specs = [ $repo_specs ];
652             }
653              
654 3         41 my $module_env_part = uc $self->module_name;
655 3         87 $module_env_part =~ s/^ALIEN:://;
656 3         37 $module_env_part =~ s/::/_/g;
657 3         21 my $env_prefix = 'ALIEN_'.$module_env_part.'_REPO_';
658              
659             # Catch e.g. 'ALIEN_MYMODULE_REPO_HTTP_HOST' variables to override repo config
660             my @env_overrides =
661 3         109 grep { index($_, $env_prefix) == 0 }
  89         152  
662             keys %ENV;
663              
664 3 50       20 unless(@$repo_specs)
665             {
666 0         0 print STDERR "If you are the author of this Alien dist, you need to provide at least\n";
667 0         0 print STDERR "one repository in your Build.PL. See:\n";
668 0         0 print STDERR "https://metacpan.org/pod/Alien::Base::ModuleBuild::API#alien_repository\n";
669 0         0 croak "No repositories specified.";
670             }
671              
672 3         6 my @repos;
673 3         21 foreach my $repo ( @$repo_specs ) {
674             #merge defaults into spec
675 3         17 foreach my $key ( keys %$repo_default ) {
676 0 0       0 next if defined $repo->{$key};
677 0         0 $repo->{$key} = $repo_default->{$key};
678             }
679              
680 3 50       44 $repo->{platform} = 'src' unless defined $repo->{platform};
681              
682 3         14 foreach my $var (@env_overrides) {
683 0         0 my $var_tail = lc substr($var, length($env_prefix));
684 0         0 my ($var_protocol, $var_key) = split /_/, $var_tail, 2;
685              
686 0 0       0 if ($repo->{protocol} eq $var_protocol) {
687 0         0 $repo->{$var_key} = $ENV{$var};
688             }
689             }
690              
691 3   50     51 push @repos, $self->alien_repository_class($repo->{protocol} || 'default')->new( $repo );
692             }
693              
694             # check validation, including c compiler for src type
695             @repos =
696 3         84 grep { $self->alien_validate_repo($_) }
  3         36  
697             @repos;
698              
699 3 50       10 unless (@repos) {
700 0         0 croak "No valid repositories available";
701             }
702              
703 3         21 return @repos;
704              
705             }
706              
707             sub alien_validate_repo {
708 7     7 0 97054 my $self = shift;
709 7         26 my ($repo) = @_;
710 7         31 my $platform = $repo->{platform};
711              
712             # return true if platform is undefined
713 7 100       70 return 1 unless defined $platform;
714              
715             # if $valid is src, check for c compiler
716 6 100       27 if ($platform eq 'src') {
717 4   33     76 return !$repo->{c_compiler_required} || $self->have_c_compiler;
718             }
719              
720             # $valid is a string (OS) to match against
721 2         37 return $self->os_type eq $platform;
722             }
723              
724             sub alien_library_destination {
725 106     106 0 4551 my $self = shift;
726              
727             # send the library into the blib if running under the blib scheme
728 106 50 100     413 my $lib_dir =
    100          
729             $self->notes('alien_blib_scheme') || $self->alien_stage_install
730             ? File::Spec->catdir( $self->base_dir, $self->blib, 'lib' )
731             : $self->install_destination($self->alien_arch ? 'arch' : 'lib');
732              
733 106         8104 my $dist_name = $self->dist_name;
734 106         1380 my $dest = _catdir( $lib_dir, qw/auto share dist/, $dist_name );
735 106         535 return $dest;
736             }
737              
738             # CPAN testers often run tests without installing modules, but rather add
739             # blib dirs to @INC, this is a problem, so here we try to deal with it
740             sub alien_detect_blib_scheme {
741 4     4 0 20 my $self = shift;
742              
743 4 100       57 return 0 if $self->alien_stage_install;
744 1 50       21 return $ENV{ALIEN_BLIB} if defined $ENV{ALIEN_BLIB};
745              
746             # check to see if Alien::Base::ModuleBuild is running from blib.
747             # if so it is likely that this is the blib scheme
748              
749 1         25 (undef, my $dir, undef) = File::Spec->splitpath( __FILE__ );
750 1         13 my @dirs = File::Spec->splitdir($dir);
751              
752 1   66     26 shift @dirs while @dirs && $dirs[0] ne 'blib';
753 1 50       9 return unless @dirs;
754              
755 1 50 33     20 if ( $dirs[1] && $dirs[1] eq 'lib' ) {
756 1         15 print qq{'blib' scheme is detected. Setting ALIEN_BLIB=1. If this has been done in error, please set ALIEN_BLIB and restart build process to disambiguate.\n};
757 1         18 return 1;
758             }
759              
760 0         0 carp q{'blib' scheme is suspected, but uncertain. Please set ALIEN_BLIB and restart build process to disambiguate. Setting ALIEN_BLIB=1 for now.};
761 0         0 return 1;
762             }
763              
764             ###################
765             # Build Methods #
766             ###################
767              
768             sub _shell_config_generate
769             {
770 4     4   102 my $scg = Shell::Config::Generate->new;
771 4         71 $scg->comment(
772             'this script sets the environment needed to build this package.',
773             'generated by: ' . __FILE__,
774             );
775 4         87 $scg;
776             }
777              
778             sub _filter_defines
779             {
780 0     0   0 join ' ', grep !/^-D/, shellwords($_[0]);
781             }
782              
783             sub _alien_bin_require {
784 2     2   688 my($self, $mod) = @_;
785              
786 2         19 my $version = $self->alien_bin_requires->{$mod};
787              
788 2 100       36 unless(eval { $mod->can('new') })
  2         92  
789             {
790 1         6 my $pm = "$mod.pm";
791 1         11 $pm =~ s/::/\//g;
792 1         14 require $pm;
793 1 50       25 $mod->VERSION($version) if $version;
794             }
795              
796 2 100       29 if($mod->can('alien_helper')) {
797 1         13 my $helpers = $mod->alien_helper;
798 1         44 foreach my $k (keys %$helpers) {
799 4         32 my $v = $helpers->{$k};
800 4 100       24 next if defined $self->alien_helper->{$k};
801 3         51 $self->alien_helper->{$k} = $v;
802             }
803             }
804             }
805              
806             sub alien_do_system {
807 12     12 1 16262 my $self = shift;
808 12         80 my $command = shift;
809              
810 12         1076 local %ENV = %ENV;
811              
812 12 50       148 if ($self->config_data( 'msys' )) {
813 0   0     0 $self->alien_bin_requires->{'Alien::MSYS'} ||= 0
814             }
815              
816 12         432 my $config;
817              
818 12         64 foreach my $mod (keys %{ $self->alien_bin_requires }) {
  12         126  
819 1         29 $self->_alien_bin_require($mod);
820              
821 1         5 my %path;
822              
823 1 50       36 if ($mod eq 'Alien::MSYS') {
    50          
    50          
    50          
824 0         0 $path{Alien::MSYS->msys_path} = 1;
825             } elsif ($mod eq 'Alien::TinyCC') {
826 0         0 $path{Alien::TinyCC->path_to_tcc} = 1;
827             } elsif ($mod eq 'Alien::Autotools') {
828 0         0 $path{$_} = 1 for map { Alien::Autotools->$_ } qw( autoconf_dir automake_dir libtool_dir );
  0         0  
829 1         48 } elsif (eval { $mod->can('bin_dir') }) {
830 1         10 $path{$_} = 1 for $mod->bin_dir;
831             }
832              
833             # remove anything already in PATH
834 1         44 delete $path{$_} for grep { defined $_ } @PATH;
  9         193  
835             # add anything else to start of PATH
836 1         17 unshift @PATH, sort keys %path;
837              
838 1   33     46 $config ||= _shell_config_generate();
839 1         10 $config->prepend_path( PATH => sort keys %path );
840             }
841              
842             # If we are using autoconf, then create a site.config file
843             # that specifies the same compiler and compiler linker flags
844             # as were used for building Perl. This is helpful for
845             # mixed 32/64bit platforms where 32bit is the default but
846             # Perl is 64bit.
847 12 50 33     276 if($self->config_data('autoconf') && !defined $ENV{CONFIG_SITE}) {
848              
849 0         0 local $CWD;
850 0         0 pop @CWD;
851              
852 0         0 my $ldflags = $Config{ldflags};
853 0 0       0 $ldflags .= " -Wl,-headerpad_max_install_names"
854             if $^O eq 'darwin';
855              
856 0         0 my %extra_site_config = %{ $self->alien_extra_site_config };
  0         0  
857 0         0 open my $fh, '>', 'config.site';
858 0         0 print $fh "CC='$Config{cc}'\n";
859             # -D define flags should be stripped because they are Perl
860             # specific.
861 0   0     0 print $fh "CFLAGS='" . join(" ", _filter_defines($Config{ccflags}), (delete($extra_site_config{CFLAGS}) ||"")) . "'\n";
862 0   0     0 print $fh "CPPFLAGS='" . join(" ", _filter_defines($Config{cppflags}), (delete($extra_site_config{CPPFLAGS}) ||"")) . "'\n";
863 0   0     0 print $fh "CXXFLAGS='" . join(" ", _filter_defines($Config{ccflags}), (delete($extra_site_config{CXXFLAGS}) ||"")) . "'\n";
864 0   0     0 print $fh "LDFLAGS='" . join(" ", $ldflags, (delete($extra_site_config{LDFLAGS}) ||"") ) . "'\n";
865 0         0 for (keys %extra_site_config) {
866 0         0 print $fh "$_='$extra_site_config{$_}'\n";
867             }
868 0         0 close $fh;
869              
870 0   0     0 my $config ||= _shell_config_generate();
871 0         0 my $config_site = File::Spec->catfile($CWD, 'config.site');
872 0 0       0 $config_site =~ s{\\}{/}g if $^O eq 'MSWin32';
873 0         0 $config->set( CONFIG_SITE => $config_site );
874 0         0 $ENV{CONFIG_SITE} = $config_site;
875             }
876              
877 12         249 foreach my $key (sort keys %{ $self->alien_env })
  12         118  
878             {
879 9         134 my $value = $self->alien_interpolate($self->alien_env->{$key});
880 9 100       85 defined $value ? $ENV{$key} = $value : delete $ENV{$key};
881 9   66     60 $config ||= _shell_config_generate();
882 9         34 $config->set( $key => $value );
883             }
884              
885 12 100       200 if($config) {
886 4 50       25 if($^O eq 'MSWin32') {
887 0         0 local $CWD;
888 0         0 pop @CWD;
889 0         0 $config->generate_file( Shell::Guess->command_shell, 'env.bat' );
890 0         0 $config->generate_file( Shell::Guess->cmd_shell, 'env.cmd' );
891 0         0 $config->generate_file( Shell::Guess->power_shell, 'env.ps1' );
892             } else {
893 4         26 local $CWD;
894 4         180 pop @CWD;
895 4         421 $config->generate_file( Shell::Guess->bourne_shell, 'env.sh' );
896 4         2278 $config->generate_file( Shell::Guess->c_shell, 'env.csh' );
897             }
898             }
899              
900 12 100       1551 $self->do_system( ref($command) ? @$command : $command );
901             }
902              
903             # alias for backwards compatibility
904             *_env_do_system = \&alien_do_system;
905              
906             sub alien_check_built_version {
907 1     1 1 11 return;
908             }
909              
910             sub alien_do_commands {
911 6     6 1 22 my $self = shift;
912 6         13 my $phase = shift;
913              
914 6         31 my $attr = "alien_${phase}_commands";
915 6         97 my $commands = $self->$attr();
916              
917 6         118 print "\n+ cd $CWD\n";
918              
919 6         263 foreach my $command (@$commands) {
920              
921 8         97 my %result = $self->alien_do_system( $command );
922 8 50       1729 unless ($result{success}) {
923 0         0 carp "External command ($result{command}) failed! Error: $?\n";
924 0         0 return 0;
925             }
926             }
927              
928 6         113 return 1;
929             }
930              
931             # wrapper for M::B::do_system which interpolates alien_ vars first
932             # futher it either captures or tees depending on the value of $Verbose
933             sub do_system {
934 42     42 0 120 my $self = shift;
935 42 100       221 my $opts = ref $_[-1] ? pop : { verbose => 1 };
936              
937 42   66     620 my $verbose = $Verbose || $opts->{verbose};
938              
939             # prevent build process from cwd-ing from underneath us
940 42         623 local $CWD;
941 42         1831 my $initial_cwd = $CWD;
942              
943 42         921 my @args = map { $self->alien_interpolate($_) } @_;
  67         437  
944              
945 42         1680 print "+ @args\n";
946              
947 42         298 my $old_super_verbose = $self->verbose;
948 42         508 $self->verbose(0);
949             my ($out, $err, $success) =
950             $verbose
951 12     12   195259 ? tee { $self->SUPER::do_system(@args) }
952 30     30   38241 : capture { $self->SUPER::do_system(@args) }
953 42 100       2879 ;
954 42         4453441 $self->verbose($old_super_verbose);
955              
956 42         2729 my %return = (
957             stdout => $out,
958             stderr => $err,
959             success => $success,
960             command => join(' ', @args),
961             );
962              
963             # restore wd
964 42         1429 $CWD = $initial_cwd;
965              
966 42 50       4212 return wantarray ? %return : $return{success}; ## no critic (Policy::Community::Wantarray)
967             }
968              
969             sub _alien_execute_helper {
970 44     44   231 my($self, $helper) = @_;
971 44         169 my $code = $self->alien_helper->{$helper};
972 44 100       539 die "no such helper: $helper" unless defined $code;
973              
974 43 100       137 if(ref($code) ne 'CODE') {
975 41         135 my $perl = $code;
976             $code = sub {
977 41     41   4863 my $value = eval $perl; ## no critic (Policy::BuiltinFunctions::ProhibitStringyEval)
978 41 100       115207 die $@ if $@;
979 40         355 $value;
980 41         414 };
981             }
982              
983 43         125 $code->();
984             }
985              
986             sub alien_interpolate {
987 94     94 1 13510 my $self = shift;
988 94         432 my ($string) = @_;
989              
990 94         579 my $prefix = $self->alien_exec_prefix;
991 94         538 my $configure = $self->alien_configure;
992 94         591 my $share = $self->alien_library_destination;
993 94   100     381 my $name = $self->alien_name || '';
994              
995             # substitute:
996             # install location share_dir (placeholder: %s)
997 94         1773 $string =~ s/(?
998             # local exec prefix (ph: %p)
999 94         292 $string =~ s/(?
1000             # correct incantation for configure on platform
1001 94         339 $string =~ s/(?
1002             # library name (ph: %n)
1003 94         399 $string =~ s/(?
1004             # current interpreter ($^X) (ph: %x)
1005 94         473 my $perl = $self->perl;
1006 94         849 $string =~ s/(?
1007 94 50       270 $perl =~ s{\\}{/}g if $^O eq 'MSWin32';
1008 94         204 $string =~ s/(?
1009              
1010             # Version, but only if needed. Complain if needed and not yet
1011             # stored.
1012 94 100       267 if ($string =~ /(?
1013 2         40 my $version = $self->config_data( 'alien_version' );
1014 2 100       69 if ( ! defined( $version ) ) {
1015 1         729 carp "Version substution requested but unable to identify";
1016             } else {
1017 1         5 $string =~ s/(?
1018             }
1019             }
1020              
1021 94         753 $string =~ s/(?_alien_execute_helper($1)/eg;
  44         194  
1022              
1023             #remove escapes (%%)
1024 92         305 $string =~ s/\%(?=\%)//g;
1025              
1026 92         657 return $string;
1027             }
1028              
1029             sub alien_exec_prefix {
1030 95     95 0 201 my $self = shift;
1031 95 50       792 if ( $self->is_windowsish ) {
1032 0         0 return '';
1033             } else {
1034 95         3966 return './';
1035             }
1036             }
1037              
1038             sub alien_configure {
1039 94     94 0 193 my $self = shift;
1040 94         151 my $configure;
1041 94 50       284 if ($self->config_data( 'msys' )) {
1042 0         0 $configure = 'sh configure';
1043             } else {
1044 94         1868 $configure = './configure';
1045             }
1046 94 50       280 if ($self->alien_autoconf_with_pic) {
1047 94         905 $configure .= ' --with-pic';
1048             }
1049 94         384 $configure;
1050             }
1051              
1052             ########################
1053             # Post-Build Methods #
1054             ########################
1055              
1056             sub alien_load_pkgconfig {
1057 3     3 0 16 my $self = shift;
1058              
1059 3         21 my $dir = _catdir($self->config_data( 'working_directory' ));
1060 3         223 my $pc_files = $self->rscan_dir( $dir, qr/\.pc$/ );
1061              
1062             my %pc_objects = map {
1063 3         1209 my $pc = Alien::Base::PkgConfig->new($_);
  0         0  
1064 0         0 $pc->make_abstract( pcfiledir => $dir );
1065 0         0 ($pc->{package}, $pc)
1066             } @$pc_files;
1067              
1068 3 50       61 $pc_objects{_manual} = $self->alien_generate_manual_pkgconfig($dir)
1069             or croak "Could not autogenerate pkgconfig information";
1070              
1071 3         22 $self->config_data( pkgconfig => \%pc_objects );
1072 3         321 return \%pc_objects;
1073             }
1074              
1075             sub alien_refresh_manual_pkgconfig {
1076 3     3 0 10 my $self = shift;
1077 3         9 my ($dir) = @_;
1078              
1079 3         25 my $pc_objects = $self->config_data( 'pkgconfig' );
1080 3 50       82 $pc_objects->{_manual} = $self->alien_generate_manual_pkgconfig($dir)
1081             or croak "Could not autogenerate pkgconfig information";
1082              
1083 3         21 $self->config_data( pkgconfig => $pc_objects );
1084              
1085 3         566 return 1;
1086             }
1087              
1088             sub alien_generate_manual_pkgconfig {
1089 10     10 0 6319 my $self = shift;
1090 10         41 my ($dir) = _catdir(shift);
1091              
1092 10         89 my $paths = $self->alien_find_lib_paths($dir);
1093              
1094             my @L =
1095 4         17 map { "-L$_" }
1096 4         17 map { _catdir( '${pcfiledir}', $_ ) }
1097 10         54 @{$paths->{lib}};
  10         32  
1098              
1099 10         37 my $provides_libs = $self->alien_provides_libs;
1100              
1101             #if no provides_libs then generate -l list from found files
1102 10 100       109 unless ($provides_libs) {
1103 9         24 my @files = map { "-l$_" } @{$paths->{lib_files}};
  9         22  
  9         23  
1104 9         52 $provides_libs = join( ' ', @files );
1105             }
1106              
1107 10         45 my $libs = join( ' ', @L, $provides_libs );
1108              
1109             my @I =
1110 4         9 map { "-I$_" }
1111 4         10 map { _catdir( '${pcfiledir}', $_ ) }
1112 10         17 @{$paths->{inc}};
  10         33  
1113              
1114 10         51 my $provides_cflags = $self->alien_provides_cflags;
1115 10 50       90 push @I, $provides_cflags if $provides_cflags;
1116 10         52 my $cflags = join( ' ', @I );
1117              
1118 10   100     74 my $manual_pc = Alien::Base::PkgConfig->new({
      100        
1119             package => $self->alien_name,
1120             vars => {
1121             pcfiledir => $dir,
1122             },
1123             keywords => {
1124             Cflags => $cflags || '',
1125             Libs => $libs || '',
1126             Version => '',
1127             },
1128             });
1129              
1130 10         881 return $manual_pc;
1131             }
1132              
1133             sub _alien_file_pattern_dynamic {
1134 14     14   37 my $self = shift;
1135 14         40 my $ext = $self->config('so'); #platform specific .so extension
1136 14         377 return qr/\.[\d.]*(?<=\.)$ext[\d.]*(?
1137             };
1138              
1139             sub _alien_file_pattern_static {
1140 14     14   25 my $self = shift;
1141 14         83 my $ext = quotemeta $self->config('lib_ext');
1142 14         789 return qr/(\.h|$ext)$/;
1143             }
1144              
1145             sub alien_find_lib_paths {
1146 14     14 0 14919 my $self = shift;
1147 14         37 my ($dir) = @_;
1148              
1149 14         121 my $libs = $self->alien_provides_libs;
1150 14         155 my @libs;
1151 14 100       45 @libs = map { my $f = $_; $f =~ s/^-l//; $f } grep { /^-l/ } split /\s+/, $libs if $libs;
  2         10  
  2         9  
  2         6  
  2         19  
1152              
1153 14         31 my (@lib_files, @lib_paths, @inc_paths);
1154              
1155 14         53 foreach my $file_pattern ($self->_alien_file_pattern_static, $self->_alien_file_pattern_dynamic) {
1156              
1157             my @files =
1158 80         3102 map { File::Spec->abs2rel( $_, $dir ) } # make relative to $dir
1159 92         1115 grep { ! -d }
1160 28         61 @{ $self->_rscan_destdir( $dir, $file_pattern ) };
  28         111  
1161              
1162 28         87 for (@files) {
1163              
1164 80         1879 my ($file, $path, $ext) = fileparse( $_, $file_pattern );
1165 80 100       206 next unless $ext; # just in case
1166              
1167 72         276 $path = File::Spec->catdir($path); # remove trailing /
1168              
1169 72 100       177 if ($ext eq '.h') {
1170 32         58 push @inc_paths, $path;
1171 32         60 next;
1172             }
1173              
1174 40         102 $file =~ s/^lib//;
1175              
1176 40 100       86 if (@libs) {
1177 14 100   14   53 next unless any { $file eq $_ } @libs;
  14         39  
1178             }
1179              
1180 32 100   38   131 next if any { $file eq $_ } @lib_files;
  38         80  
1181              
1182 20         55 push @lib_files, $file;
1183 20         52 push @lib_paths, $path;
1184             }
1185             }
1186              
1187 14         133 @lib_files = uniq @lib_files;
1188 14         82 @lib_files = sort @lib_files;
1189              
1190 14         50 @lib_paths = uniq @lib_paths;
1191 14         50 @inc_paths = uniq @inc_paths;
1192              
1193 14         126 return { lib => \@lib_paths, inc => \@inc_paths, lib_files => \@lib_files };
1194             }
1195              
1196             sub alien_refresh_packlist {
1197 0     0 0 0 my $self = shift;
1198 0   0     0 my $dir = shift || croak "Must specify a directory to include in packlist";
1199              
1200 0 0       0 return unless $self->create_packlist;
1201              
1202 0         0 my %installed_args;
1203 0 0       0 $installed_args{extra_libs} = [map { File::Spec->catdir($self->destdir, $_) } @INC]
  0         0  
1204             if defined $self->destdir;
1205              
1206 0         0 my $inst = ExtUtils::Installed->new( %installed_args );
1207 0         0 my $packlist = $inst->packlist( $self->module_name );
1208 0         0 print "Using " . $packlist->packlist_file . "\n";
1209              
1210 0         0 my $changed = 0;
1211 0         0 my $files = $self->_rscan_destdir($dir);
1212             # This is kind of strange, but MB puts the destdir paths in the
1213             # packfile, when arguably it should not. Usually you will want
1214             # to turn off packlists when you you are building an rpm anyway,
1215             # but for the sake of maximum compat with MB we add the destdir
1216             # back in after _rscan_destdir has stripped it out.
1217 0 0       0 $files = [ map { File::Spec->catdir($self->destdir, $_) } @$files ]
  0         0  
1218             if defined $self->destdir;
1219 0         0 for my $file (@$files) {
1220 0 0       0 next if $packlist->{$file};
1221 0         0 print "Adding $file to packlist\n";
1222 0         0 $changed++;
1223 0         0 $packlist->{$file}++;
1224             };
1225              
1226 0 0       0 $packlist->write if $changed;
1227             }
1228              
1229             sub alien_relocation_fixup {
1230 0     0 0 0 my($self) = @_;
1231              
1232             # so far relocation fixup is only needed on OS X
1233 0 0       0 return unless $^O eq 'darwin';
1234              
1235 0         0 my $dist_name = $self->dist_name;
1236 0 0       0 my $share = _catdir( $self->install_destination($self->alien_arch ? 'arch' : 'lib'), qw/auto share dist/, $dist_name );
1237              
1238 0         0 require File::Find;
1239             File::Find::find(sub {
1240 0 0   0   0 if(/\.dylib$/)
1241             {
1242             # save the original mode and make it writable
1243 0         0 my $mode = (stat $File::Find::name)[2];
1244 0 0       0 chmod 0755, $File::Find::name unless -w $File::Find::name;
1245              
1246 0         0 my @cmd = (
1247             'install_name_tool',
1248             '-id' => $File::Find::name,
1249             $File::Find::name,
1250             );
1251 0         0 print "+ @cmd\n";
1252 0         0 system @cmd;
1253              
1254             # restore the original permission mode
1255 0         0 chmod $mode, $File::Find::name;
1256             }
1257 0         0 }, $share);
1258             }
1259              
1260             sub _rscan_destdir {
1261 28     28   62 my($self, $dir, $pattern) = @_;
1262 28         153 my $destdir = $self->destdir;
1263 28 50       253 $dir = _catdir($destdir, $dir) if defined $destdir;
1264 28         116 my $files = $self->rscan_dir($dir, $pattern);
1265 28 50       12370 $files = [ map { my $dir = $_; $dir =~ s/^$destdir//; $dir } @$files ] if defined $destdir;
  0         0  
  0         0  
  0         0  
1266 28         84 $files;
1267             }
1268              
1269             # File::Spec uses \ as the file separator on MSWin32, which makes sense
1270             # since it is the default "native" file separator, but in practice / is
1271             # supported everywhere that matters and is significantly less problematic
1272             # in a number of common use cases (e.g. shell quoting). This is a short
1273             # cut _catdir for this rather common pattern where you want catdir with
1274             # / as the file separator on Windows.
1275             sub _catdir {
1276 130     130   1150 my $dir = File::Spec->catdir(@_);
1277 130 50       493 $dir =~ s{\\}{/}g if $^O eq 'MSWin32';
1278 130         436 $dir;
1279             }
1280              
1281             sub alien_install_network {
1282 29 100   29 1 14172 defined $ENV{ALIEN_INSTALL_NETWORK} ? !!$ENV{ALIEN_INSTALL_NETWORK} : 1;
1283             }
1284              
1285             sub alien_download_rule {
1286              
1287 46 100   46 1 11357 if(defined $ENV{ALIEN_DOWNLOAD_RULE}) {
1288 32 100       81 return 'warn' if $ENV{ALIEN_DOWNLOAD_RULE} eq 'default';
1289 31 100       264 return $ENV{ALIEN_DOWNLOAD_RULE} if $ENV{ALIEN_DOWNLOAD_RULE} =~ /^(warn|digest|encrypt|digest_or_encrypt|digest_and_encrypt)$/;
1290 1         31 warn "unknown ALIEN_DOWNLOAD_RULE \"ALIEN_DOWNLOAD_RULE\", using \"warn\" instead";
1291             }
1292              
1293 15         80 return 'warn';
1294             }
1295              
1296             1;
1297              
1298             =pod
1299              
1300             =encoding UTF-8
1301              
1302             =head1 NAME
1303              
1304             Alien::Base::ModuleBuild - A Module::Build subclass for building Alien:: modules and their libraries
1305              
1306             =head1 VERSION
1307              
1308             version 1.16_01
1309              
1310             =head1 SYNOPSIS
1311              
1312             In your Build.PL:
1313              
1314             use Alien::Base::ModuleBuild;
1315            
1316             my $builder = Alien::Base::ModuleBuild->new(
1317             module_name => 'Alien::MyLibrary',
1318            
1319             configure_requires => {
1320             'Alien::Base::ModuleBuild' => '0.005',
1321             'Module::Build' => '0.28'
1322             },
1323             requires => {
1324             'Alien::Base' => '0.005',
1325             },
1326            
1327             alien_name => 'mylibrary', # the pkg-config name if you want
1328             # to use pkg-config to discover
1329             # system version of the mylibrary
1330            
1331             alien_repository => {
1332             protocol => 'http',
1333             host => 'myhost.org',
1334             location => '/path/to/tarballs',
1335             pattern => qr{^mylibrary-([0-9\.]+)\.tar\.gz$},
1336             },
1337            
1338             # this is the default:
1339             alien_build_commands => [
1340             "%c --prefix=%s", # %c is a platform independent version of ./configure
1341             "make",
1342             ],
1343            
1344             # this is the default for install:
1345             alien_install_commands => [
1346             "make install",
1347             ],
1348            
1349             alien_isolate_dynamic => 1,
1350             );
1351              
1352             =head1 DESCRIPTION
1353              
1354             B: Please consider for new development of Ls that you use
1355             L and L instead. Like this module they work
1356             with L. Unlike this module they are more easily customized
1357             and handle a number of corner cases better. For a good place to start,
1358             please see L. Although the
1359             Alien-Base / Alien-Build team will continue to maintain this module,
1360             (we will continue to fix bugs where appropriate), we aren't adding any
1361             new features to this module.
1362              
1363             This is a subclass of L, that with L allows
1364             for easy creation of Alien distributions. This module is used during the
1365             build step of your distribution. When properly configured it will
1366              
1367             =over 4
1368              
1369             =item use pkg-config to find and use the system version of the library
1370              
1371             =item download, build and install the library if the system does not provide it
1372              
1373             =back
1374              
1375             =head1 METHODS
1376              
1377             =head2 alien_check_installed_version
1378              
1379             [version 0.001]
1380              
1381             my $version = $abmb->alien_check_installed_version;
1382              
1383             This function determines if the library is already installed as part of
1384             the operating system, and returns the version as a string. If it can't
1385             be detected then it should return empty list.
1386              
1387             The default implementation relies on C, but you will probably
1388             want to override this with your own implementation if the package you are
1389             building does not use C.
1390              
1391             =head2 alien_check_built_version
1392              
1393             [version 0.006]
1394              
1395             my $version = $amb->alien_check_built_version;
1396              
1397             This function determines the version of the library after it has been
1398             built from source. This function only gets called if the operating
1399             system version can not be found and the package is successfully built.
1400             The version is returned on success. If the version can't be detected
1401             then it should return empty list. Note that failing to detect a version
1402             is considered a failure and the corresponding C<./Build> action will
1403             fail!
1404              
1405             Any string is valid as a version as far as L is concerned.
1406             The most useful value would be a number or dotted decimal that most
1407             software developers recognize and that software tools can differentiate.
1408             In some cases packages will not have a clear version number, in which
1409             case the string C would be a reasonable choice.
1410              
1411             The default implementation relies on C, and other heuristics,
1412             but you will probably want to override this with your own implementation
1413             if the package you are building does not use C.
1414              
1415             When this method is called, the current working directory will be the
1416             build root.
1417              
1418             If you see an error message like this:
1419              
1420             Library looks like it installed, but no version was determined
1421              
1422             After the package is built from source code then you probably need to
1423             provide an implementation for this method.
1424              
1425             =head2 alien_extract_archive
1426              
1427             [version 0.024]
1428              
1429             my $dir = $amb->alien_extract_archive($filename);
1430              
1431             This function unpacks the given archive and returns the directory
1432             containing the unpacked files.
1433              
1434             The default implementation relies on L that is able
1435             to handle most common formats. In order to handle other formats or
1436             archives requiring some special treatment you may want to override
1437             this method.
1438              
1439             =head2 alien_do_system
1440              
1441             [version 0.024]
1442              
1443             my %result = $amb->alien_do_system($cmd)
1444              
1445             Similar to L, also sets the path and several
1446             environment variables in accordance to the object configuration
1447             (i.e. C) and performs the interpolation of the
1448             patterns described in L
1449             INTERPOLATION>.
1450              
1451             Returns a set of key value pairs including C, C,
1452             C and C.
1453              
1454             =head2 alien_do_commands
1455              
1456             $amb->alien_do_commands($phase);
1457              
1458             Executes the commands for the given phase.
1459              
1460             =head2 alien_interpolate
1461              
1462             my $string = $amb->alien_interpolate($string);
1463              
1464             Takes the input string and interpolates the results.
1465              
1466             =head2 alien_install_network
1467              
1468             my $bool = $amb->alien_install_network;
1469              
1470             Returns true if downloading source from the internet is allowed. This
1471             is true unless C is defined and false.
1472              
1473             =head2 alien_download_rule
1474              
1475             my $rule = $amb->alien_download_rule;
1476              
1477             This will return one of C, C, C, C
1478             or C. This is based on the C
1479             environment variable.
1480              
1481             =head1 GUIDE TO DOCUMENTATION
1482              
1483             The documentation for C is broken up into sections:
1484              
1485             =over
1486              
1487             =item General Usage (L)
1488              
1489             This is the landing document for L's parent class.
1490             It describes basic usage and background information.
1491             Its main purpose is to assist the user who wants to learn how to invoke
1492             and control C scripts at the command line.
1493              
1494             It also lists the extra documentation for its use. Users and authors of Alien::
1495             modules should familiarize themselves with these documents. L
1496             is of particular importance to authors.
1497              
1498             =item Alien-Specific Usage (L)
1499              
1500             This is the document you are currently reading.
1501              
1502             =item Authoring Reference (L)
1503              
1504             This document describes the structure and organization of
1505             C based projects, beyond that contained in
1506             C, and the relevant concepts needed by authors who are
1507             writing F scripts for a distribution or controlling
1508             C processes programmatically.
1509              
1510             Note that as it contains information both for the build and use phases of
1511             L projects, it is located in the upper namespace.
1512              
1513             =item API Reference (L)
1514              
1515             This is a reference to the C API beyond that contained
1516             in C.
1517              
1518             =back
1519              
1520             =head1 ENVIRONMENT
1521              
1522             =over 4
1523              
1524             =item B
1525              
1526             Set to a true value to install to an arch-specific directory.
1527              
1528             =item B
1529              
1530             This controls security options for fetching alienized packages over the internet.
1531             The legal values are:
1532              
1533             =over 4
1534              
1535             =item C
1536              
1537             Warn if the package is either unencrypted or lacks a digest. This is currently
1538             the default, but will change in the near future.
1539              
1540             =item C
1541              
1542             Fetch will not happen unless there is a digest for the alienized package.
1543              
1544             =item C
1545              
1546             Fetch will not happen unless via an encrypted protocol like C, or if the
1547             package is bundled with the L.
1548              
1549             =item C
1550              
1551             Fetch will only happen if the alienized package has a cryptographic signature digest,
1552             or if an encrypted protocol like C is used, or if the package is bundled with
1553             the L. This will be the default in the near future.
1554              
1555             =item C
1556              
1557             Fetch will only happen if the alienized package has a cryptographic signature digest,
1558             and is fetched via a secure protocol (like C). Bundled packages are also
1559             considered fetch via a secure protocol, but will still require a digest.
1560              
1561             =back
1562              
1563             =item B
1564              
1565             Skips checking for an installed version and forces reinstalling the Alien target.
1566              
1567             =item B
1568              
1569             If true (the default if not defined), then network installs will be allowed.
1570             Set to C<0> or another false value to turn off network installs.
1571              
1572             =item B
1573              
1574             Set to 'share' or 'system' to override the install type. Set to 'default' or unset
1575             to restore the default.
1576              
1577             =item B
1578              
1579             Enables verbose output from L.
1580              
1581             =item B
1582              
1583             Overrides $KEY in the given module's repository configuration matching $PROTOCOL.
1584             For example, C.
1585              
1586             =back
1587              
1588             =head1 SEE ALSO
1589              
1590             =over
1591              
1592             =item L
1593              
1594             =item L
1595              
1596             =item L
1597              
1598             =item L
1599              
1600             =back
1601              
1602             =head1 THANKS
1603              
1604             Thanks also to
1605              
1606             =over
1607              
1608             =item Christian Walde (Mithaldu)
1609              
1610             For productive conversations about component interoperability.
1611              
1612             =item kmx
1613              
1614             For writing Alien::Tidyp from which I drew many of my initial ideas.
1615              
1616             =item David Mertens (run4flat)
1617              
1618             For productive conversations about implementation.
1619              
1620             =item Mark Nunberg (mordy, mnunberg)
1621              
1622             For graciously teaching me about rpath and dynamic loading,
1623              
1624             =back
1625              
1626             =head1 AUTHOR
1627              
1628             Original author: Joel A Berger Ejoel.a.berger@gmail.comE
1629              
1630             Current maintainer: Graham Ollis Eplicease@cpan.orgE
1631              
1632             Contributors:
1633              
1634             David Mertens (run4flat)
1635              
1636             Mark Nunberg (mordy, mnunberg)
1637              
1638             Christian Walde (Mithaldu)
1639              
1640             Brian Wightman (MidLifeXis)
1641              
1642             Graham Ollis (plicease)
1643              
1644             Zaki Mughal (zmughal)
1645              
1646             mohawk2
1647              
1648             Vikas N Kumar (vikasnkumar)
1649              
1650             Flavio Poletti (polettix)
1651              
1652             Salvador Fandiño (salva)
1653              
1654             Gianni Ceccarelli (dakkar)
1655              
1656             Pavel Shaydo (zwon, trinitum)
1657              
1658             Kang-min Liu (劉康民, gugod)
1659              
1660             Nicholas Shipp (nshp)
1661              
1662             Petr Písař (ppisar)
1663              
1664             Alberto Simões (ambs)
1665              
1666             =head1 COPYRIGHT AND LICENSE
1667              
1668             This software is copyright (c) 2012-2022 by Joel A Berger.
1669              
1670             This is free software; you can redistribute it and/or modify it under
1671             the same terms as the Perl 5 programming language system itself.
1672              
1673             =cut
1674              
1675             __END__