File Coverage

blib/lib/Alien/Base/ModuleBuild.pm
Criterion Covered Total %
statement 519 667 77.8
branch 145 254 57.0
condition 49 102 48.0
subroutine 67 74 90.5
pod 6 29 20.6
total 786 1126 69.8


line stmt bran cond sub pod time code
1             package Alien::Base::ModuleBuild;
2              
3 1     1   224902 use strict;
  1         6  
  1         28  
4 1     1   5 use warnings;
  1         2  
  1         21  
5 1     1   27 use 5.008001;
  1         4  
6 1     1   452 use parent 'Module::Build';
  1         287  
  1         6  
7 1     1   75773 use Capture::Tiny 0.17 qw/capture tee/;
  1         26424  
  1         66  
8 1     1   544 use File::chdir;
  1         3242  
  1         100  
9 1     1   8 use File::Spec;
  1         2  
  1         26  
10 1     1   5 use File::Basename qw/fileparse/;
  1         2  
  1         66  
11 1     1   7 use Carp;
  1         2  
  1         60  
12 1     1   7 no warnings;
  1         2  
  1         42  
13 1     1   693 use Archive::Extract;
  1         145633  
  1         44  
14 1     1   11 use warnings;
  1         3  
  1         29  
15 1     1   466 use Sort::Versions;
  1         665  
  1         110  
16 1     1   8 use List::Util qw( uniq any );
  1         2  
  1         66  
17 1     1   571 use ExtUtils::Installed;
  1         5135  
  1         43  
18 1     1   7 use File::Copy qw/move/;
  1         2  
  1         62  
19 1     1   969 use Env qw( @PATH );
  1         2744  
  1         6  
20 1     1   687 use Shell::Guess;
  1         2470  
  1         31  
21 1     1   527 use Shell::Config::Generate;
  1         3214  
  1         56  
22 1     1   7 use File::Path qw/mkpath/;
  1         3  
  1         47  
23 1     1   6 use Config;
  1         2  
  1         35  
24 1     1   24 use Text::ParseWords qw( shellwords );
  1         4  
  1         68  
25 1     1   495 use Alien::Base::PkgConfig;
  1         13315  
  1         34  
26 1     1   508 use Alien::Base::ModuleBuild::Cabinet;
  1         3  
  1         32  
27 1     1   441 use Alien::Base::ModuleBuild::Repository;
  1         2  
  1         33  
28 1     1   484 use Alien::Base::ModuleBuild::Repository::HTTP;
  1         3  
  1         44  
29 1     1   472 use Alien::Base::ModuleBuild::Repository::FTP;
  1         5  
  1         41  
30 1     1   512 use Alien::Base::ModuleBuild::Repository::Local;
  1         4  
  1         7749  
31              
32             # ABSTRACT: A Module::Build subclass for building Alien:: modules and their libraries
33             our $VERSION = '1.15'; # 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 12     12   54399 undef $Force;
55 12         38 undef $ForceSystem;
56              
57 12 100       106 if(defined $ENV{ALIEN_INSTALL_TYPE})
    100          
