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