1package Alien::Build; 2 3use strict; 4use warnings; 5use 5.008004; 6use Path::Tiny (); 7use Carp (); 8use File::chdir; 9use JSON::PP (); 10use Env qw( @PATH @PKG_CONFIG_PATH ); 11use Config (); 12use Alien::Build::Log; 13 14# ABSTRACT: Build external dependencies for use in CPAN 15our $VERSION = '2.45'; # VERSION 16 17 18sub _path { goto \&Path::Tiny::path } 19 20 21sub new 22{ 23 my($class, %args) = @_; 24 my $self = bless { 25 install_prop => { 26 root => _path($args{root} || "_alien")->absolute->stringify, 27 patch => (defined $args{patch}) ? _path($args{patch})->absolute->stringify : undef, 28 }, 29 runtime_prop => { 30 alien_build_version => $Alien::Build::VERSION || 'dev', 31 }, 32 plugin_instance_prop => {}, 33 bin_dir => [], 34 pkg_config_path => [], 35 aclocal_path => [], 36 }, $class; 37 38 $self->meta->filename( 39 $args{filename} || do { 40 my(undef, $filename) = caller; 41 _path($filename)->absolute->stringify; 42 } 43 ); 44 45 if($args{meta_prop}) 46 { 47 $self->meta->prop->{$_} = $args{meta_prop}->{$_} for keys %{ $args{meta_prop} }; 48 } 49 50 $self; 51} 52 53 54my $count = 0; 55 56sub load 57{ 58 my(undef, $alienfile, @args) = @_; 59 60 my $rcfile = Path::Tiny->new($ENV{ALIEN_BUILD_RC} || '~/.alienbuild/rc.pl')->absolute; 61 if(-r $rcfile) 62 { 63 require Alien::Build::rc; 64 package Alien::Build::rc; 65 require $rcfile; 66 } 67 68 unless(-r $alienfile) 69 { 70 Carp::croak "Unable to read alienfile: $alienfile"; 71 } 72 73 my $file = _path $alienfile; 74 my $name = $file->parent->basename; 75 $name =~ s/^alien-//i; 76 $name =~ s/[^a-z]//g; 77 $name = 'x' if $name eq ''; 78 $name = ucfirst $name; 79 80 my $class = "Alien::Build::Auto::$name@{[ $count++ ]}"; 81 82 { no strict 'refs'; 83 @{ "${class}::ISA" } = ('Alien::Build'); 84 *{ "${class}::Alienfile::meta" } = sub { 85 $class =~ s{::Alienfile$}{}; 86 $class->meta; 87 }}; 88 89 my @preload = qw( Core::Setup Core::Download Core::FFI Core::Override Core::CleanInstall ); 90 push @preload, @Alien::Build::rc::PRELOAD; 91 push @preload, split /;/, $ENV{ALIEN_BUILD_PRELOAD} 92 if defined $ENV{ALIEN_BUILD_PRELOAD}; 93 94 my @postload = qw( Core::Legacy Core::Gather Core::Tail ); 95 push @postload, @Alien::Build::rc::POSTLOAD; 96 push @postload, split /;/, $ENV{ALIEN_BUILD_POSTLOAD} 97 if defined $ENV{ALIEN_BUILD_POSTLOAD}; 98 99 my $self = $class->new( 100 filename => $file->absolute->stringify, 101 @args, 102 ); 103 104 require alienfile; 105 106 foreach my $preload (@preload) 107 { 108 ref $preload eq 'CODE' ? $preload->($self->meta) : $self->meta->apply_plugin($preload); 109 } 110 111 # TODO: do this without a string eval ? 112 ## no critic 113 eval '# line '. __LINE__ . ' "' . __FILE__ . qq("\n) . qq{ 114 package ${class}::Alienfile; 115 do '@{[ $file->absolute->stringify ]}'; 116 die \$\@ if \$\@; 117 }; 118 die $@ if $@; 119 ## use critic 120 121 foreach my $postload (@postload) 122 { 123 ref $postload eq 'CODE' ? $postload->($self->meta) : $self->meta->apply_plugin($postload); 124 } 125 126 $self->{args} = \@args; 127 unless(defined $self->meta->prop->{arch}) 128 { 129 $self->meta->prop->{arch} = 1; 130 } 131 132 unless(defined $self->meta->prop->{network}) 133 { 134 $self->meta->prop->{network} = 1; 135 ## https://github.com/PerlAlien/Alien-Build/issues/23#issuecomment-341114414 136 #$self->meta->prop->{network} = 0 if $ENV{NO_NETWORK_TESTING}; 137 $self->meta->prop->{network} = 0 if (defined $ENV{ALIEN_INSTALL_NETWORK}) && ! $ENV{ALIEN_INSTALL_NETWORK}; 138 } 139 140 unless(defined $self->meta->prop->{local_source}) 141 { 142 if(! defined $self->meta->prop->{start_url}) 143 { 144 $self->meta->prop->{local_source} = 0; 145 } 146 # we assume URL schemes are at least two characters, that 147 # way Windows absolute paths can be used as local start_url 148 elsif($self->meta->prop->{start_url} =~ /^([a-z]{2,}):/i) 149 { 150 my $scheme = $1; 151 $self->meta->prop->{local_source} = $scheme eq 'file'; 152 } 153 else 154 { 155 $self->meta->prop->{local_source} = 1; 156 } 157 } 158 159 return $self; 160} 161 162 163sub resume 164{ 165 my(undef, $alienfile, $root) = @_; 166 my $h = JSON::PP::decode_json(_path("$root/state.json")->slurp); 167 my $self = Alien::Build->load("$alienfile", @{ $h->{args} }); 168 $self->{install_prop} = $h->{install}; 169 $self->{plugin_instance_prop} = $h->{plugin_instance}; 170 $self->{runtime_prop} = $h->{runtime}; 171 $self; 172} 173 174 175sub meta_prop 176{ 177 my($class) = @_; 178 $class->meta->prop; 179} 180 181 182sub install_prop 183{ 184 shift->{install_prop}; 185} 186 187 188sub plugin_instance_prop 189{ 190 my($self, $plugin) = @_; 191 my $instance_id = $plugin->instance_id; 192 $self->{plugin_instance_prop}->{$instance_id} ||= {}; 193} 194 195 196sub runtime_prop 197{ 198 shift->{runtime_prop}; 199} 200 201 202sub hook_prop 203{ 204 shift->{hook_prop}; 205} 206 207sub _command_prop 208{ 209 my($self) = @_; 210 211 return { 212 alien => { 213 install => $self->install_prop, 214 runtime => $self->runtime_prop, 215 hook => $self->hook_prop, 216 meta => $self->meta_prop, 217 }, 218 perl => { 219 config => \%Config::Config, 220 }, 221 env => \%ENV, 222 }; 223} 224 225 226sub checkpoint 227{ 228 my($self) = @_; 229 my $root = $self->root; 230 _path("$root/state.json")->spew( 231 JSON::PP->new->pretty->canonical(1)->ascii->encode({ 232 install => $self->install_prop, 233 runtime => $self->runtime_prop, 234 plugin_instance => $self->{plugin_instance_prop}, 235 args => $self->{args}, 236 }) 237 ); 238 $self; 239} 240 241 242sub root 243{ 244 my($self) = @_; 245 my $root = $self->install_prop->{root}; 246 _path($root)->mkpath unless -d $root; 247 $root; 248} 249 250 251sub install_type 252{ 253 my($self) = @_; 254 $self->{runtime_prop}->{install_type} ||= $self->probe; 255} 256 257 258sub set_prefix 259{ 260 my($self, $prefix) = @_; 261 262 if($self->meta_prop->{destdir}) 263 { 264 $self->runtime_prop->{prefix} = 265 $self->install_prop->{prefix} = $prefix; 266 } 267 else 268 { 269 $self->runtime_prop->{prefix} = $prefix; 270 $self->install_prop->{prefix} = $self->install_prop->{stage}; 271 } 272} 273 274 275sub set_stage 276{ 277 my($self, $dir) = @_; 278 $self->install_prop->{stage} = $dir; 279} 280 281sub _merge 282{ 283 my %h; 284 while(@_) 285 { 286 my $mod = shift; 287 my $ver = shift; 288 if((!defined $h{$mod}) || $ver > $h{$mod}) 289 { $h{$mod} = $ver } 290 } 291 \%h; 292} 293 294 295sub requires 296{ 297 my($self, $phase) = @_; 298 $phase ||= 'any'; 299 my $meta = $self->meta; 300 $phase =~ /^(?:any|configure)$/ 301 ? $meta->{require}->{$phase} || {} 302 : _merge %{ $meta->{require}->{any} }, %{ $meta->{require}->{$phase} }; 303} 304 305 306sub load_requires 307{ 308 my($self, $phase, $eval) = @_; 309 my $reqs = $self->requires($phase); 310 foreach my $mod (keys %$reqs) 311 { 312 my $ver = $reqs->{$mod}; 313 my $check = sub { 314 my $pm = "$mod.pm"; 315 $pm =~ s{::}{/}g; 316 require $pm; 317 }; 318 if($eval) 319 { 320 eval { $check->() }; 321 die "Required $mod @{[ $ver || 'undef' ]}, missing" if $@; 322 } 323 else 324 { 325 $check->(); 326 } 327 # note Test::Alien::Build#alienfile_skip_if_missing_prereqs does a regex 328 # on this diagnostic, so if you change it here, change it there too. 329 die "Required $mod $ver, have @{[ $mod->VERSION || 0 ]}" if $ver && ! $mod->VERSION($ver); 330 331 # allow for requires on Alien::Build or Alien::Base 332 next if $mod eq 'Alien::Build'; 333 next if $mod eq 'Alien::Base'; 334 335 if($mod->can('bin_dir')) 336 { 337 push @{ $self->{bin_dir} }, $mod->bin_dir; 338 } 339 340 if(($mod->can('runtime_prop') && $mod->runtime_prop) 341 || ($mod->isa('Alien::Base') && $mod->install_type('share'))) 342 { 343 for my $dir (qw(lib share)) { 344 my $path = _path($mod->dist_dir)->child("$dir/pkgconfig"); 345 if(-d $path) 346 { 347 push @{ $self->{pkg_config_path} }, $path->stringify; 348 } 349 } 350 my $path = _path($mod->dist_dir)->child('share/aclocal'); 351 if(-d $path) 352 { 353 $path = "$path"; 354 if($^O eq 'MSWin32') 355 { 356 # convert to MSYS path 357 $path =~ s{^([a-z]):}{/$1/}i; 358 } 359 push @{ $self->{aclocal_path} }, $path; 360 } 361 } 362 363 # sufficiently new Autotools have a aclocal_dir which will 364 # give us the directories we need. 365 if($mod eq 'Alien::Autotools' && $mod->can('aclocal_dir')) 366 { 367 push @{ $self->{aclocal_path} }, $mod->aclocal_dir; 368 } 369 370 if($mod->can('alien_helper')) 371 { 372 my $helpers = $mod->alien_helper; 373 foreach my $name (sort keys %$helpers) 374 { 375 my $code = $helpers->{$name}; 376 $self->meta->interpolator->replace_helper($name => $code); 377 } 378 } 379 380 } 381 1; 382} 383 384sub _call_hook 385{ 386 my $self = shift; 387 388 local $ENV{PATH} = $ENV{PATH}; 389 unshift @PATH, @{ $self->{bin_dir} }; 390 391 local $ENV{PKG_CONFIG_PATH} = $ENV{PKG_CONFIG_PATH}; 392 unshift @PKG_CONFIG_PATH, @{ $self->{pkg_config_path} }; 393 394 local $ENV{ACLOCAL_PATH} = $ENV{ACLOCAL_PATH}; 395 # autoconf uses MSYS paths, even for the ACLOCAL_PATH environment variable, so we can't use Env for this. 396 { 397 my @path; 398 @path = split /:/, $ENV{ACLOCAL_PATH} if defined $ENV{ACLOCAL_PATH}; 399 unshift @path, @{ $self->{aclocal_path} }; 400 $ENV{ACLOCAL_PATH} = join ':', @path; 401 } 402 403 my $config = ref($_[0]) eq 'HASH' ? shift : {}; 404 my($name, @args) = @_; 405 406 local $self->{hook_prop} = {}; 407 408 $self->meta->call_hook( $config, $name => $self, @args ); 409} 410 411 412sub probe 413{ 414 my($self) = @_; 415 local $CWD = $self->root; 416 my $dir; 417 418 my $env = $self->_call_hook('override'); 419 my $type; 420 my $error; 421 422 $env = '' if $env eq 'default'; 423 424 if($env eq 'share') 425 { 426 $type = 'share'; 427 } 428 else 429 { 430 $type = eval { 431 $self->_call_hook( 432 { 433 before => sub { 434 $dir = Alien::Build::TempDir->new($self, "probe"); 435 $CWD = "$dir"; 436 }, 437 after => sub { 438 $CWD = $self->root; 439 }, 440 ok => 'system', 441 continue => sub { 442 if($_[0] eq 'system') 443 { 444 foreach my $name (qw( probe_class probe_instance_id )) 445 { 446 if(exists $self->hook_prop->{$name} && defined $self->hook_prop->{$name}) 447 { 448 $self->install_prop->{"system_$name"} = $self->hook_prop->{$name}; 449 } 450 } 451 return undef; 452 } 453 else 454 { 455 return 1; 456 } 457 }, 458 }, 459 'probe', 460 ); 461 }; 462 $error = $@; 463 $type = 'share' unless defined $type; 464 } 465 466 if($error) 467 { 468 if($env eq 'system') 469 { 470 die $error; 471 } 472 $self->log("error in probe (will do a share install): $@"); 473 $self->log("Don't panic, we will attempt a share build from source if possible."); 474 $self->log("Do not file a bug unless you expected a system install to succeed."); 475 $type = 'share'; 476 } 477 478 if($env && $env ne $type) 479 { 480 die "requested $env install not available"; 481 } 482 483 if($type !~ /^(system|share)$/) 484 { 485 Carp::croak "probe hook returned something other than system or share: $type"; 486 } 487 488 if($type eq 'share' && (!$self->meta_prop->{network}) && (!$self->meta_prop->{local_source})) 489 { 490 $self->log("install type share requested or detected, but network fetch is turned off"); 491 $self->log("see https://metacpan.org/pod/Alien::Build::Manual::FAQ#Network-fetch-is-turned-off"); 492 Carp::croak "network fetch is turned off"; 493 } 494 495 $self->runtime_prop->{install_type} = $type; 496 497 $type; 498} 499 500 501sub download 502{ 503 my($self) = @_; 504 505 return $self unless $self->install_type eq 'share'; 506 return $self if $self->install_prop->{complete}->{download}; 507 508 if($self->meta->has_hook('download')) 509 { 510 my $tmp; 511 local $CWD; 512 my $valid = 0; 513 514 $self->_call_hook( 515 { 516 before => sub { 517 $tmp = Alien::Build::TempDir->new($self, "download"); 518 $CWD = "$tmp"; 519 }, 520 verify => sub { 521 my @list = grep { $_->basename !~ /^\./, } _path('.')->children; 522 523 my $count = scalar @list; 524 525 if($count == 0) 526 { 527 die "no files downloaded"; 528 } 529 elsif($count == 1) 530 { 531 my($archive) = $list[0]; 532 if(-d $archive) 533 { 534 $self->log("single dir, assuming directory"); 535 } 536 else 537 { 538 $self->log("single file, assuming archive"); 539 } 540 $self->install_prop->{download} = $archive->absolute->stringify; 541 $self->install_prop->{complete}->{download} = 1; 542 $valid = 1; 543 } 544 else 545 { 546 $self->log("multiple files, assuming directory"); 547 $self->install_prop->{complete}->{download} = 1; 548 $self->install_prop->{download} = _path('.')->absolute->stringify; 549 $valid = 1; 550 } 551 }, 552 after => sub { 553 $CWD = $self->root; 554 }, 555 }, 556 'download', 557 ); 558 559 return $self if $valid; 560 } 561 else 562 { 563 # This will call the default download hook 564 # defined in Core::Download since the recipe 565 # does not provide a download hook 566 return $self->_call_hook('download'); 567 } 568 569 die "download failed"; 570} 571 572 573sub fetch 574{ 575 my $self = shift; 576 $self->_call_hook( 'fetch' => @_ ); 577} 578 579 580sub decode 581{ 582 my($self, $res) = @_; 583 $self->_call_hook( decode => $res ); 584} 585 586 587sub prefer 588{ 589 my($self, $res) = @_; 590 $self->_call_hook( prefer => $res ); 591} 592 593 594sub extract 595{ 596 my($self, $archive) = @_; 597 598 $archive ||= $self->install_prop->{download}; 599 600 unless(defined $archive) 601 { 602 die "tried to call extract before download"; 603 } 604 605 my $nick_name = 'build'; 606 607 if($self->meta_prop->{out_of_source}) 608 { 609 $nick_name = 'extract'; 610 my $extract = $self->install_prop->{extract}; 611 return $extract if defined $extract && -d $extract; 612 } 613 614 my $tmp; 615 local $CWD; 616 my $ret; 617 618 $self->_call_hook({ 619 620 before => sub { 621 # called build instead of extract, because this 622 # will be used for the build step, and technically 623 # extract is a substage of build anyway. 624 $tmp = Alien::Build::TempDir->new($self, $nick_name); 625 $CWD = "$tmp"; 626 }, 627 verify => sub { 628 629 my $path = '.'; 630 if($self->meta_prop->{out_of_source} && $self->install_prop->{extract}) 631 { 632 $path = $self->install_prop->{extract}; 633 } 634 635 my @list = grep { $_->basename !~ /^\./ && $_->basename ne 'pax_global_header' } _path($path)->children; 636 637 my $count = scalar @list; 638 639 if($count == 0) 640 { 641 die "no files extracted"; 642 } 643 elsif($count == 1 && -d $list[0]) 644 { 645 $ret = $list[0]->absolute->stringify; 646 } 647 else 648 { 649 $ret = "$tmp"; 650 } 651 652 }, 653 after => sub { 654 $CWD = $self->root; 655 }, 656 657 }, 'extract', $archive); 658 659 $self->install_prop->{extract} ||= $ret; 660 $ret ? $ret : (); 661} 662 663 664sub build 665{ 666 my($self) = @_; 667 668 # save the evironment, in case some plugins decide 669 # to alter it. Or us! See just a few lines below. 670 local %ENV = %ENV; 671 672 my $stage = _path($self->install_prop->{stage}); 673 $stage->mkpath; 674 675 my $tmp; 676 677 if($self->install_type eq 'share') 678 { 679 foreach my $suffix ('', '_ffi') 680 { 681 local $CWD; 682 delete $ENV{DESTDIR} unless $self->meta_prop->{destdir}; 683 684 my %env_meta = %{ $self->meta_prop ->{env} || {} }; 685 my %env_inst = %{ $self->install_prop->{env} || {} }; 686 687 if($self->meta_prop->{env_interpolate}) 688 { 689 foreach my $key (keys %env_meta) 690 { 691 $env_meta{$key} = $self->meta->interpolator->interpolate($env_meta{$key}); 692 } 693 } 694 695 %ENV = (%ENV, %env_meta); 696 %ENV = (%ENV, %env_inst); 697 698 my $destdir; 699 700 $self->_call_hook( 701 { 702 before => sub { 703 if($self->meta_prop->{out_of_source}) 704 { 705 $self->extract; 706 $CWD = $tmp = Alien::Build::TempDir->new($self, 'build'); 707 } 708 else 709 { 710 $CWD = $tmp = $self->extract; 711 } 712 if($self->meta_prop->{destdir}) 713 { 714 $destdir = Alien::Build::TempDir->new($self, 'destdir'); 715 $ENV{DESTDIR} = "$destdir"; 716 } 717 $self->_call_hook({ all => 1 }, "patch${suffix}"); 718 }, 719 after => sub { 720 $destdir = "$destdir" if $destdir; 721 }, 722 }, "build${suffix}"); 723 724 $self->install_prop->{"_ab_build@{[ $suffix || '_share' ]}"} = "$CWD"; 725 726 $self->_call_hook("gather@{[ $suffix || '_share' ]}"); 727 } 728 } 729 730 elsif($self->install_type eq 'system') 731 { 732 local $CWD = $self->root; 733 my $dir; 734 735 $self->_call_hook( 736 { 737 before => sub { 738 $dir = Alien::Build::TempDir->new($self, "gather"); 739 $CWD = "$dir"; 740 }, 741 after => sub { 742 $CWD = $self->root; 743 }, 744 }, 745 'gather_system', 746 ); 747 748 $self->install_prop->{finished} = 1; 749 $self->install_prop->{complete}->{gather_system} = 1; 750 } 751 752 $self; 753} 754 755 756sub test 757{ 758 my($self) = @_; 759 760 if($self->install_type eq 'share') 761 { 762 foreach my $suffix ('_share', '_ffi') 763 { 764 if($self->meta->has_hook("test$suffix")) 765 { 766 my $dir = $self->install_prop->{"_ab_build$suffix"}; 767 Carp::croak("no build directory to run tests") unless $dir && -d $dir; 768 local $CWD = $dir; 769 $self->_call_hook("test$suffix"); 770 } 771 } 772 } 773 else 774 { 775 if($self->meta->has_hook("test_system")) 776 { 777 my $dir = Alien::Build::TempDir->new($self, "test"); 778 local $CWD = "$dir"; 779 $self->_call_hook("test_system"); 780 } 781 } 782 783} 784 785 786sub clean_install 787{ 788 my($self) = @_; 789 if($self->install_type eq 'share') 790 { 791 $self->_call_hook("clean_install"); 792 } 793} 794 795 796sub system 797{ 798 my($self, $command, @args) = @_; 799 800 my $prop = $self->_command_prop; 801 802 ($command, @args) = map { 803 $self->meta->interpolator->interpolate($_, $prop) 804 } ($command, @args); 805 806 $self->log("+ $command @args"); 807 808 scalar @args 809 ? system $command, @args 810 : system $command; 811} 812 813 814sub log 815{ 816 my(undef, $message) = @_; 817 my $caller = [caller]; 818 chomp $message; 819 foreach my $line (split /\n/, $message) 820 { 821 Alien::Build::Log->default->log( 822 caller => $caller, 823 message => $line, 824 ); 825 } 826} 827 828 829{ 830 my %meta; 831 832 sub meta 833 { 834 my($class) = @_; 835 $class = ref $class if ref $class; 836 $meta{$class} ||= Alien::Build::Meta->new( class => $class ); 837 } 838} 839 840package Alien::Build::Meta; 841 842our @CARP_NOT = qw( alienfile ); 843 844sub new 845{ 846 my($class, %args) = @_; 847 my $self = bless { 848 phase => 'any', 849 build_suffix => '', 850 require => { 851 any => {}, 852 share => {}, 853 system => {}, 854 }, 855 around => {}, 856 prop => {}, 857 %args, 858 }, $class; 859 $self; 860} 861 862 863sub prop 864{ 865 shift->{prop}; 866} 867 868sub filename 869{ 870 my($self, $new) = @_; 871 $self->{filename} = $new if defined $new; 872 $self->{filename}; 873} 874 875 876sub add_requires 877{ 878 my $self = shift; 879 my $phase = shift; 880 while(@_) 881 { 882 my $module = shift; 883 my $version = shift; 884 my $old = $self->{require}->{$phase}->{$module}; 885 if((!defined $old) || $version > $old) 886 { $self->{require}->{$phase}->{$module} = $version } 887 } 888 $self; 889} 890 891 892sub interpolator 893{ 894 my($self, $new) = @_; 895 if(defined $new) 896 { 897 if(defined $self->{intr}) 898 { 899 Carp::croak "tried to set interpolator twice"; 900 } 901 if(ref $new) 902 { 903 $self->{intr} = $new; 904 } 905 else 906 { 907 $self->{intr} = $new->new; 908 } 909 } 910 elsif(!defined $self->{intr}) 911 { 912 require Alien::Build::Interpolate::Default; 913 $self->{intr} = Alien::Build::Interpolate::Default->new; 914 } 915 $self->{intr}; 916} 917 918 919sub has_hook 920{ 921 my($self, $name) = @_; 922 defined $self->{hook}->{$name}; 923} 924 925 926sub _instr 927{ 928 my($self, $name, $instr) = @_; 929 if(ref($instr) eq 'CODE') 930 { 931 return $instr; 932 } 933 elsif(ref($instr) eq 'ARRAY') 934 { 935 my %phase = ( 936 download => 'share', 937 fetch => 'share', 938 decode => 'share', 939 prefer => 'share', 940 extract => 'share', 941 patch => 'share', 942 patch_ffi => 'share', 943 build => 'share', 944 build_ffi => 'share', 945 stage => 'share', 946 gather_ffi => 'share', 947 gather_share => 'share', 948 gather_system => 'system', 949 test_ffi => 'share', 950 test_share => 'share', 951 test_system => 'system', 952 ); 953 require Alien::Build::CommandSequence; 954 my $seq = Alien::Build::CommandSequence->new(@$instr); 955 $seq->apply_requirements($self, $phase{$name} || 'any'); 956 return $seq; 957 } 958 else 959 { 960 Carp::croak "type not supported as a hook"; 961 } 962} 963 964sub register_hook 965{ 966 my($self, $name, $instr) = @_; 967 push @{ $self->{hook}->{$name} }, _instr $self, $name, $instr; 968 $self; 969} 970 971 972sub default_hook 973{ 974 my($self, $name, $instr) = @_; 975 $self->{default_hook}->{$name} = _instr $self, $name, $instr; 976 $self; 977} 978 979 980sub around_hook 981{ 982 my($self, $name, $code) = @_; 983 if(my $old = $self->{around}->{$name}) 984 { 985 # this is the craziest shit I have ever 986 # come up with. 987 $self->{around}->{$name} = sub { 988 my $orig = shift; 989 $code->(sub { $old->($orig, @_) }, @_); 990 }; 991 } 992 else 993 { 994 $self->{around}->{$name} = $code; 995 } 996} 997 998sub after_hook 999{ 1000 my($self, $name, $code) = @_; 1001 $self->around_hook( 1002 $name => sub { 1003 my $orig = shift; 1004 my $ret = $orig->(@_); 1005 $code->(@_); 1006 $ret; 1007 } 1008 ); 1009} 1010 1011sub before_hook 1012{ 1013 my($self, $name, $code) = @_; 1014 $self->around_hook( 1015 $name => sub { 1016 my $orig = shift; 1017 $code->(@_); 1018 my $ret = $orig->(@_); 1019 $ret; 1020 } 1021 ); 1022} 1023 1024 1025sub call_hook 1026{ 1027 my $self = shift; 1028 my %args = ref $_[0] ? %{ shift() } : (); 1029 my($name, @args) = @_; 1030 my $error; 1031 1032 my @hooks = @{ $self->{hook}->{$name} || []}; 1033 1034 if(@hooks == 0) 1035 { 1036 if(defined $self->{default_hook}->{$name}) 1037 { 1038 @hooks = ($self->{default_hook}->{$name}) 1039 } 1040 elsif(!$args{all}) 1041 { 1042 Carp::croak "No hooks registered for $name"; 1043 } 1044 } 1045 1046 my $value; 1047 1048 foreach my $hook (@hooks) 1049 { 1050 if(eval { $args[0]->isa('Alien::Build') }) 1051 { 1052 %{ $args[0]->{hook_prop} } = ( 1053 name => $name, 1054 ); 1055 } 1056 1057 my $wrapper = $self->{around}->{$name} || sub { my $code = shift; $code->(@_) }; 1058 my $value; 1059 $args{before}->() if $args{before}; 1060 if(ref($hook) eq 'CODE') 1061 { 1062 $value = eval { 1063 my $value = $wrapper->(sub { $hook->(@_) }, @args); 1064 $args{verify}->('code') if $args{verify}; 1065 $value; 1066 }; 1067 } 1068 else 1069 { 1070 $value = $wrapper->(sub { 1071 eval { 1072 $hook->execute(@_); 1073 $args{verify}->('command') if $args{verify}; 1074 }; 1075 defined $args{ok} ? $args{ok} : 1; 1076 }, @args); 1077 } 1078 $error = $@; 1079 $args{after}->() if $args{after}; 1080 if($args{all}) 1081 { 1082 die if $error; 1083 } 1084 else 1085 { 1086 next if $error; 1087 next if $args{continue} && $args{continue}->($value); 1088 return $value; 1089 } 1090 } 1091 1092 die $error if $error && ! $args{all}; 1093 1094 $value; 1095} 1096 1097 1098sub apply_plugin 1099{ 1100 my($self, $name, @args) = @_; 1101 1102 my $class; 1103 my $pm; 1104 my $found; 1105 1106 if($name =~ /^=(.*)$/) 1107 { 1108 $class = $1; 1109 $pm = "$class.pm"; 1110 $pm =~ s!::!/!g; 1111 $found = 1; 1112 } 1113 1114 if($name !~ /::/ && !$found) 1115 { 1116 foreach my $inc (@INC) 1117 { 1118 # TODO: allow negotiators to work with @INC hooks 1119 next if ref $inc; 1120 my $file = Path::Tiny->new("$inc/Alien/Build/Plugin/$name/Negotiate.pm"); 1121 if(-r $file) 1122 { 1123 $class = "Alien::Build::Plugin::${name}::Negotiate"; 1124 $pm = "Alien/Build/Plugin/$name/Negotiate.pm"; 1125 $found = 1; 1126 last; 1127 } 1128 } 1129 } 1130 1131 unless($found) 1132 { 1133 $class = "Alien::Build::Plugin::$name"; 1134 $pm = "Alien/Build/Plugin/$name.pm"; 1135 $pm =~ s{::}{/}g; 1136 } 1137 1138 require $pm unless $class->can('new'); 1139 my $plugin = $class->new(@args); 1140 $plugin->init($self); 1141 $self; 1142} 1143 1144package Alien::Build::TempDir; 1145 1146# TODO: it's confusing that there is both a AB::TempDir and AB::Temp 1147# although they do different things. there could maybe be a better 1148# name for AB::TempDir (maybe AB::TempBuildDir, though that is a little 1149# redundant). Happily both are private classes, and either are able to 1150# rename, if a good name can be thought of. 1151 1152use overload '""' => sub { shift->as_string }, bool => sub { 1 }, fallback => 1; 1153use File::Temp qw( tempdir ); 1154 1155sub new 1156{ 1157 my($class, $build, $name) = @_; 1158 my $root = $build->install_prop->{root}; 1159 Path::Tiny->new($root)->mkpath unless -d $root; 1160 bless { 1161 dir => Path::Tiny->new(tempdir( "${name}_XXXX", DIR => $root)), 1162 }, $class; 1163} 1164 1165sub as_string 1166{ 1167 shift->{dir}->stringify; 1168} 1169 1170sub DESTROY 1171{ 1172 my($self) = @_; 1173 if(-d $self->{dir} && $self->{dir}->children == 0) 1174 { 1175 rmdir($self->{dir}) || warn "unable to remove @{[ $self->{dir} ]} $!"; 1176 } 1177} 1178 11791; 1180 1181__END__ 1182 1183=pod 1184 1185=encoding UTF-8 1186 1187=head1 NAME 1188 1189Alien::Build - Build external dependencies for use in CPAN 1190 1191=head1 VERSION 1192 1193version 2.45 1194 1195=head1 SYNOPSIS 1196 1197 my $build = Alien::Build->load('./alienfile'); 1198 $build->load_requires('configure'); 1199 $build->set_prefix('/usr/local'); 1200 $build->set_stage('/foo/mystage'); # needs to be absolute 1201 $build->load_requires($build->install_type); 1202 $build->download; 1203 $build->build; 1204 # files are now in /foo/mystage, it is your job (or 1205 # ExtUtils::MakeMaker, Module::Build, etc) to copy 1206 # those files into /usr/local 1207 1208=head1 DESCRIPTION 1209 1210This module provides tools for building external (non-CPAN) dependencies 1211for CPAN. It is mainly designed to be used at install time of a CPAN 1212client, and work closely with L<Alien::Base> which is used at runtime. 1213 1214This is the detailed documentation for the L<Alien::Build> class. 1215If you are starting out you probably want to do so from one of these documents: 1216 1217=over 4 1218 1219=item L<Alien::Build::Manual::Alien> 1220 1221A broad overview of C<Alien-Build> and its ecosystem. 1222 1223=item L<Alien::Build::Manual::AlienUser> 1224 1225For users of an C<Alien::libfoo> that is implemented using L<Alien::Base>. 1226(The developer of C<Alien::libfoo> I<should> provide the documentation 1227necessary, but if not, this is the place to start). 1228 1229=item L<Alien::Build::Manual::AlienAuthor> 1230 1231If you are writing your own L<Alien> based on L<Alien::Build> and L<Alien::Base>. 1232 1233=item L<Alien::Build::Manual::FAQ> 1234 1235If you have a common question that has already been answered, like 1236"How do I use L<alienfile> with some build system". 1237 1238=item L<Alien::Build::Manual::PluginAuthor> 1239 1240This is for the brave souls who want to write plugins that will work with 1241L<Alien::Build> + L<alienfile>. 1242 1243=back 1244 1245Note that you will not usually create a L<Alien::Build> instance 1246directly, but rather be using a thin installer layer, such as 1247L<Alien::Build::MM> (for use with L<ExtUtils::MakeMaker>) or 1248L<Alien::Build::MB> (for use with L<Module::Build>). One of the 1249goals of this project is to remain installer agnostic. 1250 1251=head1 CONSTRUCTORS 1252 1253=head2 new 1254 1255 my $build = Alien::Build->new; 1256 1257This creates a new empty instance of L<Alien::Build>. Normally you will 1258want to use C<load> below to create an instance of L<Alien::Build> from 1259an L<alienfile> recipe. 1260 1261=head2 load 1262 1263 my $build = Alien::Build->load($alienfile); 1264 1265This creates an L<Alien::Build> instance with the given L<alienfile> 1266recipe. 1267 1268=head2 resume 1269 1270 my $build = Alien::Build->resume($alienfile, $root); 1271 1272Load a checkpointed L<Alien::Build> instance. You will need the original 1273L<alienfile> and the build root (usually C<_alien>), and a build that 1274had been properly checkpointed using the C<checkpoint> method below. 1275 1276=head1 PROPERTIES 1277 1278There are three main properties for L<Alien::Build>. There are a number 1279of properties documented here with a specific usage. Note that these 1280properties may need to be serialized into something primitive like JSON 1281that does not support: regular expressions, code references of blessed 1282objects. 1283 1284If you are writing a plugin (L<Alien::Build::Plugin>) you should use a 1285prefix like "plugin_I<name>" (where I<name> is the name of your plugin) 1286so that it does not interfere with other plugin or future versions of 1287L<Alien::Build>. For example, if you were writing 1288C<Alien::Build::Plugin::Fetch::NewProtocol>, please use the prefix 1289C<plugin_fetch_newprotocol>: 1290 1291 sub init 1292 { 1293 my($self, $meta) = @_; 1294 1295 $meta->prop( plugin_fetch_newprotocol_foo => 'some value' ); 1296 1297 $meta->register_hook( 1298 some_hook => sub { 1299 my($build) = @_; 1300 $build->install_prop->{plugin_fetch_newprotocol_bar} = 'some other value'; 1301 $build->runtime_prop->{plugin_fetch_newprotocol_baz} = 'and another value'; 1302 } 1303 ); 1304 } 1305 1306If you are writing a L<alienfile> recipe please use the prefix C<my_>: 1307 1308 use alienfile; 1309 1310 meta_prop->{my_foo} = 'some value'; 1311 1312 probe sub { 1313 my($build) = @_; 1314 $build->install_prop->{my_bar} = 'some other value'; 1315 $build->install_prop->{my_baz} = 'and another value'; 1316 }; 1317 1318Any property may be used from a command: 1319 1320 probe [ 'some command %{.meta.plugin_fetch_newprotocol_foo}' ]; 1321 probe [ 'some command %{.install.plugin_fetch_newprotocol_bar}' ]; 1322 probe [ 'some command %{.runtime.plugin_fetch_newprotocol_baz}' ]; 1323 probe [ 'some command %{.meta.my_foo}' ]; 1324 probe [ 'some command %{.install.my_bar}' ]; 1325 probe [ 'some command %{.runtime.my_baz}' ]; 1326 1327=head2 meta_prop 1328 1329 my $href = $build->meta_prop; 1330 my $href = Alien::Build->meta_prop; 1331 1332Meta properties have to do with the recipe itself, and not any particular 1333instance that probes or builds that recipe. Meta properties can be changed 1334from within an L<alienfile> using the C<meta_prop> directive, or from 1335a plugin from its C<init> method (though should NOT be modified from any 1336hooks registered within that C<init> method). This is not strictly enforced, 1337but if you do not follow this rule your recipe will likely be broken. 1338 1339=over 1340 1341=item arch 1342 1343This is a hint to an installer like L<Alien::Build::MM> or L<Alien::Build::MB>, 1344that the library or tool contains architecture dependent files and so should 1345be stored in an architecture dependent location. If not specified by your 1346L<alienfile> then it will be set to true. 1347 1348=item destdir 1349 1350Use the C<DESTDIR> environment variable to stage your install before 1351copying the files into C<blib>. This is the preferred method of 1352installing libraries because it improves reliability. This technique 1353is supported by C<autoconf> and others. 1354 1355=item destdir_filter 1356 1357Regular expression for the files that should be copied from the C<DESTDIR> 1358into the stage directory. If not defined, then all files will be copied. 1359 1360=item destdir_ffi_filter 1361 1362Same as C<destdir_filter> except applies to C<build_ffi> instead of C<build>. 1363 1364=item env 1365 1366Environment variables to override during the build stage. 1367 1368=item env_interpolate 1369 1370Environment variable values will be interpolated with helpers. Example: 1371 1372 meta->prop->{env_interpolate} = 1; 1373 meta->prop->{env}->{PERL} = '%{perl}'; 1374 1375=item local_source 1376 1377Set to true if source code package is available locally. (that is not fetched 1378over the internet). This is computed by default based on the C<start_url> 1379property. Can be set by an L<alienfile> or plugin. 1380 1381=item platform 1382 1383Hash reference. Contains information about the platform beyond just C<$^O>. 1384 1385=over 4 1386 1387=item compiler_type 1388 1389Refers to the type of flags that the compiler accepts. May be expanded in the 1390future, but for now, will be one of: 1391 1392=over 4 1393 1394=item microsoft 1395 1396On Windows when using Microsoft Visual C++ 1397 1398=item unix 1399 1400Virtually everything else, including gcc on windows. 1401 1402=back 1403 1404The main difference is that with Visual C++ C<-LIBPATH> should be used instead 1405of C<-L>, and static libraries should have the C<.LIB> suffix instead of C<.a>. 1406 1407=item system_type 1408 1409C<$^O> is frequently good enough to make platform specific logic in your 1410L<alienfile>, this handles the case when $^O can cover platforms that provide 1411multiple environments that Perl might run under. The main example is windows, 1412but others may be added in the future. 1413 1414=over 4 1415 1416=item unix 1417 1418=item vms 1419 1420=item windows-activestate 1421 1422=item windows-microsoft 1423 1424=item windows-mingw 1425 1426=item windows-strawberry 1427 1428=item windows-unknown 1429 1430=back 1431 1432Note that C<cygwin> and C<msys> are considered C<unix> even though they run 1433on windows! 1434 1435=back 1436 1437=item out_of_source 1438 1439Build in a different directory from the where the source code is stored. 1440In autoconf this is referred to as a "VPATH" build. Everyone else calls this 1441an "out-of-source" build. When this property is true, instead of extracting 1442to the source build root, the downloaded source will be extracted to an source 1443extraction directory and the source build root will be empty. You can use the 1444C<extract> install property to get the location of the extracted source. 1445 1446=item network 1447 1448True if a network fetch is available. This should NOT be set by an L<alienfile> 1449or plugin. This is computed based on the C<ALIEN_INSTALL_NETWORK> environment 1450variables. 1451 1452=item start_url 1453 1454The default or start URL used by fetch plugins. 1455 1456=back 1457 1458=head2 install_prop 1459 1460 my $href = $build->install_prop; 1461 1462Install properties are used during the install phase (either 1463under C<share> or C<system> install). They are remembered for 1464the entire install phase, but not kept around during the runtime 1465phase. Thus they cannot be accessed from your L<Alien::Base> 1466based module. 1467 1468=over 1469 1470=item autoconf_prefix 1471 1472The prefix as understood by autoconf. This is only different on Windows 1473Where MSYS is used and paths like C<C:/foo> are represented as C</C/foo> 1474which are understood by the MSYS tools, but not by Perl. You should 1475only use this if you are using L<Alien::Build::Plugin::Autoconf> in 1476your L<alienfile>. 1477 1478=item download 1479 1480The location of the downloaded archive (tar.gz, or similar) or directory. 1481 1482=item env 1483 1484Environment variables to override during the build stage. 1485 1486=item extract 1487 1488The location of the last source extraction. For a "out-of-source" build 1489(see the C<out_of_source> meta property above), this will only be set once. 1490For other types of builds, the source code may be extracted multiple times, 1491and thus this property may change. 1492 1493=item old 1494 1495Hash containing information on a previously installed Alien of the same 1496name, if available. This may be useful in cases where you want to 1497reuse the previous install if it is still sufficient. 1498 1499=over 4 1500 1501=item prefix 1502 1503The prefix for the previous install. Versions prior to 1.42 unfortunately 1504had this in typo form of C<preifx>. 1505 1506=item runtime 1507 1508The runtime properties from the previous install. 1509 1510=back 1511 1512=item patch 1513 1514Directory with patches. 1515 1516=item prefix 1517 1518The install time prefix. Under a C<destdir> install this is the 1519same as the runtime or final install location. Under a non-C<destdir> 1520install this is the C<stage> directory (usually the appropriate 1521share directory under C<blib>). 1522 1523=item root 1524 1525The build root directory. This will be an absolute path. It is the 1526absolute form of C<./_alien> by default. 1527 1528=item stage 1529 1530The stage directory where files will be copied. This is usually the 1531root of the blib share directory. 1532 1533=item system_probe_class 1534 1535After the probe step this property may contain the plugin class that 1536performed the system probe. It shouldn't be filled in directly by 1537the plugin (instead if should use the hook property C<probe_class>, 1538see below). This is optional, and not all probe plugins will provide 1539this information. 1540 1541=item system_probe_instance_id 1542 1543After the probe step this property may contain the plugin instance id that 1544performed the system probe. It shouldn't be filled in directly by 1545the plugin (instead if should use the hook property C<probe_instance_id>, 1546see below). This is optional, and not all probe plugins will provide 1547this information. 1548 1549=back 1550 1551=head2 plugin_instance_prop 1552 1553 my $href = $build->plugin_instance_prop($plugin); 1554 1555This returns the private plugin instance properties for a given plugin. 1556This method should usually only be called internally by plugins themselves 1557to keep track of internal state. Because the content can be used arbitrarily 1558by the owning plugin because it is private to the plugin, and thus is not 1559part of the L<Alien::Build> spec. 1560 1561=head2 runtime_prop 1562 1563 my $href = $build->runtime_prop; 1564 1565Runtime properties are used during the install and runtime phases 1566(either under C<share> or C<system> install). This should include 1567anything that you will need to know to use the library or tool 1568during runtime, and shouldn't include anything that is no longer 1569relevant once the install process is complete. 1570 1571=over 4 1572 1573=item alien_build_version 1574 1575The version of L<Alien::Build> used to install the library or tool. 1576 1577=item alt 1578 1579Alternate configurations. If the alienized package has multiple 1580libraries this could be used to store the different compiler or 1581linker flags for each library. 1582 1583=item cflags 1584 1585The compiler flags 1586 1587=item cflags_static 1588 1589The static compiler flags 1590 1591=item command 1592 1593The command name for tools where the name my differ from platform to 1594platform. For example, the GNU version of make is usually C<make> in 1595Linux and C<gmake> on FreeBSD. 1596 1597=item ffi_name 1598 1599The name DLL or shared object "name" to use when searching for dynamic 1600libraries at runtime. This is passed into L<FFI::CheckLib>, so if 1601your library is something like C<libarchive.so> or C<archive.dll> you 1602would set this to C<archive>. This may be a string or an array of 1603strings. 1604 1605=item ffi_checklib 1606 1607This property contains two sub properties: 1608 1609=over 4 1610 1611=item share 1612 1613 $build->runtime_prop->{ffi_checklib}->{share} = [ ... ]; 1614 1615Array of additional L<FFI::CheckLib> flags to pass in to C<find_lib> 1616for a C<share> install. 1617 1618=item system 1619 1620Array of additional L<FFI::CheckLib> flags to pass in to C<find_lib> 1621for a C<system> install. 1622 1623Among other things, useful for specifying the C<try_linker_script> 1624flag: 1625 1626 $build->runtime_prop->{ffi_checklib}->{system} = [ try_linker_script => 1 ]; 1627 1628=back 1629 1630=item install_type 1631 1632The install type. Is one of: 1633 1634=over 4 1635 1636=item system 1637 1638For when the library or tool is provided by the operating system, can be 1639detected by L<Alien::Build>, and is considered satisfactory by the 1640C<alienfile> recipe. 1641 1642=item share 1643 1644For when a system install is not possible, the library source will be 1645downloaded from the internet or retrieved in another appropriate fashion 1646and built. 1647 1648=back 1649 1650=item libs 1651 1652The library flags 1653 1654=item libs_static 1655 1656The static library flags 1657 1658=item perl_module_version 1659 1660The version of the Perl module used to install the alien (if available). 1661For example if L<Alien::curl> is installing C<libcurl> this would be the 1662version of L<Alien::curl> used during the install step. 1663 1664=item prefix 1665 1666The final install root. This is usually they share directory. 1667 1668=item version 1669 1670The version of the library or tool 1671 1672=back 1673 1674=head2 hook_prop 1675 1676 my $href = $build->hook_prop; 1677 1678Hook properties are for the currently running (if any) hook. They are 1679used only during the execution of each hook and are discarded after. 1680If no hook is currently running then C<hook_prop> will return C<undef>. 1681 1682=over 4 1683 1684=item name 1685 1686The name of the currently running hook. 1687 1688=item version (probe) 1689 1690Probe and PkgConfig plugins I<may> set this property indicating the 1691version of the alienized package. Not all plugins and configurations 1692may be able to provide this. 1693 1694=item probe_class (probe) 1695 1696Probe and PkgConfig plugins I<may> set this property indicating the 1697plugin class that made the probe. If the probe results in a system 1698install this will be propagated to C<system_probe_class> for later 1699use. 1700 1701=item probe_instance_id (probe) 1702 1703Probe and PkgConfig plugins I<may> set this property indicating the 1704plugin instance id that made the probe. If the probe results in a 1705system install this will be propagated to C<system_probe_instance_id> 1706for later use. 1707 1708=back 1709 1710=head1 METHODS 1711 1712=head2 checkpoint 1713 1714 $build->checkpoint; 1715 1716Save any install or runtime properties so that they can be reloaded on 1717a subsequent run in a separate process. This is useful if your build 1718needs to be done in multiple stages from a C<Makefile>, such as with 1719L<ExtUtils::MakeMaker>. Once checkpointed you can use the C<resume> 1720constructor (documented above) to resume the probe/build/install] 1721process. 1722 1723=head2 root 1724 1725 my $dir = $build->root; 1726 1727This is just a shortcut for: 1728 1729 my $root = $build->install_prop->{root}; 1730 1731Except that it will be created if it does not already exist. 1732 1733=head2 install_type 1734 1735 my $type = $build->install_type; 1736 1737This will return the install type. (See the like named install property 1738above for details). This method will call C<probe> if it has not already 1739been called. 1740 1741=head2 set_prefix 1742 1743 $build->set_prefix($prefix); 1744 1745Set the final (unstaged) prefix. This is normally only called by L<Alien::Build::MM> 1746and similar modules. It is not intended for use from plugins or from an L<alienfile>. 1747 1748=head2 set_stage 1749 1750 $build->set_stage($dir); 1751 1752Sets the stage directory. This is normally only called by L<Alien::Build::MM> 1753and similar modules. It is not intended for use from plugins or from an L<alienfile>. 1754 1755=head2 requires 1756 1757 my $hash = $build->requires($phase); 1758 1759Returns a hash reference of the modules required for the given phase. Phases 1760include: 1761 1762=over 4 1763 1764=item configure 1765 1766These modules must already be available when the L<alienfile> is read. 1767 1768=item any 1769 1770These modules are used during either a C<system> or C<share> install. 1771 1772=item share 1773 1774These modules are used during the build phase of a C<share> install. 1775 1776=item system 1777 1778These modules are used during the build phase of a C<system> install. 1779 1780=back 1781 1782=head2 load_requires 1783 1784 $build->load_requires($phase); 1785 1786This loads the appropriate modules for the given phase (see C<requires> above 1787for a description of the phases). 1788 1789=head2 probe 1790 1791 my $install_type = $build->probe; 1792 1793Attempts to determine if the operating system has the library or 1794tool already installed. If so, then the string C<system> will 1795be returned and a system install will be performed. If not, 1796then the string C<share> will be installed and the tool or 1797library will be downloaded and built from source. 1798 1799If the environment variable C<ALIEN_INSTALL_TYPE> is set, then that 1800will force a specific type of install. If the detection logic 1801cannot accommodate the install type requested then it will fail with 1802an exception. 1803 1804=head2 download 1805 1806 $build->download; 1807 1808Download the source, usually as a tarball, usually from the internet. 1809 1810Under a C<system> install this does not do anything. 1811 1812=head2 fetch 1813 1814 my $res = $build->fetch; 1815 my $res = $build->fetch($url, %options); 1816 1817Fetch a resource using the fetch hook. Returns the same hash structure 1818described below in the hook documentation. 1819 1820[version 2.39] 1821 1822As of L<Alien::Build> 2.39, these options are supported: 1823 1824=over 4 1825 1826=item http_headers 1827 1828 my $res = $build->fetch($url, http_headers => [ $key1 => $value1, $key2 => $value 2, ... ]); 1829 1830Set the HTTP request headers on all outgoing HTTP requests. Note that not all 1831protocols or fetch plugins support setting request headers, but the ones that 1832do not I<should> issue a warning if you try to set request headers and they 1833are not supported. 1834 1835=back 1836 1837=head2 decode 1838 1839 my $decoded_res = $build->decode($res); 1840 1841Decode the HTML or file listing returned by C<fetch>. Returns the same 1842hash structure described below in the hook documentation. 1843 1844=head2 prefer 1845 1846 my $sorted_res = $build->prefer($res); 1847 1848Filter and sort candidates. The preferred candidate will be returned first in the list. 1849The worst candidate will be returned last. Returns the same hash structure described 1850below in the hook documentation. 1851 1852=head2 extract 1853 1854 my $dir = $build->extract; 1855 my $dir = $build->extract($archive); 1856 1857Extracts the given archive into a fresh directory. This is normally called internally 1858to L<Alien::Build>, and for normal usage is not needed from a plugin or L<alienfile>. 1859 1860=head2 build 1861 1862 $build->build; 1863 1864Run the build step. It is expected that C<probe> and C<download> 1865have already been performed. What it actually does depends on the 1866type of install: 1867 1868=over 4 1869 1870=item share 1871 1872The source is extracted, and built as determined by the L<alienfile> 1873recipe. If there is a C<gather_share> that will be executed last. 1874 1875=item system 1876 1877The C<gather_system> hook will be executed. 1878 1879=back 1880 1881=head2 test 1882 1883 $build->test; 1884 1885Run the test phase 1886 1887=head2 clean_install 1888 1889 $build->clean_install 1890 1891Clean files from the final install location. The default implementation removes all 1892files recursively except for the C<_alien> directory. This is helpful when you have 1893an old install with files that may break the new build. 1894 1895For a non-share install this doesn't do anything. 1896 1897=head2 system 1898 1899 $build->system($command); 1900 $build->system($command, @args); 1901 1902Interpolates the command and arguments and run the results using 1903the Perl C<system> command. 1904 1905=head2 log 1906 1907 $build->log($message); 1908 1909Send a message to the log. By default this prints to C<STDOUT>. 1910 1911=head2 meta 1912 1913 my $meta = Alien::Build->meta; 1914 my $meta = $build->meta; 1915 1916Returns the meta object for your L<Alien::Build> class or instance. The 1917meta object is a way to manipulate the recipe, and so any changes to the 1918meta object should be made before the C<probe>, C<download> or C<build> steps. 1919 1920=head1 META METHODS 1921 1922=head2 prop 1923 1924 my $href = $build->meta->prop; 1925 1926Meta properties. This is the same as calling C<meta_prop> on 1927the class or L<Alien::Build> instance. 1928 1929=head2 add_requires 1930 1931 Alien::Build->meta->add_requires($phase, $module => $version, ...); 1932 1933Add the requirement to the given phase. Phase should be one of: 1934 1935=over 4 1936 1937=item configure 1938 1939=item any 1940 1941=item share 1942 1943=item system 1944 1945=back 1946 1947=head2 interpolator 1948 1949 my $interpolator = $build->meta->interpolator; 1950 my $interpolator = Alien::Build->interpolator; 1951 1952Returns the L<Alien::Build::Interpolate> instance for the L<Alien::Build> class. 1953 1954=head2 has_hook 1955 1956 my $bool = $build->meta->has_hook($name); 1957 my $bool = Alien::Build->has_hook($name); 1958 1959Returns if there is a usable hook registered with the given name. 1960 1961=head2 register_hook 1962 1963 $build->meta->register_hook($name, $instructions); 1964 Alien::Build->meta->register_hook($name, $instructions); 1965 1966Register a hook with the given name. C<$instruction> should be either 1967a code reference, or a command sequence, which is an array reference. 1968 1969=head2 default_hook 1970 1971 $build->meta->default_hook($name, $instructions); 1972 Alien::Build->meta->default_hook($name, $instructions); 1973 1974Register a default hook, which will be used if the L<alienfile> does not 1975register its own hook with that name. 1976 1977=head2 around_hook 1978 1979 $build->meta->around_hook($hook, $code); 1980 Alien::Build->meta->around_hook($name, $code); 1981 1982Wrap the given hook with a code reference. This is similar to a L<Moose> 1983method modifier, except that it wraps around the given hook instead of 1984a method. For example, this will add a probe system requirement: 1985 1986 $build->meta->around_hook( 1987 probe => sub { 1988 my $orig = shift; 1989 my $build = shift; 1990 my $type = $orig->($build, @_); 1991 return $type unless $type eq 'system'; 1992 # also require a configuration file 1993 if(-f '/etc/foo.conf') 1994 { 1995 return 'system'; 1996 } 1997 else 1998 { 1999 return 'share'; 2000 } 2001 }, 2002 ); 2003 2004=head2 apply_plugin 2005 2006 Alien::Build->meta->apply_plugin($name); 2007 Alien::Build->meta->apply_plugin($name, @args); 2008 2009Apply the given plugin with the given arguments. 2010 2011=head1 ENVIRONMENT 2012 2013L<Alien::Build> responds to these environment variables: 2014 2015=over 4 2016 2017=item ALIEN_INSTALL_NETWORK 2018 2019If set to true (the default), then network fetch will be allowed. If set to 2020false, then network fetch will not be allowed. 2021 2022What constitutes a local vs. network fetch is determined based on the C<start_url> 2023and C<local_source> meta properties. An L<alienfile> or plugin C<could> override 2024this detection (possibly inappropriately), so this variable is not a substitute 2025for properly auditing of Perl modules for environments that require that. 2026 2027=item ALIEN_INSTALL_TYPE 2028 2029If set to C<share> or C<system>, it will override the system detection logic. 2030If set to C<default>, it will use the default setting for the L<alienfile>. 2031The behavior of other values is undefined. 2032 2033Although the recommended way for a consumer to use an L<Alien::Base> based L<Alien> 2034is to declare it as a static configure and build-time dependency, some consumers 2035may prefer to fallback on using an L<Alien> only when the consumer itself cannot 2036detect the necessary package. In some cases the consumer may want the user to opt-in 2037to using an L<Alien> before requiring it. 2038 2039To keep the interface consistent among Aliens, the consumer of the fallback opt-in 2040L<Alien> may fallback on the L<Alien> if the environment variable C<ALIEN_INSTALL_TYPE> 2041is set to any value. The rationale is that by setting this environment variable the 2042user is aware that L<Alien> modules may be installed and have indicated consent. 2043The actual implementation of this, by its nature would have to be in the consuming 2044CPAN module. 2045 2046=item ALIEN_BUILD_LOG 2047 2048The default log class used. See L<Alien::Build::Log> and L<Alien::Build::Log::Default>. 2049 2050=item ALIEN_BUILD_RC 2051 2052Perl source file which can override some global defaults for L<Alien::Build>, 2053by, for example, setting preload and postload plugins. 2054 2055=item ALIEN_BUILD_PKG_CONFIG 2056 2057Override the logic in L<Alien::Build::Plugin::PkgConfig::Negotiate> which 2058chooses the best C<pkg-config> plugin. 2059 2060=item ALIEN_BUILD_PRELOAD 2061 2062semicolon separated list of plugins to automatically load before parsing 2063your L<alienfile>. 2064 2065=item ALIEN_BUILD_POSTLOAD 2066 2067semicolon separated list of plugins to automatically load after parsing 2068your L<alienfile>. 2069 2070=item DESTDIR 2071 2072This environment variable will be manipulated during a destdir install. 2073 2074=item PKG_CONFIG 2075 2076This environment variable can be used to override the program name for C<pkg-config> 2077when using the command line plugin: L<Alien::Build::Plugin::PkgConfig::CommandLine>. 2078 2079=item ftp_proxy, all_proxy 2080 2081If these environment variables are set, it may influence the Download negotiation 2082plugin L<Alien::Build::Plugin::Downaload::Negotiate>. Other proxy variables may 2083be used by some Fetch plugins, if they support it. 2084 2085=back 2086 2087=head1 SUPPORT 2088 2089The intent of the C<Alien-Build> team is to support as best as possible 2090all Perls from 5.8.4 to the latest production version. So long as they 2091are also supported by the Perl toolchain. 2092 2093Please feel encouraged to report issues that you encounter to the 2094project GitHub Issue tracker: 2095 2096=over 4 2097 2098=item L<https://github.com/PerlAlien/Alien-Build/issues> 2099 2100=back 2101 2102Better if you can fix the issue yourself, please feel encouraged to open 2103pull-request on the project GitHub: 2104 2105=over 4 2106 2107=item L<https://github.com/PerlAlien/Alien-Build/pulls> 2108 2109=back 2110 2111If you are confounded and have questions, join us on the C<#native> 2112channel on irc.perl.org. The C<Alien-Build> developers frequent this 2113channel and can probably help point you in the right direction. If you 2114don't have an IRC client handy, you can use this web interface: 2115 2116=over 4 2117 2118=item L<https://chat.mibbit.com/?channel=%23native&server=irc.perl.org> 2119 2120=back 2121 2122=head1 SEE ALSO 2123 2124L<Alien::Build::Manual::AlienAuthor>, 2125L<Alien::Build::Manual::AlienUser>, 2126L<Alien::Build::Manual::Contributing>, 2127L<Alien::Build::Manual::FAQ>, 2128L<Alien::Build::Manual::PluginAuthor> 2129 2130L<alienfile>, L<Alien::Build::MM>, L<Alien::Build::Plugin>, L<Alien::Base>, L<Alien> 2131 2132=head1 THANKS 2133 2134L<Alien::Base> was originally written by Joel Berger, the rest of this project would 2135not have been possible without him getting the project started. Thanks to his support 2136I have been able to augment the original L<Alien::Base> system with a reliable set 2137of tools (L<Alien::Build>, L<alienfile>, L<Test::Alien>), which make up this toolset. 2138 2139The original L<Alien::Base> is still copyright (c) 2012-2020 Joel Berger. It has 2140the same license as the rest of the Alien::Build and related tools distributed as 2141C<Alien-Build>. Joel Berger thanked a number of people who helped in in the development 2142of L<Alien::Base>, in the documentation for that module. 2143 2144I would also like to acknowledge the other members of the PerlAlien github 2145organization, Zakariyya Mughal (sivoais, ZMUGHAL) and mohawk (ETJ). Also important 2146in the early development of L<Alien::Build> were the early adopters Chase Whitener 2147(genio, CAPOEIRAB, author of L<Alien::libuv>), William N. Braswell, Jr (willthechill, 2148WBRASWELL, author of L<Alien::JPCRE2> and L<Alien::PCRE2>) and Ahmad Fatoum (a3f, 2149ATHREEF, author of L<Alien::libudev> and L<Alien::LibUSB>). 2150 2151The Alien ecosystem owes a debt to Dan Book, who goes by Grinnz on IRC, for answering 2152question about how to use L<Alien::Build> and friends. 2153 2154=head1 AUTHOR 2155 2156Author: Graham Ollis E<lt>plicease@cpan.orgE<gt> 2157 2158Contributors: 2159 2160Diab Jerius (DJERIUS) 2161 2162Roy Storey (KIWIROY) 2163 2164Ilya Pavlov 2165 2166David Mertens (run4flat) 2167 2168Mark Nunberg (mordy, mnunberg) 2169 2170Christian Walde (Mithaldu) 2171 2172Brian Wightman (MidLifeXis) 2173 2174Zaki Mughal (zmughal) 2175 2176mohawk (mohawk2, ETJ) 2177 2178Vikas N Kumar (vikasnkumar) 2179 2180Flavio Poletti (polettix) 2181 2182Salvador Fandiño (salva) 2183 2184Gianni Ceccarelli (dakkar) 2185 2186Pavel Shaydo (zwon, trinitum) 2187 2188Kang-min Liu (劉康民, gugod) 2189 2190Nicholas Shipp (nshp) 2191 2192Juan Julián Merelo Guervós (JJ) 2193 2194Joel Berger (JBERGER) 2195 2196Petr Písař (ppisar) 2197 2198Lance Wicks (LANCEW) 2199 2200Ahmad Fatoum (a3f, ATHREEF) 2201 2202José Joaquín Atria (JJATRIA) 2203 2204Duke Leto (LETO) 2205 2206Shoichi Kaji (SKAJI) 2207 2208Shawn Laffan (SLAFFAN) 2209 2210Paul Evans (leonerd, PEVANS) 2211 2212Håkon Hægland (hakonhagland, HAKONH) 2213 2214nick nauwelaerts (INPHOBIA) 2215 2216=head1 COPYRIGHT AND LICENSE 2217 2218This software is copyright (c) 2011-2020 by Graham Ollis. 2219 2220This is free software; you can redistribute it and/or modify it under 2221the same terms as the Perl 5 programming language system itself. 2222 2223=cut 2224