58             {
59 9 100       101 if($ENV{ALIEN_INSTALL_TYPE} eq 'share')
    100          
60             {
61 3         22 $Force = 1;
62 3         26 $ForceSystem = 0;
63             }
64             elsif($ENV{ALIEN_INSTALL_TYPE} eq 'system')
65             {
66 3         25 $Force = 0;
67 3         22 $ForceSystem = 1;
68             }
69             else # anything else, including 'default'
70             {
71 3         27 $Force = 0;
72 3         14 $ForceSystem = 0;
73             }
74             }
75             elsif(defined $ENV{ALIEN_FORCE})
76             {
77 2         24 $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 274178 my $class = shift;
196 38         229 my %args = @_;
197              
198             # merge default and user-defined repository classes
199             $args{alien_repository_class}{$_} ||= $default_repository_class{$_}
200 38   33     1024 for keys %default_repository_class;
201              
202 38         608 my $self = $class->SUPER::new(%args);
203              
204             ## Recheck Force System
205 38 100 100     476703 if(!defined($ENV{ALIEN_INSTALL_TYPE}) && !defined($ENV{ALIEN_FORCE}) && defined($self->alien_install_type)) {
      100        
206 2 100       65 if ($self->alien_install_type eq 'share' ) { $Force = 1; $ForceSystem = 0; }
  1 50       53  
  1         14  
207 1         64 elsif($self->alien_install_type eq 'system') { $Force = 0; $ForceSystem = 1; }
  1         15  
208             }
209              
210 38         767 $self->config_data("Force" => $Force);
211 38         7806 $self->config_data("ForceSystem" => $ForceSystem);
212              
213             $self->alien_helper->{pkg_config} = 'Alien::Base::PkgConfig->pkg_config_command'
214 38 50       3471 unless defined $self->alien_helper->{pkg_config};
215              
216 38         974 my $ab_version = eval {
217 38         1742 require Alien::Base;
218 38         7262 Alien::Base->VERSION;
219             };
220 38   50     245 $ab_version ||= 0;
221              
222             # setup additional temporary directories, and yes we have to add File::ShareDir manually
223 38 50       449 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         435 $self->config_data( 'inline_auto_include' => $self->alien_inline_auto_include );
230              
231 38 100 100     4390 if($Force || !$self->alien_check_installed_version) {
232 36 100   43   848 if (any { /(?alien_build_commands }) {
  43 100       905  
  63         1573  
  4         120  
  36         659  
233 29         727 $self->config_data( 'autoconf' => 1 );
234             }
235              
236 36 50 0     9503 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         363 $self->config_data( 'msys' => 0 );
241             }
242              
243 36         5773 foreach my $tool (keys %{ $self->alien_bin_requires }) {
  36         836  
244 7         287 my $version = $self->alien_bin_requires->{$tool};
245 7 100 100     247 if($tool eq 'Alien::CMake' && $version < 0.07) {
246 1         43 $version = '0.07';
247             }
248 7         156 $self->_add_prereq( 'build_requires', $tool, $version );
249             }
250              
251             my @repos = ref $args{alien_repository} eq 'ARRAY'
252 1         56 ? @{ $args{alien_repository} }
253 36 100       1743 : ( $args{alien_repository} );
254              
255 36         238 foreach my $repo (@repos)
256             {
257 36 100       339 next unless defined $repo;
258 5 100 50     128 if(($repo->{protocol}||'') eq 'https')
259             {
260 2         120 $self->_add_prereq( 'build_requires', 'IO::Socket::SSL', '1.56' );
261 2         301 $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       435 if ($ENV{AUTOMATED_TESTING}) {
271 38         565 $self->alien_selection_method('newest');
272             }
273              
274 38         1199 $self->config_data( 'finished_installing' => 0 );
275              
276 38 100   76   4394 if(any { /(?alien_build_commands }) {
  76 50       633  
  67         759  
  4         46  
  38         231  
277 0         0 carp "%p is deprecated, See https://metacpan.org/pod/Alien::Base::ModuleBuild::API#p";
278             }
279              
280 38         2488 return $self;
281             }
282              
283             sub alien_init_temp_dir {
284 6     6 0 8681 my $self = shift;
285 6         124 my $temp_dir = $self->alien_temp_dir;
286 6         175 my $share_dir = $self->alien_share_dir;
287              
288             # make sure we are in base_dir
289 6         208 local $CWD = $self->base_dir;
290              
291 6 50       805 unless ( -d $temp_dir ) {
292 6 50       470 mkdir $temp_dir or croak "Could not create temporary directory $temp_dir";
293             }
294 6         224 $self->add_to_cleanup( $temp_dir );
295              
296 6 50       1063 unless ( -d $share_dir ) {
297 6 50       339 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         855 my $share_dirs = $self->share_dir;
303 6         105 unshift @{ $share_dirs->{dist} }, $share_dir;
  6         55  
304 6         49 $self->share_dir( $share_dirs );
305             {
306 6         268 local $CWD = $share_dir;
  6         75  
307 6 50       824 open my $fh, '>', 'README' or die "Could not open README for writing (in directory $share_dir)\n";
308 6         333 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 14513 my $self = shift;
342 4         103 $self->notes( 'alien_blib_scheme' => $self->alien_detect_blib_scheme );
343              
344             # PLEASE NOTE, BOTH BRANCHES CALL SUPER::ACTION_code !!!!!!!
345 4 50       447 if ( $self->notes('ACTION_alien_completed') ) {
346              
347 0         0 $self->SUPER::ACTION_code;
348              
349             } else {
350              
351 4         113 $self->depends_on('alien_code');
352 4         320 $self->SUPER::ACTION_code;
353             }
354              
355 4         8397 my $module = $self->module_name;
356 4         66 my $file = File::Spec->catfile($self->blib, 'lib', split /::/, "$module\::Install::Files.pm");
357 4 50       199 unless (-e $file) {
358 4         32 mkpath(File::Spec->catdir($self->blib, 'lib', split /::/, "$module\::Install"), { verbose => 0 });
359 4         998 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         133 close $fh;
377             }
378              
379 4 50       66 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       68 $self->depends_on('alien_install') if $self->alien_stage_install;
389             }
390              
391             sub process_share_dir_files {
392 4     4 0 3948 my $self = shift;
393 4         42 $self->SUPER::process_share_dir_files(@_);
394              
395             # copy the compiled files into blib if running under blib scheme
396 4 50 66     6624 $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 15 my ($self, $archive) = @_;
401 3         44 print "Extracting Archive ... ";
402 3         114 my $ae = Archive::Extract->new( archive => $archive );
403 3 50       1702 $ae->extract or croak "Archive extraction failed!";
404 3         263204 print "Done\n";
405 3         52 return $ae->extract_path;
406             }
407              
408             sub ACTION_alien_code {
409 4     4 0 327 my $self = shift;
410 4         80 local $| = 1; # don't buffer stdout
411              
412 4         78 $self->alien_init_temp_dir;
413              
414 4         301 $self->config_data( name => $self->alien_name );
415 4         534 $self->config_data( ffi_name => $self->alien_ffi_name );
416              
417 4         400 my $version;
418 4 50       39 $version = $self->alien_check_installed_version
419             unless $self->config_data('Force');
420              
421 4 100       130 if ($version) {
422 1         35 $self->config_data( install_type => 'system' );
423 1         94 $self->config_data( version => $version );
424 1         88 my %system_provides;
425 1 50       27 $system_provides{Cflags} = $self->alien_provides_cflags
426             if defined $self->alien_provides_cflags;
427 1 50       66 $system_provides{Libs} = $self->alien_provides_libs
428             if defined $self->alien_provides_libs;
429 1         46 $self->config_data( system_provides => \%system_provides );
430 1         102 return;
431             }
432              
433 3 50       115 if ($self->config_data('ForceSystem')) {
434 0         0 die "Requested system install, but system package not detected."
435             }
436              
437 3         385 my @repos = $self->alien_create_repositories;
438              
439 3         88 my $cabinet = Alien::Base::ModuleBuild::Cabinet->new;
440              
441 3         25 foreach my $repo (@repos) {
442 3         42 $cabinet->add_files( $repo->probe() );
443             }
444              
445 3         26 $cabinet->sort_files;
446              
447             {
448 3         7 local $CWD = $self->alien_temp_dir;
  3         47  
449              
450 3         194 my $file = $cabinet->files->[0];
451              
452 3 50       20 unless (defined $file) {
453 0         0 die "no files found in repository";
454             }
455              
456 3         36 $version = $file->version;
457 3         14 $self->config_data( alien_version => $version ); # Temporary setting, may be overridden later
458              
459 3         931 print "Downloading File: " . $file->filename . " ... ";
460 3         34 my $filename = $file->get;
461 3 50       10 croak "Error downloading file" unless $filename;
462 3         41 print "Done\n";
463              
464 3         60 my $extract_path = _catdir(File::Spec->rel2abs($self->alien_extract_archive($filename)));
465              
466 3         71 $self->config_data( working_directory => $extract_path );
467 3         771 $CWD = $extract_path;
468              
469 3 50       230 if ( $file->platform eq 'src' ) {
470 3         50 print "Building library ... ";
471 3 50       128 unless ($self->alien_do_commands('build')) {
472 0         0 print "Failed\n";
473 0         0 croak "Build not completed";
474             }
475             }
476              
477 3         194 print "Done\n";
478              
479             }
480              
481 3         187 $self->config_data( install_type => 'share' );
482 3         960 $self->config_data( original_prefix => $self->alien_library_destination );
483              
484 3         423 my $pc = $self->alien_load_pkgconfig;
485             my $pc_version = (
486             $pc->{$self->alien_name} || $pc->{_manual}
487 3   33     20 )->keyword('Version');
488              
489 3 50       329 unless (defined $version) {
490 3         15 local $CWD = $self->config_data( 'working_directory' );
491 3         291 $version = $self->alien_check_built_version
492             }
493              
494 3 50 66     303 if (! $version && ! $pc_version) {
495 1         45 print STDERR "If you are the author of this Alien dist, you may need to provide a an\n";
496 1         18 print STDERR "alien_check_built_version method for your Alien::Base::ModuleBuild\n";
497 1         13 print STDERR "class. See:\n";
498 1         11 print STDERR "https://metacpan.org/pod/Alien::Base::ModuleBuild#alien_check_built_version\n";
499 1         487 carp "Library looks like it installed, but no version was determined";
500 1         94 $self->config_data( version => 0 );
501             return
502 1         298 }
503              
504 2 50 33     69 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     52 $self->config_data( version => $pc_version || $version );
509              
510             # prevent building multiple times (on M::B::dispatch)
511 2         277 $self->notes( 'ACTION_alien_completed' => 1 );
512              
513 2         294 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 80732 my $self = shift;
536 1         26 $self->SUPER::ACTION_install;
537 1 50       63842 if($self->alien_stage_install) {
538 0         0 $self->alien_relocation_fixup;
539             } else {
540 1         69 $self->depends_on('alien_install');
541             }
542             }
543              
544             sub ACTION_alien_install {
545 4     4 0 508 my $self = shift;
546              
547 4         44 local $| = 1; # don't buffer stdout
548              
549 4 100       18 return if $self->config_data( 'install_type' ) eq 'system';
550              
551 3         88 my $destdir = $self->destdir;
552 3         36 my $target = $self->alien_library_destination;
553              
554 3 50 33     26 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         9 local $CWD = $target;
  3         16  
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       258 unless ( -e 'README' ) {
569 0         0 die "share_dir mismatch detected ($target)\n"
570             }
571             }
572              
573 3 50       83 if(!$self->config_data( 'finished_installing' ))
574             {
575 3         76 local $CWD = $self->config_data( 'working_directory' );
576 3         223 local $ENV{DESTDIR} = $ENV{DESTDIR};
577 3 50 33     23 $ENV{DESTDIR} = $destdir if defined $destdir && !$self->alien_stage_install;
578 3         13 print "Installing library to $CWD ... ";
579 3 50       119 $self->alien_do_commands('install') or die "Failed\n";
580 3         195 print "Done\n";
581             }
582              
583 3 50       292 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         116 $self->alien_refresh_manual_pkgconfig( $self->alien_library_destination );
604 3         24 $self->config_data( 'finished_installing' => 1 );
605              
606 3 50 66     313 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 207 my $self = shift;
633 30         201 my $command = $self->alien_version_check;
634              
635 30         815 my %result = $self->do_system($command, {verbose => 0});
636 30   50     3283 my $version = ($result{success} && $result{stdout}) || 0;
637              
638 30         1346 return $version;
639             }
640              
641             sub alien_create_repositories {
642 3     3 0 26 my $self = shift;
643              
644             ## get repository specs
645 3         106 my $repo_default = $self->alien_repository_default;
646 3         138 my $repo_specs = $self->alien_repository;
647              
648             # upconvert to arrayref if a single hashref is passed
649 3 50       108 if (ref $repo_specs eq 'HASH') {
650 3         18 $repo_specs = [ $repo_specs ];
651             }
652              
653 3         87 my $module_env_part = uc $self->module_name;
654 3         174 $module_env_part =~ s/^ALIEN:://;
655 3         426 $module_env_part =~ s/::/_/g;
656 3         19 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         149 grep { index($_, $env_prefix) == 0 }
  86         177  
661             keys %ENV;
662              
663 3 50       25 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         9 my @repos;
672 3         25 foreach my $repo ( @$repo_specs ) {
673             #merge defaults into spec
674 3         21 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       49 $repo->{platform} = 'src' unless defined $repo->{platform};
680              
681 3         33 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     66 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         103 grep { $self->alien_validate_repo($_) }
  3         41  
696             @repos;
697              
698 3 50       12 unless (@repos) {
699 0         0 croak "No valid repositories available";
700             }
701              
702 3         32 return @repos;
703              
704             }
705              
706             sub alien_validate_repo {
707 7     7 0 102543 my $self = shift;
708 7         28 my ($repo) = @_;
709 7         35 my $platform = $repo->{platform};
710              
711             # return true if platform is undefined
712 7 100       113 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     108 return !$repo->{c_compiler_required} || $self->have_c_compiler;
717             }
718              
719             # $valid is a string (OS) to match against
720 2         34 return $self->os_type eq $platform;
721             }
722              
723             sub alien_library_destination {
724 106     106 0 6474 my $self = shift;
725              
726             # send the library into the blib if running under the blib scheme
727 106 50 100     458 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         11146 my $dist_name = $self->dist_name;
733 106         1500 my $dest = _catdir( $lib_dir, qw/auto share dist/, $dist_name );
734 106         348 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 30 my $self = shift;
741              
742 4 100       84 return 0 if $self->alien_stage_install;
743 1 50       30 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         36 (undef, my $dir, undef) = File::Spec->splitpath( __FILE__ );
749 1         25 my @dirs = File::Spec->splitdir($dir);
750              
751 1   66     36 shift @dirs while @dirs && $dirs[0] ne 'blib';
752 1 50       12 return unless @dirs;
753              
754 1 50 33     18 if ( $dirs[1] && $dirs[1] eq 'lib' ) {
755 1         20 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         16 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   184 my $scg = Shell::Config::Generate->new;
770 4         118 $scg->comment(
771             'this script sets the environment needed to build this package.',
772             'generated by: ' . __FILE__,
773             );
774 4         102 $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   650 my($self, $mod) = @_;
784              
785 2         20 my $version = $self->alien_bin_requires->{$mod};
786              
787 2 100       35 unless(eval { $mod->can('new') })
  2         89  
788             {
789 1         5 my $pm = "$mod.pm";
790 1         18 $pm =~ s/::/\//g;
791 1         22 require $pm;
792 1 50       43 $mod->VERSION($version) if $version;
793             }
794              
795 2 100       35 if($mod->can('alien_helper')) {
796 1         17 my $helpers = $mod->alien_helper;
797 1         38 foreach my $k (keys %$helpers) {
798 4         43 my $v = $helpers->{$k};
799 4 100       24 next if defined $self->alien_helper->{$k};
800 3         42 $self->alien_helper->{$k} = $v;
801             }
802             }
803             }
804              
805             sub alien_do_system {
806 12     12 1 21211 my $self = shift;
807 12         95 my $command = shift;
808              
809 12         1388 local %ENV = %ENV;
810              
811 12 50       234 if ($self->config_data( 'msys' )) {
812 0   0     0 $self->alien_bin_requires->{'Alien::MSYS'} ||= 0
813             }
814              
815 12         555 my $config;
816              
817 12         49 foreach my $mod (keys %{ $self->alien_bin_requires }) {
  12         167  
818 1         23 $self->_alien_bin_require($mod);
819              
820 1         3 my %path;
821              
822 1 50       25 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         15 } elsif (eval { $mod->can('bin_dir') }) {
829 1         19 $path{$_} = 1 for $mod->bin_dir;
830             }
831              
832             # remove anything already in PATH
833 1         52 delete $path{$_} for grep { defined $_ } @PATH;
  9         233  
834             # add anything else to start of PATH
835 1         22 unshift @PATH, sort keys %path;
836              
837 1   33     69 $config ||= _shell_config_generate();
838 1         18 $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     302 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         265 foreach my $key (sort keys %{ $self->alien_env })
  12         186  
877             {
878 9         173 my $value = $self->alien_interpolate($self->alien_env->{$key});
879 9 100       86 defined $value ? $ENV{$key} = $value : delete $ENV{$key};
880 9   66     168 $config ||= _shell_config_generate();
881 9         41 $config->set( $key => $value );
882             }
883              
884 12 100       213 if($config) {
885 4 50       31 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         25 local $CWD;
893 4         226 pop @CWD;
894 4         633 $config->generate_file( Shell::Guess->bourne_shell, 'env.sh' );
895 4         2821 $config->generate_file( Shell::Guess->c_shell, 'env.csh' );
896             }
897             }
898              
899 12 100       1920 $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 6 return;
907             }
908              
909             sub alien_do_commands {
910 6     6 1 23 my $self = shift;
911 6         24 my $phase = shift;
912              
913 6         58 my $attr = "alien_${phase}_commands";
914 6         109 my $commands = $self->$attr();
915              
916 6         138 print "\n+ cd $CWD\n";
917              
918 6         320 foreach my $command (@$commands) {
919              
920 8         118 my %result = $self->alien_do_system( $command );
921 8 50       2325 unless ($result{success}) {
922 0         0 carp "External command ($result{command}) failed! Error: $?\n";
923 0         0 return 0;
924             }
925             }
926              
927 6         172 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 210 my $self = shift;
934 42 100       253 my $opts = ref $_[-1] ? pop : { verbose => 1 };
935              
936 42   66     1013 my $verbose = $Verbose || $opts->{verbose};
937              
938             # prevent build process from cwd-ing from underneath us
939 42         950 local $CWD;
940 42         2377 my $initial_cwd = $CWD;
941              
942 42         1067 my @args = map { $self->alien_interpolate($_) } @_;
  67         606  
943              
944 42         1967 print "+ @args\n";
945              
946 42         374 my $old_super_verbose = $self->verbose;
947 42         631 $self->verbose(0);
948             my ($out, $err, $success) =
949             $verbose
950 12     12   210032 ? tee { $self->SUPER::do_system(@args) }
951 30     30   48926 : capture { $self->SUPER::do_system(@args) }
952 42 100       3668 ;
953 42         5444704 $self->verbose($old_super_verbose);
954              
955 42         4123 my %return = (
956             stdout => $out,
957             stderr => $err,
958             success => $success,
959             command => join(' ', @args),
960             );
961              
962             # restore wd
963 42         1898 $CWD = $initial_cwd;
964              
965 42 50       5305 return wantarray ? %return : $return{success}; ## no critic (Policy::Freenode::Wantarray)
966             }
967              
968             sub _alien_execute_helper {
969 44     44   345 my($self, $helper) = @_;
970 44         252 my $code = $self->alien_helper->{$helper};
971 44 100       751 die "no such helper: $helper" unless defined $code;
972              
973 43 100       183 if(ref($code) ne 'CODE') {
974 41         176 my $perl = $code;
975             $code = sub {
976 41     41   6323 my $value = eval $perl; ## no critic (Policy::BuiltinFunctions::ProhibitStringyEval)
977 41 100       148962 die $@ if $@;
978 40         450 $value;
979 41         676 };
980             }
981              
982 43         175 $code->();
983             }
984              
985             sub alien_interpolate {
986 94     94 1 13048 my $self = shift;
987 94         384 my ($string) = @_;
988              
989 94         493 my $prefix = $self->alien_exec_prefix;
990 94         615 my $configure = $self->alien_configure;
991 94         721 my $share = $self->alien_library_destination;
992 94   100     342 my $name = $self->alien_name || '';
993              
994             # substitute:
995             # install location share_dir (placeholder: %s)
996 94         1969 $string =~ s/(?
997             # local exec prefix (ph: %p)
998 94         308 $string =~ s/(?
999             # correct incantation for configure on platform
1000 94         284 $string =~ s/(?
1001             # library name (ph: %n)
1002 94         726 $string =~ s/(?
1003             # current interpreter ($^X) (ph: %x)
1004 94         625 my $perl = $self->perl;
1005 94         1186 $string =~ s/(?
1006 94 50       447 $perl =~ s{\\}{/}g if $^O eq 'MSWin32';
1007 94         286 $string =~ s/(?
1008              
1009             # Version, but only if needed. Complain if needed and not yet
1010             # stored.
1011 94 100       357 if ($string =~ /(?
1012 2         37 my $version = $self->config_data( 'alien_version' );
1013 2 100       62 if ( ! defined( $version ) ) {
1014 1         509 carp "Version substution requested but unable to identify";
1015             } else {
1016 1         19 $string =~ s/(?
1017             }
1018             }
1019              
1020 94         711 $string =~ s/(?_alien_execute_helper($1)/eg;
  44         373  
1021              
1022             #remove escapes (%%)
1023 92         325 $string =~ s/\%(?=\%)//g;
1024              
1025 92         636 return $string;
1026             }
1027              
1028             sub alien_exec_prefix {
1029 95     95 0 245 my $self = shift;
1030 95 50       543 if ( $self->is_windowsish ) {
1031 0         0 return '';
1032             } else {
1033 95         4233 return './';
1034             }
1035             }
1036              
1037             sub alien_configure {
1038 94     94 0 392 my $self = shift;
1039 94         193 my $configure;
1040 94 50       641 if ($self->config_data( 'msys' )) {
1041 0         0 $configure = 'sh configure';
1042             } else {
1043 94         2637 $configure = './configure';
1044             }
1045 94 50       897 if ($self->alien_autoconf_with_pic) {
1046 94         1367 $configure .= ' --with-pic';
1047             }
1048 94         465 $configure;
1049             }
1050              
1051             ########################
1052             # Post-Build Methods #
1053             ########################
1054              
1055             sub alien_load_pkgconfig {
1056 3     3 0 24 my $self = shift;
1057              
1058 3         29 my $dir = _catdir($self->config_data( 'working_directory' ));
1059 3         247 my $pc_files = $self->rscan_dir( $dir, qr/\.pc$/ );
1060              
1061             my %pc_objects = map {
1062 3         1655 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       75 $pc_objects{_manual} = $self->alien_generate_manual_pkgconfig($dir)
1068             or croak "Could not autogenerate pkgconfig information";
1069              
1070 3         30 $self->config_data( pkgconfig => \%pc_objects );
1071 3         354 return \%pc_objects;
1072             }
1073              
1074             sub alien_refresh_manual_pkgconfig {
1075 3     3 0 25 my $self = shift;
1076 3         15 my ($dir) = @_;
1077              
1078 3         37 my $pc_objects = $self->config_data( 'pkgconfig' );
1079 3 50       137 $pc_objects->{_manual} = $self->alien_generate_manual_pkgconfig($dir)
1080             or croak "Could not autogenerate pkgconfig information";
1081              
1082 3         33 $self->config_data( pkgconfig => $pc_objects );
1083              
1084 3         881 return 1;
1085             }
1086              
1087             sub alien_generate_manual_pkgconfig {
1088 10     10 0 8214 my $self = shift;
1089 10         97 my ($dir) = _catdir(shift);
1090              
1091 10         145 my $paths = $self->alien_find_lib_paths($dir);
1092              
1093             my @L =
1094 4         19 map { "-L$_" }
1095 4         23 map { _catdir( '${pcfiledir}', $_ ) }
1096 10         45 @{$paths->{lib}};
  10         45  
1097              
1098 10         57 my $provides_libs = $self->alien_provides_libs;
1099              
1100             #if no provides_libs then generate -l list from found files
1101 10 100       160 unless ($provides_libs) {
1102 9         25 my @files = map { "-l$_" } @{$paths->{lib_files}};
  9         67  
  9         39  
1103 9         84 $provides_libs = join( ' ', @files );
1104             }
1105              
1106 10         88 my $libs = join( ' ', @L, $provides_libs );
1107              
1108             my @I =
1109 4         23 map { "-I$_" }
1110 4         17 map { _catdir( '${pcfiledir}', $_ ) }
1111 10         56 @{$paths->{inc}};
  10         35  
1112              
1113 10         98 my $provides_cflags = $self->alien_provides_cflags;
1114 10 50       127 push @I, $provides_cflags if $provides_cflags;
1115 10         33 my $cflags = join( ' ', @I );
1116              
1117 10   100     50 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         1046 return $manual_pc;
1130             }
1131              
1132             sub _alien_file_pattern_dynamic {
1133 14     14   44 my $self = shift;
1134 14         74 my $ext = $self->config('so'); #platform specific .so extension
1135 14         436 return qr/\.[\d.]*(?<=\.)$ext[\d.]*(?
1136             };
1137              
1138             sub _alien_file_pattern_static {
1139 14     14   47 my $self = shift;
1140 14         98 my $ext = quotemeta $self->config('lib_ext');
1141 14         1202 return qr/(\.h|$ext)$/;
1142             }
1143              
1144             sub alien_find_lib_paths {
1145 14     14 0 18756 my $self = shift;
1146 14         62 my ($dir) = @_;
1147              
1148 14         135 my $libs = $self->alien_provides_libs;
1149 14         162 my @libs;
1150 14 100       77 @libs = map { my $f = $_; $f =~ s/^-l//; $f } grep { /^-l/ } split /\s+/, $libs if $libs;
  2         6  
  2         8  
  2         14  
  2         29  
1151              
1152 14         61 my (@lib_files, @lib_paths, @inc_paths);
1153              
1154 14         94 foreach my $file_pattern ($self->_alien_file_pattern_static, $self->_alien_file_pattern_dynamic) {
1155              
1156             my @files =
1157 80         3866 map { File::Spec->abs2rel( $_, $dir ) } # make relative to $dir
1158 92         1501 grep { ! -d }
1159 28         80 @{ $self->_rscan_destdir( $dir, $file_pattern ) };
  28         146  
1160              
1161 28         153 for (@files) {
1162              
1163 80         2431 my ($file, $path, $ext) = fileparse( $_, $file_pattern );
1164 80 100       251 next unless $ext; # just in case
1165              
1166 72         347 $path = File::Spec->catdir($path); # remove trailing /
1167              
1168 72 100       201 if ($ext eq '.h') {
1169 32         72 push @inc_paths, $path;
1170 32         84 next;
1171             }
1172              
1173 40         136 $file =~ s/^lib//;
1174              
1175 40 100       110 if (@libs) {
1176 14 100   14   54 next unless any { $file eq $_ } @libs;
  14         51  
1177             }
1178              
1179 32 100   38   184 next if any { $file eq $_ } @lib_files;
  38         110  
1180              
1181 20         75 push @lib_files, $file;
1182 20         57 push @lib_paths, $path;
1183             }
1184             }
1185              
1186 14         136 @lib_files = uniq @lib_files;
1187 14         73 @lib_files = sort @lib_files;
1188              
1189 14         67 @lib_paths = uniq @lib_paths;
1190 14         64 @inc_paths = uniq @inc_paths;
1191              
1192 14         192 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   97 my($self, $dir, $pattern) = @_;
1261 28         259 my $destdir = $self->destdir;
1262 28 50       342 $dir = _catdir($destdir, $dir) if defined $destdir;
1263 28         141 my $files = $self->rscan_dir($dir, $pattern);
1264 28 50       15098 $files = [ map { my $dir = $_; $dir =~ s/^$destdir//; $dir } @$files ] if defined $destdir;
  0         0  
  0         0  
  0         0  
1265 28         111 $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   1369 my $dir = File::Spec->catdir(@_);
1276 130 50       615 $dir =~ s{\\}{/}g if $^O eq 'MSWin32';
1277 130         346 $dir;
1278             }
1279              
1280             1;
1281              
1282             =pod
1283              
1284             =encoding UTF-8
1285              
1286             =head1 NAME
1287              
1288             Alien::Base::ModuleBuild - A Module::Build subclass for building Alien:: modules and their libraries
1289              
1290             =head1 VERSION
1291              
1292             version 1.15
1293              
1294             =head1 SYNOPSIS
1295              
1296             In your Build.PL:
1297              
1298             use Alien::Base::ModuleBuild;
1299            
1300             my $builder = Alien::Base::ModuleBuild->new(
1301             module_name => 'Alien::MyLibrary',
1302            
1303             configure_requires => {
1304             'Alien::Base::ModuleBuild' => '0.005',
1305             'Module::Build' => '0.28'
1306             },
1307             requires => {
1308             'Alien::Base' => '0.005',
1309             },
1310            
1311             alien_name => 'mylibrary', # the pkg-config name if you want
1312             # to use pkg-config to discover
1313             # system version of the mylibrary
1314            
1315             alien_repository => {
1316             protocol => 'http',
1317             host => 'myhost.org',
1318             location => '/path/to/tarballs',
1319             pattern => qr{^mylibrary-([0-9\.]+)\.tar\.gz$},
1320             },
1321            
1322             # this is the default:
1323             alien_build_commands => [
1324             "%c --prefix=%s", # %c is a platform independent version of ./configure
1325             "make",
1326             ],
1327            
1328             # this is the default for install:
1329             alien_install_commands => [
1330             "make install",
1331             ],
1332            
1333             alien_isolate_dynamic => 1,
1334             );
1335              
1336             =head1 DESCRIPTION
1337              
1338             B: Please consider for new development of Ls that you use
1339             L and L instead. Like this module they work
1340             with L. Unlike this module they are more easily customized
1341             and handle a number of corner cases better. For a good place to start,
1342             please see L. Although the
1343             Alien-Base / Alien-Build team will continue to maintain this module,
1344             (we will continue to fix bugs where appropriate), we aren't adding any
1345             new features to this module.
1346              
1347             This is a subclass of L, that with L allows
1348             for easy creation of Alien distributions. This module is used during the
1349             build step of your distribution. When properly configured it will
1350              
1351             =over 4
1352              
1353             =item use pkg-config to find and use the system version of the library
1354              
1355             =item download, build and install the library if the system does not provide it
1356              
1357             =back
1358              
1359             =head1 METHODS
1360              
1361             =head2 alien_check_installed_version
1362              
1363             [version 0.001]
1364              
1365             my $version = $abmb->alien_check_installed_version;
1366              
1367             This function determines if the library is already installed as part of
1368             the operating system, and returns the version as a string. If it can't
1369             be detected then it should return empty list.
1370              
1371             The default implementation relies on C, but you will probably
1372             want to override this with your own implementation if the package you are
1373             building does not use C.
1374              
1375             =head2 alien_check_built_version
1376              
1377             [version 0.006]
1378              
1379             my $version = $amb->alien_check_built_version;
1380              
1381             This function determines the version of the library after it has been
1382             built from source. This function only gets called if the operating
1383             system version can not be found and the package is successfully built.
1384             The version is returned on success. If the version can't be detected
1385             then it should return empty list. Note that failing to detect a version
1386             is considered a failure and the corresponding C<./Build> action will
1387             fail!
1388              
1389             Any string is valid as a version as far as L is concerned.
1390             The most useful value would be a number or dotted decimal that most
1391             software developers recognize and that software tools can differentiate.
1392             In some cases packages will not have a clear version number, in which
1393             case the string C would be a reasonable choice.
1394              
1395             The default implementation relies on C, and other heuristics,
1396             but you will probably want to override this with your own implementation
1397             if the package you are building does not use C.
1398              
1399             When this method is called, the current working directory will be the
1400             build root.
1401              
1402             If you see an error message like this:
1403              
1404             Library looks like it installed, but no version was determined
1405              
1406             After the package is built from source code then you probably need to
1407             provide an implementation for this method.
1408              
1409             =head2 alien_extract_archive
1410              
1411             [version 0.024]
1412              
1413             my $dir = $amb->alien_extract_archive($filename);
1414              
1415             This function unpacks the given archive and returns the directory
1416             containing the unpacked files.
1417              
1418             The default implementation relies on L that is able
1419             to handle most common formats. In order to handle other formats or
1420             archives requiring some special treatment you may want to override
1421             this method.
1422              
1423             =head2 alien_do_system
1424              
1425             [version 0.024]
1426              
1427             my %result = $amb->alien_do_system($cmd)
1428              
1429             Similar to L, also sets the path and several
1430             environment variables in accordance to the object configuration
1431             (i.e. C) and performs the interpolation of the
1432             patterns described in L
1433             INTERPOLATION>.
1434              
1435             Returns a set of key value pairs including C, C,
1436             C and C.
1437              
1438             =head2 alien_do_commands
1439              
1440             $amb->alien_do_commands($phase);
1441              
1442             Executes the commands for the given phase.
1443              
1444             =head2 alien_interpolate
1445              
1446             my $string = $amb->alien_interpolate($string);
1447              
1448             Takes the input string and interpolates the results.
1449              
1450             =head1 GUIDE TO DOCUMENTATION
1451              
1452             The documentation for C is broken up into sections:
1453              
1454             =over
1455              
1456             =item General Usage (L)
1457              
1458             This is the landing document for L's parent class.
1459             It describes basic usage and background information.
1460             Its main purpose is to assist the user who wants to learn how to invoke
1461             and control C scripts at the command line.
1462              
1463             It also lists the extra documentation for its use. Users and authors of Alien::
1464             modules should familiarize themselves with these documents. L
1465             is of particular importance to authors.
1466              
1467             =item Alien-Specific Usage (L)
1468              
1469             This is the document you are currently reading.
1470              
1471             =item Authoring Reference (L)
1472              
1473             This document describes the structure and organization of
1474             C based projects, beyond that contained in
1475             C, and the relevant concepts needed by authors who are
1476             writing F scripts for a distribution or controlling
1477             C processes programmatically.
1478              
1479             Note that as it contains information both for the build and use phases of
1480             L projects, it is located in the upper namespace.
1481              
1482             =item API Reference (L)
1483              
1484             This is a reference to the C API beyond that contained
1485             in C.
1486              
1487             =back
1488              
1489             =head1 ENVIRONMENT
1490              
1491             =over 4
1492              
1493             =item B
1494              
1495             Enables verbose output from L.
1496              
1497             =item B
1498              
1499             Skips checking for an installed version and forces reinstalling the Alien target.
1500              
1501             =item B
1502              
1503             Set to 'share' or 'system' to override the install type. Set to 'default' or unset
1504             to restore the default.
1505              
1506             =item B
1507              
1508             Set to a true value to install to an arch-specific directory.
1509              
1510             =item B
1511              
1512             Overrides $KEY in the given module's repository configuration matching $PROTOCOL.
1513             For example, C.
1514              
1515             =back
1516              
1517             =head1 SEE ALSO
1518              
1519             =over
1520              
1521             =item L
1522              
1523             =item L
1524              
1525             =item L
1526              
1527             =item L
1528              
1529             =back
1530              
1531             =head1 THANKS
1532              
1533             Thanks also to
1534              
1535             =over
1536              
1537             =item Christian Walde (Mithaldu)
1538              
1539             For productive conversations about component interoperability.
1540              
1541             =item kmx
1542              
1543             For writing Alien::Tidyp from which I drew many of my initial ideas.
1544              
1545             =item David Mertens (run4flat)
1546              
1547             For productive conversations about implementation.
1548              
1549             =item Mark Nunberg (mordy, mnunberg)
1550              
1551             For graciously teaching me about rpath and dynamic loading,
1552              
1553             =back
1554              
1555             =head1 AUTHOR
1556              
1557             Original author: Joel A Berger Ejoel.a.berger@gmail.comE
1558              
1559             Current maintainer: Graham Ollis Eplicease@cpan.orgE
1560              
1561             Contributors:
1562              
1563             David Mertens (run4flat)
1564              
1565             Mark Nunberg (mordy, mnunberg)
1566              
1567             Christian Walde (Mithaldu)
1568              
1569             Brian Wightman (MidLifeXis)
1570              
1571             Graham Ollis (plicease)
1572              
1573             Zaki Mughal (zmughal)
1574              
1575             mohawk2
1576              
1577             Vikas N Kumar (vikasnkumar)
1578              
1579             Flavio Poletti (polettix)
1580              
1581             Salvador Fandiño (salva)
1582              
1583             Gianni Ceccarelli (dakkar)
1584              
1585             Pavel Shaydo (zwon, trinitum)
1586              
1587             Kang-min Liu (劉康民, gugod)
1588              
1589             Nicholas Shipp (nshp)
1590              
1591             Petr Pisar (ppisar)
1592              
1593             Alberto Simões (ambs)
1594              
1595             =head1 COPYRIGHT AND LICENSE
1596              
1597             This software is copyright (c) 2012-2020 by Joel A Berger.
1598              
1599             This is free software; you can redistribute it and/or modify it under
1600             the same terms as the Perl 5 programming language system itself.
1601              
1602             =cut
1603              
1604             __END__