ÿØÿà JFIF    ÿÛ „ ( %!1!%*+...983,7(-.- Base/Wrapper.pm000044400000032325152346246300007404 0ustar00package Alien::Base::Wrapper; use strict; use warnings; use 5.006; use Config; use Text::ParseWords qw( shellwords ); # NOTE: Although this module is now distributed with Alien-Build, # it should have NO non-perl-core dependencies for all Perls # 5.6.0-5.30.1 (as of this writing, and any Perl more recent). # You should be able to extract this module from the rest of # Alien-Build and use it by itself. (There is a dzil plugin # for this [AlienBase::Wrapper::Bundle] # ABSTRACT: Compiler and linker wrapper for Alien our $VERSION = '2.74'; # VERSION sub _join { join ' ', map { my $x = $_; $x =~ s/(\s)/\\$1/g; $x; } @_; } sub new { my($class, @aliens) = @_; my $export = 1; my $writemakefile = 0; my @cflags_I; my @cflags_other; my @ldflags_L; my @ldflags_l; my @ldflags_other; my %requires = ( 'ExtUtils::MakeMaker' => '6.52', 'Alien::Base::Wrapper' => '1.97', ); foreach my $alien (@aliens) { if($alien eq '!export') { $export = 0; next; } if($alien eq 'WriteMakefile') { $writemakefile = 1; next; } my $version = 0; if($alien =~ s/=(.*)$//) { $version = $1; } $alien = "Alien::$alien" unless $alien =~ /::/; $requires{$alien} = $version; my $alien_pm = $alien . '.pm'; $alien_pm =~ s/::/\//g; require $alien_pm unless eval { $alien->can('cflags') } && eval { $alien->can('libs') }; my $cflags; my $libs; if($alien->install_type eq 'share' && $alien->can('cflags_static')) { $cflags = $alien->cflags_static; $libs = $alien->libs_static; } else { $cflags = $alien->cflags; $libs = $alien->libs; } $cflags = '' unless defined $cflags; $libs = '' unless defined $libs; push @cflags_I, grep /^-I/, shellwords $cflags; push @cflags_other, grep !/^-I/, shellwords $cflags; push @ldflags_L, grep /^-L/, shellwords $libs; push @ldflags_l, grep /^-l/, shellwords $libs; push @ldflags_other, grep !/^-[Ll]/, shellwords $libs; } my @cflags_define = grep /^-D/, @cflags_other; my @cflags_other2 = grep !/^-D/, @cflags_other; my @mm; push @mm, INC => _join @cflags_I if @cflags_I; push @mm, CCFLAGS => _join(@cflags_other2) . " $Config{ccflags}" if @cflags_other2; push @mm, DEFINE => _join(@cflags_define) if @cflags_define; # TODO: handle spaces in -L paths push @mm, LIBS => ["@ldflags_L @ldflags_l"]; my @ldflags = (@ldflags_L, @ldflags_other); push @mm, LDDLFLAGS => _join(@ldflags) . " $Config{lddlflags}" if @ldflags; push @mm, LDFLAGS => _join(@ldflags) . " $Config{ldflags}" if @ldflags; my @mb; push @mb, extra_compiler_flags => _join(@cflags_I, @cflags_other); push @mb, extra_linker_flags => _join(@ldflags_l); if(@ldflags) { push @mb, config => { lddlflags => _join(@ldflags) . " $Config{lddlflags}", ldflags => _join(@ldflags) . " $Config{ldflags}", }, } bless { cflags_I => \@cflags_I, cflags_other => \@cflags_other, ldflags_L => \@ldflags_L, ldflags_l => \@ldflags_l, ldflags_other => \@ldflags_other, mm => \@mm, mb => \@mb, _export => $export, _writemakefile => $writemakefile, requires => \%requires, }, $class; } my $default_abw = __PACKAGE__->new; # for testing only sub _reset { __PACKAGE__->new } sub _myexec { my @command = @_; if($^O eq 'MSWin32') { # To handle weird quoting on MSWin32 # this logic needs to be improved. my $command = "@command"; $command =~ s{"}{\\"}g; system $command; if($? == -1 ) { die "failed to execute: $!\n"; } elsif($? & 127) { die "child died with signal @{[ $? & 128 ]}"; } else { exit($? >> 8); } } else { exec @command; } } sub cc { my @command = ( shellwords($Config{cc}), @{ $default_abw->{cflags_I} }, @{ $default_abw->{cflags_other} }, @ARGV, ); print "@command\n" unless $ENV{ALIEN_BASE_WRAPPER_QUIET}; _myexec @command; } sub ld { my @command = ( shellwords($Config{ld}), @{ $default_abw->{ldflags_L} }, @{ $default_abw->{ldflags_other} }, @ARGV, @{ $default_abw->{ldflags_l} }, ); print "@command\n" unless $ENV{ALIEN_BASE_WRAPPER_QUIET}; _myexec @command; } sub mm_args { my $self = ref $_[0] ? shift : $default_abw; @{ $self->{mm} }; } sub mm_args2 { my $self = shift; $self = $default_abw unless ref $self; my %args = @_; my @mm = @{ $self->{mm} }; while(@mm) { my $key = shift @mm; my $value = shift @mm; if(defined $args{$key}) { if($args{$key} eq 'LIBS') { require Carp; # Todo: support this maybe? Carp::croak("please do not specify your own LIBS key with mm_args2"); } else { $args{$key} = join ' ', $value, $args{$key}; } } else { $args{$key} = $value; } } foreach my $module (keys %{ $self->{requires} }) { $args{CONFIGURE_REQUIRES}->{$module} = $self->{requires}->{$module}; } %args; } sub mb_args { my $self = ref $_[0] ? shift : $default_abw; @{ $self->{mb} }; } sub import { shift; my $abw = $default_abw = __PACKAGE__->new(@_); if($abw->_export) { my $caller = caller; no strict 'refs'; *{"${caller}::cc"} = \&cc; *{"${caller}::ld"} = \&ld; } if($abw->_writemakefile) { my $caller = caller; no strict 'refs'; *{"${caller}::WriteMakefile"} = \&WriteMakefile; } } sub WriteMakefile { my %args = @_; require ExtUtils::MakeMaker; ExtUtils::MakeMaker->VERSION('6.52'); my @aliens; if(my $reqs = delete $args{alien_requires}) { if(ref $reqs eq 'HASH') { @aliens = map { my $module = $_; my $version = $reqs->{$module}; $version ? "$module=$version" : "$module"; } sort keys %$reqs; } elsif(ref $reqs eq 'ARRAY') { @aliens = @$reqs; } else { require Carp; Carp::croak("aliens_require must be either a hash or array reference"); } } else { require Carp; Carp::croak("You are using Alien::Base::Wrapper::WriteMakefile, but didn't specify any alien requirements"); } ExtUtils::MakeMaker::WriteMakefile( Alien::Base::Wrapper->new(@aliens)->mm_args2(%args), ); } sub _export { shift->{_export} } sub _writemakefile { shift->{_writemakefile} } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Base::Wrapper - Compiler and linker wrapper for Alien =head1 VERSION version 2.74 =head1 SYNOPSIS From the command line: % perl -MAlien::Base::Wrapper=Alien::Foo,Alien::Bar -e cc -- -o foo.o -c foo.c % perl -MAlien::Base::Wrapper=Alien::Foo,Alien::Bar -e ld -- -o foo foo.o From Makefile.PL (static): use ExtUtils::MakeMaker; use Alien::Base::Wrapper (); WriteMakefile( Alien::Base::Wrapper->new( 'Alien::Foo', 'Alien::Bar')->mm_args2( 'NAME' => 'Foo::XS', 'VERSION_FROM' => 'lib/Foo/XS.pm', ), ); From Makefile.PL (static with wrapper) use Alien::Base::Wrapper qw( WriteMakefile); WriteMakefile( 'NAME' => 'Foo::XS', 'VERSION_FROM' => 'lib/Foo/XS.pm', 'alien_requires' => { 'Alien::Foo' => 0, 'Alien::Bar' => 0, }, ); From Makefile.PL (dynamic): use Devel::CheckLib qw( check_lib ); use ExtUtils::MakeMaker 6.52; my @mm_args; my @libs; if(check_lib( lib => [ 'foo' ] ) { push @mm_args, LIBS => [ '-lfoo' ]; } else { push @mm_args, CC => '$(FULLPERL) -MAlien::Base::Wrapper=Alien::Foo -e cc --', LD => '$(FULLPERL) -MAlien::Base::Wrapper=Alien::Foo -e ld --', BUILD_REQUIRES => { 'Alien::Foo' => 0, 'Alien::Base::Wrapper' => 0, } ; } WriteMakefile( 'NAME' => 'Foo::XS', 'VERSION_FROM' => 'lib/Foo/XS.pm', 'CONFIGURE_REQUIRES => { 'ExtUtils::MakeMaker' => 6.52, }, @mm_args, ); =head1 DESCRIPTION This module acts as a wrapper around one or more L modules. It is designed to work with L based aliens, but it should work with any L which uses the same essential API. In the first example (from the command line), this class acts as a wrapper around the compiler and linker that Perl is configured to use. It takes the normal compiler and linker flags and adds the flags provided by the Aliens specified, and then executes the command. It will print the command to the console so that you can see exactly what is happening. In the second example (from Makefile.PL non-dynamic), this class is used to generate the appropriate L (EUMM) arguments needed to C. In the third example (from Makefile.PL dynamic), we do a quick check to see if the simple linker flag C<-lfoo> will work, if so we use that. If not, we use a wrapper around the compiler and linker that will use the alien flags that are known at build time. The problem that this form attempts to solve is that compiler and linker flags typically need to be determined at I time, when a distribution is installed, meaning if you are going to use an L module then it needs to be a configure prerequisite, even if the library is already installed and easily detected on the operating system. The author of this module believes that the third (from Makefile.PL dynamic) form is somewhat unnecessary. L modules based on L have a few prerequisites, but they are well maintained and reliable, so while there is a small cost in terms of extra dependencies, the overall reliability thanks to reduced overall complexity. =head1 CONSTRUCTOR =head2 new my $abw = Alien::Base::Wrapper->new(@aliens); Instead of passing the aliens you want to use into this modules import you can create a non-global instance of C using the OO interface. =head1 FUNCTIONS =head2 cc % perl -MAlien::Base::Wrapper=Alien::Foo -e cc -- cflags Invoke the C compiler with the appropriate flags from C and what is provided on the command line. =head2 ld % perl -MAlien::Base::Wrapper=Alien::Foo -e ld -- ldflags Invoke the linker with the appropriate flags from C and what is provided on the command line. =head2 mm_args my %args = $abw->mm_args; my %args = Alien::Base::Wrapper->mm_args; Returns arguments that you can pass into C to compile/link against the specified Aliens. Note that this does not set C. You probably want to use C below instead for that reason. =head2 mm_args2 my %args = $abw->mm_args2(%args); my %args = Alien::Base::Wrapper->mm_args2(%args); Returns arguments that you can pass into C to compile/link against. It works a little differently from C above in that you can pass in arguments. It also adds the appropriate C for you so you do not have to do that explicitly. =head2 mb_args my %args = $abw->mb_args; my %args = Alien::Base::Wrapper->mb_args; Returns arguments that you can pass into the constructor to L. =head2 WriteMakefile use Alien::Base::Wrapper qw( WriteMakefile ); WriteMakefile(%args, alien_requires => \%aliens); WriteMakefile(%args, alien_requires => \@aliens); This is a thin wrapper around C from L, which adds the given aliens to the configure requirements and sets the appropriate compiler and linker flags. If the aliens are specified as a hash reference, then the keys are the module names and the values are the versions. For a list it is just the name of the aliens. For the list form you can specify a version by appending C<=version> to the name of the Aliens, that is: WriteMakefile( alien_requires => [ 'Alien::libfoo=1.23', 'Alien::libbar=4.56' ], ); The list form is recommended if the ordering of the aliens matter. The aliens are sorted in the hash form to make it consistent, but it may not be the order that you want. =head1 ENVIRONMENT Alien::Base::Wrapper responds to these environment variables: =over 4 =item ALIEN_BASE_WRAPPER_QUIET If set to true, do not print the command before executing =back =head1 SEE ALSO L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Base/Authoring.pod000044400000003370152346246300010070 0ustar00# ABSTRACT: Authoring an Alien distribution using Alien::Base # PODNAME: Alien::Base::Authoring __END__ =pod =encoding UTF-8 =head1 NAME Alien::Base::Authoring - Authoring an Alien distribution using Alien::Base =head1 VERSION version 2.74 =head1 SYNOPSIS % perldoc Alien::Build::Manual::AlienAuthor % perldoc Alien::Base::ModuleBuild::Authoring =head1 DESCRIPTION This used to document the only way to author an L distribution, which was with L. You should now seriously consider using the newer more reliable method which is via L and L. Read all about it in L and L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Base/PkgConfig.pm000044400000011450152346246300007627 0ustar00package Alien::Base::PkgConfig; use strict; use warnings; use 5.008004; use Carp; use Config; use Path::Tiny qw( path ); use Capture::Tiny qw( capture_stderr ); # ABSTRACT: Private legacy pkg-config class for Alien::Base our $VERSION = '2.74'; # VERSION sub new { my $class = shift; # allow creation of an object from a full spec. if (ref $_[0] eq 'HASH') { return bless $_[0], $class; } my ($path) = @_; croak "Must specify a file" unless defined $path; $path = path( $path )->absolute; my($name) = $path->basename =~ /^(.*)\.pc$/; my $self = { package => $name, vars => { pcfiledir => $path->parent->stringify }, keywords => {}, }; bless $self, $class; $self->read($path); return $self; } sub read { my $self = shift; my ($path) = @_; open my $fh, '<', $path or croak "Cannot open .pc file $path: $!"; while (my $line = <$fh>) { if ($line =~ /^([^=:]+?)=([^\n\r]*)/) { $self->{vars}{$1} = $2; } elsif ($line =~ /^([^=:]+?):\s*([^\n\r]*)/) { $self->{keywords}{$1} = $2; } } } # getter/setter for vars sub var { my $self = shift; my ($var, $newval) = @_; if (defined $newval) { $self->{vars}{$var} = $newval; } return $self->{vars}{$var}; } # abstract keywords and other vars in terms of "pure" vars sub make_abstract { my $self = shift; die "make_abstract needs a key (and possibly a value)" unless @_; my ($var, $value) = @_; $value = defined $value ? $value : $self->{vars}{$var}; # convert other vars foreach my $key (keys %{ $self->{vars} }) { next if $key eq $var; # don't overwrite the current var $self->{vars}{$key} =~ s/\Q$value\E/\$\{$var\}/g; } # convert keywords foreach my $key (keys %{ $self->{keywords} }) { $self->{keywords}{$key} =~ s/\Q$value\E/\$\{$var\}/g; } } sub _interpolate_vars { my $self = shift; my ($string, $override) = @_; $override ||= {}; foreach my $key (keys %$override) { carp "Overriden pkg-config variable $key, contains no data" unless $override->{$key}; } if (defined $string) { 1 while $string =~ s/\$\{(.*?)\}/$override->{$1} || $self->{vars}{$1}/e; } return $string; } sub keyword { my $self = shift; my ($keyword, $override) = @_; { no warnings 'uninitialized'; croak "overrides passed to 'keyword' must be a hashref" if defined $override and ref $override ne 'HASH'; } return $self->_interpolate_vars( $self->{keywords}{$keyword}, $override ); } my $pkg_config_command; sub pkg_config_command { unless (defined $pkg_config_command) { capture_stderr { # For now we prefer PkgConfig.pm over pkg-config on # Solaris 64 bit Perls. We may need to do this on # other platforms, in which case this logic should # be abstracted so that it can be shared here and # in Build.PL if (`pkg-config --version` && $? == 0 && !($^O eq 'solaris' && $Config{ptrsize} == 8)) { $pkg_config_command = 'pkg-config'; } else { require PkgConfig; $pkg_config_command = "$^X $INC{'PkgConfig.pm'}"; } } } $pkg_config_command; } sub TO_JSON { my($self) = @_; my %hash = %$self; $hash{'__CLASS__'} = ref($self); \%hash; } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Base::PkgConfig - Private legacy pkg-config class for Alien::Base =head1 VERSION version 2.74 =head1 DESCRIPTION This class is used internally by L and L to store information from pkg-config about installed Aliens. It is not used internally by the newer L and L. It should never be used externally, should not be used for code new inside of C. =head1 SEE ALSO =over =item L =item L =item L =back =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Base/FAQ.pod000044400000003305152346246300006535 0ustar00# ABSTRACT: Frequently asked questions # VERSION # PODNAME: Alien::Base::FAQ __END__ =pod =encoding UTF-8 =head1 NAME Alien::Base::FAQ - Frequently asked questions =head1 VERSION version 2.74 =head1 SYNOPSIS % perldoc Alien::Build::Manual::FAQ % perldoc Alien::Base::ModuleBuild::FAQ =head1 DESCRIPTION This used to answer FAQs regarding the only way to author an L distribution, which was with L. You should now seriously consider using the newer more reliable method which is via L and L. =over 4 =item L =item L =back =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Role.pm000044400000004414152346246300006011 0ustar00package Alien::Role; use strict; use warnings; use 5.008004; # ABSTRACT: Extend Alien::Base with roles! our $VERSION = '2.74'; # VERSION 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Role - Extend Alien::Base with roles! =head1 VERSION version 2.74 =head1 SYNOPSIS package Alien::libfoo; use parent qw( Alien::Base ); use Role::Tiny::With qw( with ); with 'Alien::Role::Dino'; 1; =head1 DESCRIPTION The C namespace is intended for writing roles that can be applied to L to extend its functionality. You could of course write subclasses that extend L, but then you have to either stick with just one subclass or deal with multiple inheritance! It is recommended that you use L since it can be used on plain old Perl classes which is good since L doesn't use anything fancy like L or L. There is one working example that use this technique that are worth checking out in the event you are interested: L. This class itself doesn't do anything, it just documents the technique. =head1 SEE ALSO =over 4 =item L =item L =item L =item L =item L =back =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build.pm000044400000203534152346246300006153 0ustar00package Alien::Build; use strict; use warnings; use 5.008004; use Path::Tiny (); use Carp (); use File::chdir; use JSON::PP (); use Env qw( @PATH @PKG_CONFIG_PATH ); use Config (); use Alien::Build::Log; # ABSTRACT: Build external dependencies for use in CPAN our $VERSION = '2.74'; # VERSION sub _path { goto \&Path::Tiny::path } sub new { my($class, %args) = @_; my $self = bless { install_prop => { root => _path($args{root} || "_alien")->absolute->stringify, patch => (defined $args{patch}) ? _path($args{patch})->absolute->stringify : undef, }, runtime_prop => { alien_build_version => $Alien::Build::VERSION || 'dev', }, plugin_instance_prop => {}, bin_dir => [], pkg_config_path => [], aclocal_path => [], }, $class; # force computing this as soon as possible $self->download_rule; $self->meta->filename( $args{filename} || do { my(undef, $filename) = caller; _path($filename)->absolute->stringify; } ); if($args{meta_prop}) { $self->meta->prop->{$_} = $args{meta_prop}->{$_} for keys %{ $args{meta_prop} }; } $self; } my $count = 0; sub load { my(undef, $alienfile, @args) = @_; my $rcfile = Path::Tiny->new($ENV{ALIEN_BUILD_RC} || '~/.alienbuild/rc.pl')->absolute; if(-r $rcfile) { require Alien::Build::rc; package Alien::Build::rc; require $rcfile; } unless(-r $alienfile) { Carp::croak "Unable to read alienfile: $alienfile"; } my $file = _path $alienfile; my $name = $file->parent->basename; $name =~ s/^alien-//i; $name =~ s/[^a-z]//g; $name = 'x' if $name eq ''; $name = ucfirst $name; my $class = "Alien::Build::Auto::$name@{[ $count++ ]}"; { no strict 'refs'; @{ "${class}::ISA" } = ('Alien::Build'); *{ "${class}::Alienfile::meta" } = sub { $class =~ s{::Alienfile$}{}; $class->meta; }}; my @preload = qw( Core::Setup Core::Download Core::FFI Core::Override Core::CleanInstall ); push @preload, @Alien::Build::rc::PRELOAD; push @preload, split /;/, $ENV{ALIEN_BUILD_PRELOAD} if defined $ENV{ALIEN_BUILD_PRELOAD}; my @postload = qw( Core::Legacy Core::Gather Core::Tail ); push @postload, @Alien::Build::rc::POSTLOAD; push @postload, split /;/, $ENV{ALIEN_BUILD_POSTLOAD} if defined $ENV{ALIEN_BUILD_POSTLOAD}; my $self = $class->new( filename => $file->absolute->stringify, @args, ); require alienfile; foreach my $preload (@preload) { ref $preload eq 'CODE' ? $preload->($self->meta) : $self->meta->apply_plugin($preload); } # TODO: do this without a string eval ? ## no critic eval '# line '. __LINE__ . ' "' . __FILE__ . qq("\n) . qq{ package ${class}::Alienfile; do '@{[ $file->absolute->stringify ]}'; die \$\@ if \$\@; }; die $@ if $@; ## use critic foreach my $postload (@postload) { ref $postload eq 'CODE' ? $postload->($self->meta) : $self->meta->apply_plugin($postload); } $self->{args} = \@args; unless(defined $self->meta->prop->{arch}) { $self->meta->prop->{arch} = 1; } unless(defined $self->meta->prop->{network}) { $self->meta->prop->{network} = 1; ## https://github.com/PerlAlien/Alien-Build/issues/23#issuecomment-341114414 #$self->meta->prop->{network} = 0 if $ENV{NO_NETWORK_TESTING}; $self->meta->prop->{network} = 0 if (defined $ENV{ALIEN_INSTALL_NETWORK}) && ! $ENV{ALIEN_INSTALL_NETWORK}; } unless(defined $self->meta->prop->{local_source}) { if(! defined $self->meta->prop->{start_url}) { $self->meta->prop->{local_source} = 0; } # we assume URL schemes are at least two characters, that # way Windows absolute paths can be used as local start_url elsif($self->meta->prop->{start_url} =~ /^([a-z]{2,}):/i) { my $scheme = $1; $self->meta->prop->{local_source} = $scheme eq 'file'; } else { $self->meta->prop->{local_source} = 1; } } return $self; } sub resume { my(undef, $alienfile, $root) = @_; my $h = JSON::PP::decode_json(_path("$root/state.json")->slurp); my $self = Alien::Build->load("$alienfile", @{ $h->{args} }); $self->{install_prop} = $h->{install}; $self->{plugin_instance_prop} = $h->{plugin_instance}; $self->{runtime_prop} = $h->{runtime}; $self; } sub meta_prop { my($class) = @_; $class->meta->prop; } sub install_prop { shift->{install_prop}; } sub plugin_instance_prop { my($self, $plugin) = @_; my $instance_id = $plugin->instance_id; $self->{plugin_instance_prop}->{$instance_id} ||= {}; } sub runtime_prop { shift->{runtime_prop}; } sub hook_prop { shift->{hook_prop}; } sub _command_prop { my($self) = @_; return { alien => { install => $self->install_prop, runtime => $self->runtime_prop, hook => $self->hook_prop, meta => $self->meta_prop, }, perl => { config => \%Config::Config, }, env => \%ENV, }; } sub checkpoint { my($self) = @_; my $root = $self->root; _path("$root/state.json")->spew( JSON::PP->new->pretty->canonical(1)->ascii->encode({ install => $self->install_prop, runtime => $self->runtime_prop, plugin_instance => $self->{plugin_instance_prop}, args => $self->{args}, }) ); $self; } sub root { my($self) = @_; my $root = $self->install_prop->{root}; _path($root)->mkpath unless -d $root; $root; } sub install_type { my($self) = @_; $self->{runtime_prop}->{install_type} ||= $self->probe; } sub download_rule { my($self) = @_; $self->install_prop->{download_rule} ||= do { my $dr = $ENV{ALIEN_DOWNLOAD_RULE}; $dr = 'warn' unless defined $dr; $dr = 'warn' if $dr eq 'default'; unless($dr =~ /^(warn|digest|encrypt|digest_or_encrypt|digest_and_encrypt)$/) { $self->log("unknown ALIEN_DOWNLOAD_RULE \"$dr\", using \"warn\" instead"); $dr = 'warn'; } $dr; }; } sub set_prefix { my($self, $prefix) = @_; if($self->meta_prop->{destdir}) { $self->runtime_prop->{prefix} = $self->install_prop->{prefix} = $prefix; } else { $self->runtime_prop->{prefix} = $prefix; $self->install_prop->{prefix} = $self->install_prop->{stage}; } } sub set_stage { my($self, $dir) = @_; $self->install_prop->{stage} = $dir; } sub _merge { my %h; while(@_) { my $mod = shift; my $ver = shift; if((!defined $h{$mod}) || $ver > $h{$mod}) { $h{$mod} = $ver } } \%h; } sub requires { my($self, $phase) = @_; $phase ||= 'any'; my $meta = $self->meta; $phase =~ /^(?:any|configure)$/ ? $meta->{require}->{$phase} || {} : _merge %{ $meta->{require}->{any} }, %{ $meta->{require}->{$phase} }; } sub load_requires { my($self, $phase, $eval) = @_; my $reqs = $self->requires($phase); foreach my $mod (keys %$reqs) { my $ver = $reqs->{$mod}; my $check = sub { my $pm = "$mod.pm"; $pm =~ s{::}{/}g; require $pm; }; if($eval) { eval { $check->() }; die "Required $mod @{[ $ver || 'undef' ]}, missing" if $@; } else { $check->(); } # note Test::Alien::Build#alienfile_skip_if_missing_prereqs does a regex # on this diagnostic, so if you change it here, change it there too. die "Required $mod $ver, have @{[ $mod->VERSION || 0 ]}" if $ver && ! $mod->VERSION($ver); # allow for requires on Alien::Build or Alien::Base next if $mod eq 'Alien::Build'; next if $mod eq 'Alien::Base'; if($mod->can('bin_dir')) { push @{ $self->{bin_dir} }, $mod->bin_dir; } if(($mod->can('runtime_prop') && $mod->runtime_prop) || ($mod->isa('Alien::Base') && $mod->install_type('share'))) { for my $dir (qw(lib share)) { my $path = _path($mod->dist_dir)->child("$dir/pkgconfig"); if(-d $path) { push @{ $self->{pkg_config_path} }, $path->stringify; } } my $path = _path($mod->dist_dir)->child('share/aclocal'); if(-d $path) { $path = "$path"; if($^O eq 'MSWin32') { # convert to MSYS path $path =~ s{^([a-z]):}{/$1/}i; } push @{ $self->{aclocal_path} }, $path; } } # sufficiently new Autotools have a aclocal_dir which will # give us the directories we need. if($mod eq 'Alien::Autotools' && $mod->can('aclocal_dir')) { push @{ $self->{aclocal_path} }, $mod->aclocal_dir; } if($mod->can('alien_helper')) { my $helpers = $mod->alien_helper; foreach my $name (sort keys %$helpers) { my $code = $helpers->{$name}; $self->meta->interpolator->replace_helper($name => $code); } } } 1; } sub _call_hook { my $self = shift; local $ENV{PATH} = $ENV{PATH}; unshift @PATH, @{ $self->{bin_dir} }; local $ENV{PKG_CONFIG_PATH} = $ENV{PKG_CONFIG_PATH}; unshift @PKG_CONFIG_PATH, @{ $self->{pkg_config_path} }; local $ENV{ACLOCAL_PATH} = $ENV{ACLOCAL_PATH}; # autoconf uses MSYS paths, even for the ACLOCAL_PATH environment variable, so we can't use Env for this. { my @path; @path = split /:/, $ENV{ACLOCAL_PATH} if defined $ENV{ACLOCAL_PATH}; unshift @path, @{ $self->{aclocal_path} }; $ENV{ACLOCAL_PATH} = join ':', @path; } my $config = ref($_[0]) eq 'HASH' ? shift : {}; my($name, @args) = @_; local $self->{hook_prop} = {}; $self->meta->call_hook( $config, $name => $self, @args ); } sub probe { my($self) = @_; local $CWD = $self->root; my $dir; my $env = $self->_call_hook('override'); my $type; my $error; $env = '' if $env eq 'default'; if($env eq 'share') { $type = 'share'; } else { $type = eval { $self->_call_hook( { before => sub { $dir = Alien::Build::TempDir->new($self, "probe"); $CWD = "$dir"; }, after => sub { $CWD = $self->root; }, ok => 'system', continue => sub { if($_[0] eq 'system') { foreach my $name (qw( probe_class probe_instance_id )) { if(exists $self->hook_prop->{$name} && defined $self->hook_prop->{$name}) { $self->install_prop->{"system_$name"} = $self->hook_prop->{$name}; } } return undef; } else { return 1; } }, }, 'probe', ); }; $error = $@; $type = 'share' unless defined $type; } if($error) { if($env eq 'system') { die $error; } $self->log("error in probe (will do a share install): $@"); $self->log("Don't panic, we will attempt a share build from source if possible."); $self->log("Do not file a bug unless you expected a system install to succeed."); $type = 'share'; } if($env && $env ne $type) { die "requested $env install not available"; } if($type !~ /^(system|share)$/) { Carp::croak "probe hook returned something other than system or share: $type"; } if($type eq 'share' && (!$self->meta_prop->{network}) && (!$self->meta_prop->{local_source})) { $self->log("install type share requested or detected, but network fetch is turned off"); $self->log("see https://metacpan.org/pod/Alien::Build::Manual::FAQ#Network-fetch-is-turned-off"); Carp::croak "network fetch is turned off"; } $self->runtime_prop->{install_type} = $type; $type; } sub download { my($self) = @_; return $self unless $self->install_type eq 'share'; return $self if $self->install_prop->{complete}->{download}; if($self->meta->has_hook('download')) { my $tmp; local $CWD; my $valid = 0; $self->_call_hook( { before => sub { $tmp = Alien::Build::TempDir->new($self, "download"); $CWD = "$tmp"; }, verify => sub { my @list = grep { $_->basename !~ /^\./, } _path('.')->children; my $count = scalar @list; if($count == 0) { die "no files downloaded"; } elsif($count == 1) { my($archive) = $list[0]; if(-d $archive) { # TODO: this is probably a bug that we don't set # download or compelte properties? $self->log("single dir, assuming directory"); } else { $self->log("single file, assuming archive"); } $self->install_prop->{download} = $archive->absolute->stringify; $self->install_prop->{complete}->{download} = 1; $valid = 1; } else { $self->log("multiple files, assuming directory"); $self->install_prop->{complete}->{download} = 1; $self->install_prop->{download} = _path('.')->absolute->stringify; $valid = 1; } }, after => sub { $CWD = $self->root; }, }, 'download', ); # experimental and undocumented for now if($self->meta->has_hook('check_download')) { $self->meta->call_hook(check_download => $self); } return $self if $valid; } else { # This will call the default download hook # defined in Core::Download since the recipe # does not provide a download hook my $ret = $self->_call_hook('download'); # experimental and undocumented for now if($self->meta->has_hook('check_download')) { $self->meta->call_hook(check_download => $self); } return $self; } die "download failed"; } sub fetch { my $self = shift; my $url = $_[0] || $self->meta_prop->{start_url}; my $secure = 0; if(defined $url && ($url =~ /^(https|file):/ || $url !~ /:/)) { # considered secure when either https or a local file $secure = 1; } elsif(!defined $url) { $self->log("warning: undefined url in fetch"); } else { $self->log("warning: attempting to fetch a non-TLS or bundled URL: @{[ $url ]}"); } die "insecure fetch is not allowed" if $self->download_rule =~ /^(encrypt|digest_and_encrypt)$/ && !$secure; my $file = $self->_call_hook( 'fetch' => @_ ); $secure = 0; if(ref($file) ne 'HASH') { $self->log("warning: fetch returned non-hash reference"); } elsif(!defined $file->{protocol}) { $self->log("warning: fetch did not return a protocol"); } elsif($file->{protocol} !~ /^(https|file)$/) { $self->log("warning: fetch did not use a secure protocol: @{[ $file->{protocol} ]}"); } else { $secure = 1; } die "insecure fetch is not allowed" if $self->download_rule =~ /^(encrypt|digest_and_encrypt)$/ && !$secure; $file; } sub check_digest { my($self, $file) = @_; return '' unless $self->meta_prop->{check_digest}; unless(ref($file) eq 'HASH') { my $path = Path::Tiny->new($file); $file = { type => 'file', filename => $path->basename, path => "$path", tmp => 0, }; } my $path = $file->{path}; if(defined $path) { # there is technically a race condition here die "Missing file in digest check: @{[ $file->{filename} ]}" unless -f $path; die "Unreadable file in digest check: @{[ $file->{filename} ]}" unless -r $path; } else { die "File is wrong type" unless defined $file->{type} && $file->{type} eq 'file'; die "File has no filename" unless defined $file->{filename}; die "@{[ $file->{filename} ]} has no content" unless defined $file->{content}; } my $filename = $file->{filename}; my $signature = $self->meta_prop->{digest}->{$filename} || $self->meta_prop->{digest}->{'*'}; die "No digest for $filename" unless defined $signature && ref $signature eq 'ARRAY'; my($algo, $expected) = @$signature; if($self->meta->call_hook( check_digest => $self, $file, $algo, $expected )) { # record the verification here so that we can check in the extract step that the signature # was checked. $self->install_prop->{download_detail}->{$path}->{digest} = [$algo, $expected] if defined $path; return 1; } else { die "No plugin provides digest algorithm for $algo"; } } sub decode { my($self, $res) = @_; my $res2 = $self->_call_hook( decode => $res ); $res2->{protocol} = $res->{protocol} if !defined $res2->{protocol} && defined $res->{protocol}; return $res2; } sub prefer { my($self, $res) = @_; my $res2 = $self->_call_hook( prefer => $res ); $res2->{protocol} = $res->{protocol} if !defined $res2->{protocol} && defined $res->{protocol}; return $res2; } sub extract { my($self, $archive) = @_; $archive ||= $self->install_prop->{download}; unless(defined $archive) { die "tried to call extract before download"; } { my $checked_digest = 0; my $encrypted_fetch = 0; my $detail = $self->install_prop->{download_detail}->{$archive}; if(defined $detail) { if(defined $detail->{digest}) { my($algo, $expected) = @{ $detail->{digest} }; my $file = { type => 'file', filename => Path::Tiny->new($archive)->basename, path => $archive, tmp => 0, }; $checked_digest = $self->meta->call_hook( check_digest => $self, $file, $algo, $expected ) } if(!defined $detail->{protocol}) { $self->log("warning: extract did not receive protocol details for $archive") unless $checked_digest; } elsif($detail->{protocol} !~ /^(https|file)$/) { $self->log("warning: extracting from a file that was fetched via insecure protocol @{[ $detail->{protocol} ]}") unless $checked_digest ; } else { $encrypted_fetch = 1; } } else { $self->log("warning: extract received no download details for $archive"); } if($self->download_rule eq 'digest') { die "required digest missing for $archive" unless $checked_digest; } elsif($self->download_rule eq 'encrypt') { die "file was fetched insecurely for $archive" unless $encrypted_fetch; } elsif($self->download_rule eq 'digest_or_encrypt') { die "file was fetched insecurely and required digest missing for $archive" unless $checked_digest || $encrypted_fetch; } elsif($self->download_rule eq 'digest_and_encrypt') { die "file was fetched insecurely and required digest missing for $archive" unless $checked_digest || $encrypted_fetch; die "required digest missing for $archive" unless $checked_digest; die "file was fetched insecurely for $archive" unless $encrypted_fetch; } elsif($self->download_rule eq 'warn') { unless($checked_digest || $encrypted_fetch) { $self->log("!!! NOTICE OF FUTURE CHANGE IN BEHAVIOR !!!"); $self->log("a future version of Alien::Build will die here by default with this exception: file was fetched insecurely and required digest missing for $archive"); $self->log("!!! NOTICE OF FUTURE CHANGE IN BEHAVIOR !!!"); } } else { die "internal error, unknown download rule: @{[ $self->download_rule ]}"; } } my $nick_name = 'build'; if($self->meta_prop->{out_of_source}) { $nick_name = 'extract'; my $extract = $self->install_prop->{extract}; return $extract if defined $extract && -d $extract; } my $tmp; local $CWD; my $ret; $self->_call_hook({ before => sub { # called build instead of extract, because this # will be used for the build step, and technically # extract is a substage of build anyway. $tmp = Alien::Build::TempDir->new($self, $nick_name); $CWD = "$tmp"; }, verify => sub { my $path = '.'; if($self->meta_prop->{out_of_source} && $self->install_prop->{extract}) { $path = $self->install_prop->{extract}; } my @list = grep { $_->basename !~ /^\./ && $_->basename ne 'pax_global_header' } _path($path)->children; my $count = scalar @list; if($count == 0) { die "no files extracted"; } elsif($count == 1 && -d $list[0]) { $ret = $list[0]->absolute->stringify; } else { $ret = "$tmp"; } }, after => sub { $CWD = $self->root; }, }, 'extract', $archive); $self->install_prop->{extract} ||= $ret; $ret ? $ret : (); } sub build { my($self) = @_; # save the evironment, in case some plugins decide # to alter it. Or us! See just a few lines below. local %ENV = %ENV; my $stage = _path($self->install_prop->{stage}); $stage->mkpath; my $tmp; if($self->install_type eq 'share') { foreach my $suffix ('', '_ffi') { local $CWD; delete $ENV{DESTDIR} unless $self->meta_prop->{destdir}; my %env_meta = %{ $self->meta_prop ->{env} || {} }; my %env_inst = %{ $self->install_prop->{env} || {} }; if($self->meta_prop->{env_interpolate}) { foreach my $key (keys %env_meta) { $env_meta{$key} = $self->meta->interpolator->interpolate($env_meta{$key}, $self); } } %ENV = (%ENV, %env_meta); %ENV = (%ENV, %env_inst); my $destdir; $self->_call_hook( { before => sub { if($self->meta_prop->{out_of_source}) { $self->extract; $CWD = $tmp = Alien::Build::TempDir->new($self, 'build'); } else { $CWD = $tmp = $self->extract; } if($self->meta_prop->{destdir}) { $destdir = Alien::Build::TempDir->new($self, 'destdir'); $ENV{DESTDIR} = "$destdir"; } $self->_call_hook({ all => 1 }, "patch${suffix}"); }, after => sub { $destdir = "$destdir" if $destdir; }, }, "build${suffix}"); $self->install_prop->{"_ab_build@{[ $suffix || '_share' ]}"} = "$CWD"; $self->_call_hook("gather@{[ $suffix || '_share' ]}"); } } elsif($self->install_type eq 'system') { local $CWD = $self->root; my $dir; $self->_call_hook( { before => sub { $dir = Alien::Build::TempDir->new($self, "gather"); $CWD = "$dir"; }, after => sub { $CWD = $self->root; }, }, 'gather_system', ); $self->install_prop->{finished} = 1; $self->install_prop->{complete}->{gather_system} = 1; } $self; } sub test { my($self) = @_; if($self->install_type eq 'share') { foreach my $suffix ('_share', '_ffi') { if($self->meta->has_hook("test$suffix")) { my $dir = $self->install_prop->{"_ab_build$suffix"}; Carp::croak("no build directory to run tests") unless $dir && -d $dir; local $CWD = $dir; $self->_call_hook("test$suffix"); } } } else { if($self->meta->has_hook("test_system")) { my $dir = Alien::Build::TempDir->new($self, "test"); local $CWD = "$dir"; $self->_call_hook("test_system"); } } } sub clean_install { my($self) = @_; if($self->install_type eq 'share') { $self->_call_hook("clean_install"); } } sub system { my($self, $command, @args) = @_; my $prop = $self->_command_prop; ($command, @args) = map { $self->meta->interpolator->interpolate($_, $prop) } ($command, @args); $self->log("+ $command @args"); scalar @args ? system $command, @args : system $command; } sub log { my(undef, $message) = @_; my $caller = [caller]; chomp $message; foreach my $line (split /\n/, $message) { Alien::Build::Log->default->log( caller => $caller, message => $line, ); } } { my %meta; sub meta { my($class) = @_; $class = ref $class if ref $class; $meta{$class} ||= Alien::Build::Meta->new( class => $class ); } } package Alien::Build::Meta; our @CARP_NOT = qw( alienfile ); sub new { my($class, %args) = @_; my $self = bless { phase => 'any', build_suffix => '', require => { any => {}, share => {}, system => {}, }, around => {}, prop => {}, %args, }, $class; $self; } sub prop { shift->{prop}; } sub filename { my($self, $new) = @_; $self->{filename} = $new if defined $new; $self->{filename}; } sub add_requires { my $self = shift; my $phase = shift; while(@_) { my $module = shift; my $version = shift; my $old = $self->{require}->{$phase}->{$module}; if((!defined $old) || $version > $old) { $self->{require}->{$phase}->{$module} = $version } } $self; } sub interpolator { my($self, $new) = @_; if(defined $new) { if(defined $self->{intr}) { Carp::croak "tried to set interpolator twice"; } if(ref $new) { $self->{intr} = $new; } else { $self->{intr} = $new->new; } } elsif(!defined $self->{intr}) { require Alien::Build::Interpolate::Default; $self->{intr} = Alien::Build::Interpolate::Default->new; } $self->{intr}; } sub has_hook { my($self, $name) = @_; defined $self->{hook}->{$name}; } sub _instr { my($self, $name, $instr) = @_; if(ref($instr) eq 'CODE') { return $instr; } elsif(ref($instr) eq 'ARRAY') { my %phase = ( download => 'share', fetch => 'share', decode => 'share', prefer => 'share', extract => 'share', patch => 'share', patch_ffi => 'share', build => 'share', build_ffi => 'share', stage => 'share', gather_ffi => 'share', gather_share => 'share', gather_system => 'system', test_ffi => 'share', test_share => 'share', test_system => 'system', ); require Alien::Build::CommandSequence; my $seq = Alien::Build::CommandSequence->new(@$instr); $seq->apply_requirements($self, $phase{$name} || 'any'); return $seq; } else { Carp::croak "type not supported as a hook"; } } sub register_hook { my($self, $name, $instr) = @_; push @{ $self->{hook}->{$name} }, _instr $self, $name, $instr; $self; } sub default_hook { my($self, $name, $instr) = @_; $self->{default_hook}->{$name} = _instr $self, $name, $instr; $self; } sub around_hook { my($self, $name, $code) = @_; if(my $old = $self->{around}->{$name}) { # this is the craziest shit I have ever # come up with. $self->{around}->{$name} = sub { my $orig = shift; $code->(sub { $old->($orig, @_) }, @_); }; } else { $self->{around}->{$name} = $code; } } sub after_hook { my($self, $name, $code) = @_; $self->around_hook( $name => sub { my $orig = shift; my $ret = $orig->(@_); $code->(@_); $ret; } ); } sub before_hook { my($self, $name, $code) = @_; $self->around_hook( $name => sub { my $orig = shift; $code->(@_); my $ret = $orig->(@_); $ret; } ); } sub call_hook { my $self = shift; my %args = ref $_[0] ? %{ shift() } : (); my($name, @args) = @_; my $error; my @hooks = @{ $self->{hook}->{$name} || []}; if(@hooks == 0) { if(defined $self->{default_hook}->{$name}) { @hooks = ($self->{default_hook}->{$name}) } elsif(!$args{all}) { Carp::croak "No hooks registered for $name"; } } my $value; foreach my $hook (@hooks) { if(eval { $args[0]->isa('Alien::Build') }) { %{ $args[0]->{hook_prop} } = ( name => $name, ); } my $wrapper = $self->{around}->{$name} || sub { my $code = shift; $code->(@_) }; my $value; $args{before}->() if $args{before}; if(ref($hook) eq 'CODE') { $value = eval { my $value = $wrapper->(sub { $hook->(@_) }, @args); $args{verify}->('code') if $args{verify}; $value; }; } else { $value = $wrapper->(sub { eval { $hook->execute(@_); $args{verify}->('command') if $args{verify}; }; defined $args{ok} ? $args{ok} : 1; }, @args); } $error = $@; $args{after}->() if $args{after}; if($args{all}) { die if $error; } else { next if $error; next if $args{continue} && $args{continue}->($value); return $value; } } die $error if $error && ! $args{all}; $value; } sub apply_plugin { my($self, $name, @args) = @_; my $class; my $pm; my $found; if($name =~ /^=(.*)$/) { $class = $1; $pm = "$class.pm"; $pm =~ s!::!/!g; $found = 1; } if($name !~ /::/ && !$found) { foreach my $inc (@INC) { # TODO: allow negotiators to work with @INC hooks next if ref $inc; my $file = Path::Tiny->new("$inc/Alien/Build/Plugin/$name/Negotiate.pm"); if(-r $file) { $class = "Alien::Build::Plugin::${name}::Negotiate"; $pm = "Alien/Build/Plugin/$name/Negotiate.pm"; $found = 1; last; } } } unless($found) { $class = "Alien::Build::Plugin::$name"; $pm = "Alien/Build/Plugin/$name.pm"; $pm =~ s{::}{/}g; } require $pm unless $class->can('new'); my $plugin = $class->new(@args); $plugin->init($self); $self; } package Alien::Build::TempDir; # TODO: it's confusing that there is both a AB::TempDir and AB::Temp # although they do different things. there could maybe be a better # name for AB::TempDir (maybe AB::TempBuildDir, though that is a little # redundant). Happily both are private classes, and either are able to # rename, if a good name can be thought of. use overload '""' => sub { shift->as_string }, bool => sub { 1 }, fallback => 1; use File::Temp qw( tempdir ); sub new { my($class, $build, $name) = @_; my $root = $build->install_prop->{root}; Path::Tiny->new($root)->mkpath unless -d $root; bless { dir => Path::Tiny->new(tempdir( "${name}_XXXX", DIR => $root)), }, $class; } sub as_string { shift->{dir}->stringify; } sub DESTROY { my($self) = @_; if(-d $self->{dir} && $self->{dir}->children == 0) { rmdir($self->{dir}) || warn "unable to remove @{[ $self->{dir} ]} $!"; } } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build - Build external dependencies for use in CPAN =head1 VERSION version 2.74 =head1 SYNOPSIS my $build = Alien::Build->load('./alienfile'); $build->load_requires('configure'); $build->set_prefix('/usr/local'); $build->set_stage('/foo/mystage'); # needs to be absolute $build->load_requires($build->install_type); $build->download; $build->build; # files are now in /foo/mystage, it is your job (or # ExtUtils::MakeMaker, Module::Build, etc) to copy # those files into /usr/local =head1 DESCRIPTION This module provides tools for building external (non-CPAN) dependencies for CPAN. It is mainly designed to be used at install time of a CPAN client, and work closely with L which is used at runtime. This is the detailed documentation for the L class. If you are starting out you probably want to do so from one of these documents: =over 4 =item L A broad overview of C and its ecosystem. =item L For users of an C that is implemented using L. (The developer of C I provide the documentation necessary, but if not, this is the place to start). =item L If you are writing your own L based on L and L. =item L If you have a common question that has already been answered, like "How do I use L with some build system". =item L This is for the brave souls who want to write plugins that will work with L + L. =item L If you are concerned that Ls might be downloading tarballs off the internet, then this is the place for you. This will discuss some of the risks of downloading (really any) software off the internet and will give you some tools to remediate these risks. =back Note that you will not usually create a L instance directly, but rather be using a thin installer layer, such as L (for use with L) or L (for use with L). One of the goals of this project is to remain installer agnostic. =head1 CONSTRUCTORS =head2 new my $build = Alien::Build->new; This creates a new empty instance of L. Normally you will want to use C below to create an instance of L from an L recipe. =head2 load my $build = Alien::Build->load($alienfile); This creates an L instance with the given L recipe. =head2 resume my $build = Alien::Build->resume($alienfile, $root); Load a checkpointed L instance. You will need the original L and the build root (usually C<_alien>), and a build that had been properly checkpointed using the C method below. =head1 PROPERTIES There are three main properties for L. There are a number of properties documented here with a specific usage. Note that these properties may need to be serialized into something primitive like JSON that does not support: regular expressions, code references of blessed objects. If you are writing a plugin (L) you should use a prefix like "plugin_I" (where I is the name of your plugin) so that it does not interfere with other plugin or future versions of L. For example, if you were writing C, please use the prefix C: sub init { my($self, $meta) = @_; $meta->prop( plugin_fetch_newprotocol_foo => 'some value' ); $meta->register_hook( some_hook => sub { my($build) = @_; $build->install_prop->{plugin_fetch_newprotocol_bar} = 'some other value'; $build->runtime_prop->{plugin_fetch_newprotocol_baz} = 'and another value'; } ); } If you are writing a L recipe please use the prefix C: use alienfile; meta_prop->{my_foo} = 'some value'; probe sub { my($build) = @_; $build->install_prop->{my_bar} = 'some other value'; $build->install_prop->{my_baz} = 'and another value'; }; Any property may be used from a command: probe [ 'some command %{.meta.plugin_fetch_newprotocol_foo}' ]; probe [ 'some command %{.install.plugin_fetch_newprotocol_bar}' ]; probe [ 'some command %{.runtime.plugin_fetch_newprotocol_baz}' ]; probe [ 'some command %{.meta.my_foo}' ]; probe [ 'some command %{.install.my_bar}' ]; probe [ 'some command %{.runtime.my_baz}' ]; =head2 meta_prop my $href = $build->meta_prop; my $href = Alien::Build->meta_prop; Meta properties have to do with the recipe itself, and not any particular instance that probes or builds that recipe. Meta properties can be changed from within an L using the C directive, or from a plugin from its C method (though should NOT be modified from any hooks registered within that C method). This is not strictly enforced, but if you do not follow this rule your recipe will likely be broken. =over =item arch This is a hint to an installer like L or L, that the library or tool contains architecture dependent files and so should be stored in an architecture dependent location. If not specified by your L then it will be set to true. =item check_digest True if cryptographic digest should be checked when files are fetched or downloaded. This is set by L. =item destdir Some plugins (L for example) support installing via C. They will set this property to true if they plan on doing such an install. This helps L find the staged install files and how to locate them. If available, C is used to stage install files in a sub directory before copying the files into C. This is generally preferred method if available. =item destdir_filter Regular expression for the files that should be copied from the C into the stage directory. If not defined, then all files will be copied. =item destdir_ffi_filter Same as C except applies to C instead of C. =item digest This properties contains the cryptographic digests (if any) that should be used when verifying any fetched and downloaded files. It is a hash reference where the key is the filename and the value is an array reference containing a pair of values, the first being the algorithm ('SHA256' is recommended) and the second is the actual digest. The special filename C<*> may be specified to indicate that any downloaded file should match that digest. If there are both real filenames and the C<*> placeholder, the real filenames will be used for filenames that match and any other files will use the placeholder. Example: $build->meta_prop->{digest} = { 'foo-1.00.tar.gz' => [ SHA256 => '9feac593aa49a44eb837de52513a57736457f1ea70078346c60f0bfc5f24f2c1' ], 'foo-1.01.tar.gz' => [ SHA256 => '6bbde6a7f10ae5924cf74afc26ff5b7bc4b4f9dfd85c6b534c51bd254697b9e7' ], '*' => [ SHA256 => '33a20aae3df6ecfbe812b48082926d55391be4a57d858d35753ab1334b9fddb3' ], }; Cryptographic signatures will only be checked if the L is set and if the L is loaded. (The Digest negotiator can be used directly, but is also loaded automatically if you use the L is used by the L). =item env Environment variables to override during the build stage. =item env_interpolate Environment variable values will be interpolated with helpers. Example: meta->prop->{env_interpolate} = 1; meta->prop->{env}->{PERL} = '%{perl}'; =item local_source Set to true if source code package is available locally. (that is not fetched over the internet). This is computed by default based on the C property. Can be set by an L or plugin. =item platform Hash reference. Contains information about the platform beyond just C<$^O>. =over 4 =item platform.compiler_type Refers to the type of flags that the compiler accepts. May be expanded in the future, but for now, will be one of: =over 4 =item microsoft On Windows when using Microsoft Visual C++ =item unix Virtually everything else, including gcc on windows. =back The main difference is that with Visual C++ C<-LIBPATH> should be used instead of C<-L>, and static libraries should have the C<.LIB> suffix instead of C<.a>. =item platform.system_type C<$^O> is frequently good enough to make platform specific logic in your L, this handles the case when $^O can cover platforms that provide multiple environments that Perl might run under. The main example is windows, but others may be added in the future. =over 4 =item unix =item vms =item windows-activestate =item windows-microsoft =item windows-mingw =item windows-strawberry =item windows-unknown =back Note that C and C are considered C even though they run on windows! =item platform.cpu.count Contains a non-negative integer of available (possibly virtual) CPUs on the system. This can be used by build plugins to build in parallel. The environment variable C can be set to override the CPU count. =item platform.cpu.arch.name Contains a normalized name for the architecture of the current Perl. This can be used by fetch plugins to determine which binary packages to download. The value may be one of the following, but this list will be expanded as needed. =over 4 =item C 32-bit ARM soft-float =item C 32-bit ARM hard-float =item C 64-bit ARM =item C 32-bit PowerPC (big-endian) =item C 64-bit PowerPC (big-endian) =item C 32-bit Intel (i386, i486, i686) =item C 64-bit Intel (AMD64) =item C Unable to detect architecture. Please report this if needed. =back =back =item out_of_source Build in a different directory from the where the source code is stored. In autoconf this is referred to as a "VPATH" build. Everyone else calls this an "out-of-source" build. When this property is true, instead of extracting to the source build root, the downloaded source will be extracted to an source extraction directory and the source build root will be empty. You can use the C install property to get the location of the extracted source. =item network True if a network fetch is available. This should NOT be set by an L or plugin. This is computed based on the C environment variables. =item start_url The default or start URL used by fetch plugins. =back =head2 install_prop my $href = $build->install_prop; Install properties are used during the install phase (either under C or C install). They are remembered for the entire install phase, but not kept around during the runtime phase. Thus they cannot be accessed from your L based module. =over =item autoconf_prefix The prefix as understood by autoconf. This is only different on Windows Where MSYS is used and paths like C are represented as C which are understood by the MSYS tools, but not by Perl. You should only use this if you are using L in your L. This is set during before the L is run. =item download The location of the downloaded archive (tar.gz, or similar) or directory. This will be undefined until the archive is actually downloaded. =item download_detail This property contains optional details about a downloaded file. This property is populated by L core. This property is a hash reference. The key is the path to the file that has been downloaded and the value is a hash reference with additional detail. All fields are optional. =over 4 =item download_detail.digest This, if available, with the cryptographic signature that was successfully matched against the downloaded file. It is an array reference with a pair of values, the algorithm (typically something like C) and the digest. =item download_detail.protocol This, if available, will be the URL protocol used to fetch the downloaded file. =back =item env Environment variables to override during the build stage. Plugins are free to set additional overrides using this hash. =item extract The location of the last source extraction. For a "out-of-source" build (see the C meta property above), this will only be set once. For other types of builds, the source code may be extracted multiple times, and thus this property may change. =item old [deprecated] Hash containing information on a previously installed Alien of the same name, if available. This may be useful in cases where you want to reuse the previous install if it is still sufficient. =over 4 =item old.prefix [deprecated] The prefix for the previous install. Versions prior to 1.42 unfortunately had this in typo form of C. =item old.runtime [deprecated] The runtime properties from the previous install. =back =item patch Directory with patches, if available. This will be C if there are no patches. When initially installing an alien this will usually be a sibling of the C, a directory called C. Once installed this will be in the share directory called C<_alien/patch>. The former is useful for rebuilding an alienized package using L. =item prefix The install time prefix. Under a C install this is the same as the runtime or final install location. Under a non-C install this is the C directory (usually the appropriate share directory under C). =item root The build root directory. This will be an absolute path. It is the absolute form of C<./_alien> by default. =item stage The stage directory where files will be copied. This is usually the root of the blib share directory. =item system_probe_class After the probe step this property may contain the plugin class that performed the system probe. It shouldn't be filled in directly by the plugin (instead if should use the hook property C, see below). This is optional, and not all probe plugins will provide this information. =item system_probe_instance_id After the probe step this property may contain the plugin instance id that performed the system probe. It shouldn't be filled in directly by the plugin (instead if should use the hook property C, see below). This is optional, and not all probe plugins will provide this information. =back =head2 plugin_instance_prop my $href = $build->plugin_instance_prop($plugin); This returns the private plugin instance properties for a given plugin. This method should usually only be called internally by plugins themselves to keep track of internal state. Because the content can be used arbitrarily by the owning plugin because it is private to the plugin, and thus is not part of the L spec. =head2 runtime_prop my $href = $build->runtime_prop; Runtime properties are used during the install and runtime phases (either under C or C install). This should include anything that you will need to know to use the library or tool during runtime, and shouldn't include anything that is no longer relevant once the install process is complete. =over 4 =item alien_build_version The version of L used to install the library or tool. =item alt Alternate configurations. If the alienized package has multiple libraries this could be used to store the different compiler or linker flags for each library. Typically this will be set by a plugin in the gather stage (for either share or system installs). =item cflags The compiler flags. This is typically set by a plugin in the gather stage (for either share or system installs). =item cflags_static The static compiler flags. This is typically set by a plugin in the gather stage (for either share or system installs). =item command The command name for tools where the name my differ from platform to platform. For example, the GNU version of make is usually C in Linux and C on FreeBSD. This is typically set by a plugin in the gather stage (for either share or system installs). =item ffi_name The name DLL or shared object "name" to use when searching for dynamic libraries at runtime. This is passed into L, so if your library is something like C or C you would set this to C. This may be a string or an array of strings. This is typically set by a plugin in the gather stage (for either share or system installs). =item ffi_checklib This property contains two sub properties: =over 4 =item ffi_checklib.share $build->runtime_prop->{ffi_checklib}->{share} = [ ... ]; Array of additional L flags to pass in to C for a C install. =item ffi_checklib.system Array of additional L flags to pass in to C for a C install. Among other things, useful for specifying the C flag: $build->runtime_prop->{ffi_checklib}->{system} = [ try_linker_script => 1 ]; =back This is typically set by a plugin in the gather stage (for either share or system installs). =item inline_auto_include [version 2.53] This property is an array reference of C code that will be passed into L to make sure that appropriate headers are automatically included. See L for details. =item install_type The install type. This is set by AB core after the L is executed. Is one of: =over 4 =item system For when the library or tool is provided by the operating system, can be detected by L, and is considered satisfactory by the C recipe. =item share For when a system install is not possible, the library source will be downloaded from the internet or retrieved in another appropriate fashion and built. =back =item libs The library flags. This is typically set by a plugin in the gather stage (for either share or system installs). =item libs_static The static library flags. This is typically set by a plugin in the gather stage (for either share or system installs). =item perl_module_version The version of the Perl module used to install the alien (if available). For example if L is installing C this would be the version of L used during the install step. =item prefix The final install root. This is usually they share directory. =item version The version of the library or tool. This is typically set by a plugin in the gather stage (for either share or system installs). =back =head2 hook_prop my $href = $build->hook_prop; Hook properties are for the currently running (if any) hook. They are used only during the execution of each hook and are discarded after. If no hook is currently running then C will return C. =over 4 =item name The name of the currently running hook. =item version (probe) Probe and PkgConfig plugins I set this property indicating the version of the alienized package. Not all plugins and configurations may be able to provide this. =item probe_class (probe) Probe and PkgConfig plugins I set this property indicating the plugin class that made the probe. If the probe results in a system install this will be propagated to C for later use. =item probe_instance_id (probe) Probe and PkgConfig plugins I set this property indicating the plugin instance id that made the probe. If the probe results in a system install this will be propagated to C for later use. =back =head1 METHODS =head2 checkpoint $build->checkpoint; Save any install or runtime properties so that they can be reloaded on a subsequent run in a separate process. This is useful if your build needs to be done in multiple stages from a C, such as with L. Once checkpointed you can use the C constructor (documented above) to resume the probe/build/install] process. =head2 root my $dir = $build->root; This is just a shortcut for: my $root = $build->install_prop->{root}; Except that it will be created if it does not already exist. =head2 install_type my $type = $build->install_type; This will return the install type. (See the like named install property above for details). This method will call C if it has not already been called. =head2 download_rule my $rule = $build->download_rule; This returns install rule as a string. This is determined by the environment and should be one of: =over 4 =item C Warn only if fetching via non secure source (secure sources include C, and bundled files, may include other encrypted protocols in the future). =item C Require that any downloaded source package have a cryptographic signature in the L and that signature matches what was downloaded. =item C Require that any downloaded source package is fetched via secure source. =item C Require that any downloaded source package is B fetched via a secure source B has a cryptographic signature in the L and that signature matches what was downloaded. =item C Require that any downloaded source package is B fetched via a secure source B has a cryptographic signature in the L and that signature matches what was downloaded. =back The current default is C, but in the near future this will be upgraded to C. =head2 set_prefix $build->set_prefix($prefix); Set the final (unstaged) prefix. This is normally only called by L and similar modules. It is not intended for use from plugins or from an L. =head2 set_stage $build->set_stage($dir); Sets the stage directory. This is normally only called by L and similar modules. It is not intended for use from plugins or from an L. =head2 requires my $hash = $build->requires($phase); Returns a hash reference of the modules required for the given phase. Phases include: =over 4 =item configure These modules must already be available when the L is read. =item any These modules are used during either a C or C install. =item share These modules are used during the build phase of a C install. =item system These modules are used during the build phase of a C install. =back =head2 load_requires $build->load_requires($phase); This loads the appropriate modules for the given phase (see C above for a description of the phases). =head2 probe my $install_type = $build->probe; Attempts to determine if the operating system has the library or tool already installed. If so, then the string C will be returned and a system install will be performed. If not, then the string C will be installed and the tool or library will be downloaded and built from source. If the environment variable C is set, then that will force a specific type of install. If the detection logic cannot accommodate the install type requested then it will fail with an exception. =head2 download $build->download; Download the source, usually as a tarball, usually from the internet. Under a C install this does not do anything. =head2 fetch my $res = $build->fetch; my $res = $build->fetch($url, %options); Fetch a resource using the fetch hook. Returns the same hash structure described below in the L documentation. [version 2.39] As of L 2.39, these options are supported: =over 4 =item http_headers my $res = $build->fetch($url, http_headers => [ $key1 => $value1, $key2 => $value 2, ... ]); Set the HTTP request headers on all outgoing HTTP requests. Note that not all protocols or fetch plugins support setting request headers, but the ones that do not I issue a warning if you try to set request headers and they are not supported. =back =head2 check_digest [experimental] my $bool = $build->check_digest($path); Checks any cryptographic signatures for the given file. The file is specified by C<$path> which may be one of: =over 4 =item string Containing the path to the file to be checked. =item L Containing the path to the file to be checked. =item C A Hash reference containing information about a file. See the L for details on the format. =back Returns true if the cryptographic signature matches, false if cryptographic signatures are disabled. Will throw an exception if the signature does not match, or if no plugin provides the correct algorithm for checking the signature. =head2 decode my $decoded_res = $build->decode($res); Decode the HTML or file listing returned by C. Returns the same hash structure described below in the L documentation. =head2 prefer my $sorted_res = $build->prefer($res); Filter and sort candidates. The preferred candidate will be returned first in the list. The worst candidate will be returned last. Returns the same hash structure described below in the L documentation. =head2 extract my $dir = $build->extract; my $dir = $build->extract($archive); Extracts the given archive into a fresh directory. This is normally called internally to L, and for normal usage is not needed from a plugin or L. =head2 build $build->build; Run the build step. It is expected that C and C have already been performed. What it actually does depends on the type of install: =over 4 =item share The source is extracted, and built as determined by the L recipe. If there is a C that will be executed last. =item system The L will be executed. =back =head2 test $build->test; Run the test phase =head2 clean_install $build->clean_install Clean files from the final install location. The default implementation removes all files recursively except for the C<_alien> directory. This is helpful when you have an old install with files that may break the new build. For a non-share install this doesn't do anything. =head2 system $build->system($command); $build->system($command, @args); Interpolates the command and arguments and run the results using the Perl C command. =head2 log $build->log($message); Send a message to the log. By default this prints to C. =head2 meta my $meta = Alien::Build->meta; my $meta = $build->meta; Returns the meta object for your L class or instance. The meta object is a way to manipulate the recipe, and so any changes to the meta object should be made before the C, C or C steps. =head1 META METHODS =head2 prop my $href = $build->meta->prop; Meta properties. This is the same as calling C on the class or L instance. =head2 add_requires Alien::Build->meta->add_requires($phase, $module => $version, ...); Add the requirement to the given phase. Phase should be one of: =over 4 =item configure =item any =item share =item system =back =head2 interpolator my $interpolator = $build->meta->interpolator; my $interpolator = Alien::Build->interpolator; Returns the L instance for the L class. =head2 has_hook my $bool = $build->meta->has_hook($name); my $bool = Alien::Build->has_hook($name); Returns if there is a usable hook registered with the given name. =head2 register_hook $build->meta->register_hook($name, $instructions); Alien::Build->meta->register_hook($name, $instructions); Register a hook with the given name. C<$instruction> should be either a code reference, or a command sequence, which is an array reference. =head2 default_hook $build->meta->default_hook($name, $instructions); Alien::Build->meta->default_hook($name, $instructions); Register a default hook, which will be used if the L does not register its own hook with that name. =head2 around_hook $build->meta->around_hook($hook_name, $code); Alien::Build->meta->around_hook($hook_name, $code); Wrap the given hook with a code reference. This is similar to a L method modifier, except that it wraps around the given hook instead of a method. For example, this will add a probe system requirement: $build->meta->around_hook( probe => sub { my $orig = shift; my $build = shift; my $type = $orig->($build, @_); return $type unless $type eq 'system'; # also require a configuration file if(-f '/etc/foo.conf') { return 'system'; } else { return 'share'; } }, ); =head2 after_hook $build->meta->after_hook($hook_name, sub { my(@args) = @_; ... }); Execute the given code reference after the hook. The original arguments are passed into the code reference. =head2 before_hook $build->meta->before_hook($hook_name, sub { my(@args) = @_; ... }); Execute the given code reference before the hook. The original arguments are passed into the code reference. =head2 apply_plugin Alien::Build->meta->apply_plugin($name); Alien::Build->meta->apply_plugin($name, @args); Apply the given plugin with the given arguments. =head1 ENVIRONMENT L responds to these environment variables: =over 4 =item ALIEN_BUILD_LOG The default log class used. See L and L. =item ALIEN_BUILD_PKG_CONFIG Override the logic in L which chooses the best C plugin. =item ALIEN_BUILD_POSTLOAD semicolon separated list of plugins to automatically load after parsing your L. =item ALIEN_BUILD_PRELOAD semicolon separated list of plugins to automatically load before parsing your L. =item ALIEN_BUILD_RC Perl source file which can override some global defaults for L, by, for example, setting preload and postload plugins. =item ALIEN_DOWNLOAD_RULE This value determines the rules by which types of downloads are allowed. The legal values listed under L, plus C which will be the default for the current version of L. For this version that default is C. =item ALIEN_INSTALL_NETWORK If set to true (the default), then network fetch will be allowed. If set to false, then network fetch will not be allowed. What constitutes a local vs. network fetch is determined based on the C and C meta properties. An L or plugin C override this detection (possibly inappropriately), so this variable is not a substitute for properly auditing of Perl modules for environments that require that. =item ALIEN_INSTALL_TYPE If set to C or C, it will override the system detection logic. If set to C, it will use the default setting for the L. The behavior of other values is undefined. Although the recommended way for a consumer to use an L based L is to declare it as a static configure and build-time dependency, some consumers may prefer to fallback on using an L only when the consumer itself cannot detect the necessary package. In some cases the consumer may want the user to opt-in to using an L before requiring it. To keep the interface consistent among Aliens, the consumer of the fallback opt-in L may fallback on the L if the environment variable C is set to any value. The rationale is that by setting this environment variable the user is aware that L modules may be installed and have indicated consent. The actual implementation of this, by its nature would have to be in the consuming CPAN module. =item DESTDIR This environment variable will be manipulated during a destdir install. =item PKG_CONFIG This environment variable can be used to override the program name for C when using the command line plugin: L. =item ftp_proxy, all_proxy If these environment variables are set, it may influence the Download negotiation plugin L. Other proxy variables may be used by some Fetch plugins, if they support it. =back =head1 SUPPORT The intent of the C team is to support as best as possible all Perls from 5.8.4 to the latest production version. So long as they are also supported by the Perl toolchain. Please feel encouraged to report issues that you encounter to the project GitHub Issue tracker: =over 4 =item L =back Better if you can fix the issue yourself, please feel encouraged to open pull-request on the project GitHub: =over 4 =item L =back If you are confounded and have questions, join us on the C<#native> channel on irc.perl.org. The C developers frequent this channel and can probably help point you in the right direction. If you don't have an IRC client handy, you can use this web interface: =over 4 =item L =back =head1 SEE ALSO L, L, L, L, L L, L, L, L, L =head1 THANKS L was originally written by Joel Berger, the rest of this project would not have been possible without him getting the project started. Thanks to his support I have been able to augment the original L system with a reliable set of tools (L, L, L), which make up this toolset. The original L is still copyright (c) 2012-2020 Joel Berger. It has the same license as the rest of the Alien::Build and related tools distributed as C. Joel Berger thanked a number of people who helped in in the development of L, in the documentation for that module. I would also like to acknowledge the other members of the PerlAlien github organization, Zakariyya Mughal (sivoais, ZMUGHAL) and mohawk (ETJ). Also important in the early development of L were the early adopters Chase Whitener (genio, CAPOEIRAB, author of L), William N. Braswell, Jr (willthechill, WBRASWELL, author of L and L) and Ahmad Fatoum (a3f, ATHREEF, author of L and L). The Alien ecosystem owes a debt to Dan Book, who goes by Grinnz on IRC, for answering question about how to use L and friends. =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/CommandSequence.pm000044400000011655152346246300011223 0ustar00package Alien::Build::CommandSequence; use strict; use warnings; use 5.008004; use Text::ParseWords qw( shellwords ); use Capture::Tiny qw( capture ); # ABSTRACT: Alien::Build command sequence our $VERSION = '2.74'; # VERSION sub new { my($class, @commands) = @_; my $self = bless { commands => \@commands, }, $class; $self; } sub apply_requirements { my($self, $meta, $phase) = @_; my $intr = $meta->interpolator; foreach my $command (@{ $self->{commands} }) { next if ref $command eq 'CODE'; if(ref $command eq 'ARRAY') { foreach my $arg (@$command) { next if ref $arg eq 'CODE'; $meta->add_requires($phase, $intr->requires($arg)) } } else { $meta->add_requires($phase, $intr->requires($command)); } } $self; } my %built_in = ( cd => sub { my(undef, $dir) = @_; if(!defined $dir) { die "undef passed to cd"; } elsif(-d $dir) { chdir($dir) || die "unable to cd $dir $!"; } else { die "unable to cd $dir, does not exist"; } }, ); sub _run_list { my($build, @cmd) = @_; $build->log("+ @cmd"); return $built_in{$cmd[0]}->(@cmd) if $built_in{$cmd[0]}; system @cmd; die "external command failed" if $?; } sub _run_string { my($build, $cmd) = @_; $build->log("+ $cmd"); { my $cmd = $cmd; $cmd =~ s{\\}{\\\\}g if $^O eq 'MSWin32'; my @cmd = shellwords($cmd); return $built_in{$cmd[0]}->(@cmd) if $built_in{$cmd[0]}; } system $cmd; die "external command failed" if $?; } sub _run_with_code { my($build, @cmd) = @_; my $code = pop @cmd; $build->log("+ @cmd"); my %args = ( command => \@cmd ); if($built_in{$cmd[0]}) { my $error; ($args{out}, $args{err}, $error) = capture { eval { $built_in{$cmd[0]}->(@cmd) }; $@; }; $args{exit} = $error eq '' ? 0 : 2; $args{builtin} = 1; } else { ($args{out}, $args{err}, $args{exit}) = capture { system @cmd; $? }; } $build->log("[output consumed by Alien::Build recipe]"); $code->($build, \%args); } sub _apply { my($where, $prop, $value) = @_; if($where =~ /^(.*?)\.(.*?)$/) { _apply($2, $prop->{$1}, $value); } else { $prop->{$where} = $value; } } sub execute { my($self, $build) = @_; my $intr = $build->meta->interpolator; foreach my $command (@{ $self->{commands} }) { if(ref($command) eq 'CODE') { $command->($build); } elsif(ref($command) eq 'ARRAY') { my($command, @args) = @$command; my $code; $code = pop @args if $args[-1] && ref($args[-1]) eq 'CODE'; if($args[-1] && ref($args[-1]) eq 'SCALAR') { my $dest = ${ pop @args }; if($dest =~ /^\%\{((?:alien|)\.(?:install|runtime|hook)\.[a-z\.0-9_]+)\}$/) { $dest = $1; $dest =~ s/^\./alien./; $code = sub { my($build, $args) = @_; die "external command failed" if $args->{exit}; my $out = $args->{out}; chomp $out; _apply($dest, $build->_command_prop, $out); }; } else { die "illegal destination: $dest"; } } ($command, @args) = map { $intr->interpolate($_, $build) } ($command, @args); if($code) { _run_with_code $build, $command, @args, $code; } else { _run_list $build, $command, @args; } } else { my $command = $intr->interpolate($command, $build); _run_string $build, $command; } } } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::CommandSequence - Alien::Build command sequence =head1 VERSION version 2.74 =head1 CONSTRUCTOR =head2 new my $seq = Alien::Build::CommandSequence->new(@commands); =head1 METHODS =head2 apply_requirements $seq->apply_requirements($meta, $phase); =head2 execute $seq->execute($build); =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/MM.pm000044400000035622152346246300006465 0ustar00package Alien::Build::MM; use strict; use warnings; use 5.008004; use Alien::Build; use Path::Tiny (); use Capture::Tiny qw( capture ); use Carp (); # ABSTRACT: Alien::Build installer code for ExtUtils::MakeMaker our $VERSION = '2.74'; # VERSION sub new { my($class, %prop) = @_; my $self = bless {}, $class; my %meta = map { $_ => $prop{$_} } grep /^my_/, keys %prop; my $build = $self->{build} = Alien::Build->load('alienfile', root => "_alien", (-d 'patch' ? (patch => 'patch') : ()), meta_prop => \%meta, ) ; if(%meta) { $build->meta->add_requires(configure => 'Alien::Build::MM' => '1.20'); $build->meta->add_requires(configure => 'Alien::Build' => '1.20'); } if(defined $prop{alienfile_meta}) { $self->{alienfile_meta} = $prop{alienfile_meta}; } else { $self->{alienfile_meta} = 1; } $self->{clean_install} = $prop{clean_install}; $self->build->load_requires('configure'); $self->build->root; $self->build->checkpoint; $self; } sub build { shift->{build}; } sub alienfile_meta { shift->{alienfile_meta}; } sub clean_install { shift->{clean_install}; } sub mm_args { my($self, %args) = @_; if($args{DISTNAME}) { $self->build->set_stage(Path::Tiny->new("blib/lib/auto/share/dist/$args{DISTNAME}")->absolute->stringify); $self->build->install_prop->{mm}->{distname} = $args{DISTNAME}; my $module = $args{DISTNAME}; $module =~ s/-/::/g; # See if there is an existing version installed, without pulling it into this process my($old_prefix, $err, $ret) = capture { system $^X, "-M$module", -e => "print $module->dist_dir"; $? }; if($ret == 0) { chomp $old_prefix; my $file = Path::Tiny->new($old_prefix, qw( _alien alien.json )); if(-r $file) { my $old_runtime = eval { require JSON::PP; JSON::PP::decode_json($file->slurp); }; unless($@) { $self->build->install_prop->{old}->{runtime} = $old_runtime; $self->build->install_prop->{old}->{prefix} = $old_prefix; } } } } else { Carp::croak "DISTNAME is required"; } my $ab_version = '0.25'; if($self->clean_install) { $ab_version = '1.74'; } $args{CONFIGURE_REQUIRES} = Alien::Build::_merge( 'Alien::Build::MM' => $ab_version, %{ $args{CONFIGURE_REQUIRES} || {} }, %{ $self->build->requires('configure') || {} }, ); if($self->build->install_type eq 'system') { $args{BUILD_REQUIRES} = Alien::Build::_merge( 'Alien::Build::MM' => $ab_version, %{ $args{BUILD_REQUIRES} || {} }, %{ $self->build->requires('system') || {} }, ); } elsif($self->build->install_type eq 'share') { $args{BUILD_REQUIRES} = Alien::Build::_merge( 'Alien::Build::MM' => $ab_version, %{ $args{BUILD_REQUIRES} || {} }, %{ $self->build->requires('share') || {} }, ); } else { die "unknown install type: @{[ $self->build->install_type ]}" } $args{PREREQ_PM} = Alien::Build::_merge( 'Alien::Build' => $ab_version, %{ $args{PREREQ_PM} || {} }, ); #$args{META_MERGE}->{'meta-spec'}->{version} = 2; $args{META_MERGE}->{dynamic_config} = 1; if($self->alienfile_meta) { $args{META_MERGE}->{x_alienfile} = { generated_by => "@{[ __PACKAGE__ ]} version @{[ __PACKAGE__->VERSION || 'dev' ]}", requires => { map { my %reqs = %{ $self->build->requires($_) }; $reqs{$_} = "$reqs{$_}" for keys %reqs; $_ => \%reqs; } qw( share system ) }, }; } $self->build->checkpoint; %args; } sub mm_postamble { # NOTE: older versions of the Alien::Build::MM documentation # didn't include $mm and @rest args, so anything that this # method uses them for has to be optional. # (as of this writing they are unused, but are being added # to match the way mm_install works). my($self, $mm, @rest) = @_; my $postamble = ''; # remove the _alien directory on a make realclean: $postamble .= "realclean :: alien_realclean\n" . "\n" . "alien_realclean:\n" . "\t\$(RM_RF) _alien\n\n"; # remove the _alien directory on a make clean: $postamble .= "clean :: alien_clean\n" . "\n" . "alien_clean:\n" . "\t\$(RM_RF) _alien\n\n"; my $dirs = $self->build->meta_prop->{arch} ? '$(INSTALLARCHLIB) $(INSTALLSITEARCH) $(INSTALLVENDORARCH)' : '$(INSTALLPRIVLIB) $(INSTALLSITELIB) $(INSTALLVENDORLIB)' ; # set prefix $postamble .= "alien_prefix : _alien/mm/prefix\n\n" . "_alien/mm/prefix :\n" . "\t\$(FULLPERL) -MAlien::Build::MM=cmd -e prefix \$(INSTALLDIRS) $dirs\n\n"; # set verson $postamble .= "alien_version : _alien/mm/version\n\n" . "_alien/mm/version : _alien/mm/prefix\n" . "\t\$(FULLPERL) -MAlien::Build::MM=cmd -e version \$(VERSION)\n\n"; # download $postamble .= "alien_download : _alien/mm/download\n\n" . "_alien/mm/download : _alien/mm/prefix _alien/mm/version\n" . "\t\$(FULLPERL) -MAlien::Build::MM=cmd -e download\n\n"; # build $postamble .= "alien_build : _alien/mm/build\n\n" . "_alien/mm/build : _alien/mm/download\n" . "\t\$(FULLPERL) -MAlien::Build::MM=cmd -e build\n\n"; # append to all $postamble .= "pure_all :: _alien/mm/build\n\n"; $postamble .= "subdirs-test_dynamic subdirs-test_static subdirs-test :: alien_test\n\n"; $postamble .= "alien_test :\n" . "\t\$(FULLPERL) -MAlien::Build::MM=cmd -e test\n\n"; # prop $postamble .= "alien_prop :\n" . "\t\$(FULLPERL) -MAlien::Build::MM=cmd -e dumpprop\n\n"; $postamble .= "alien_prop_meta :\n" . "\t\$(FULLPERL) -MAlien::Build::MM=cmd -e dumpprop meta\n\n"; $postamble .= "alien_prop_install :\n" . "\t\$(FULLPERL) -MAlien::Build::MM=cmd -e dumpprop install\n\n"; $postamble .= "alien_prop_runtime :\n" . "\t\$(FULLPERL) -MAlien::Build::MM=cmd -e dumpprop runtime\n\n"; # install $postamble .= "alien_clean_install : _alien/mm/prefix\n" . "\t\$(FULLPERL) -MAlien::Build::MM=cmd -e clean_install\n\n"; $postamble; } sub mm_install { # NOTE: older versions of the Alien::Build::MM documentation # didn't include this method, so anything that this method # does has to be optional my($self, $mm, @rest) = @_; my $section = do { package MY; $mm->SUPER::install(@rest); }; return ".NOTPARALLEL : \n\n" . ".NO_PARALLEL : \n\n" . "install :: alien_clean_install\n\n" . $section; } sub import { my(undef, @args) = @_; foreach my $arg (@args) { if($arg eq 'cmd') { package main; *_args = sub { my $build = Alien::Build->resume('alienfile', '_alien'); $build->load_requires('configure'); $build->load_requires($build->install_type); ($build, @ARGV) }; *_touch = sub { my($name) = @_; my $path = Path::Tiny->new("_alien/mm/$name"); $path->parent->mkpath; $path->touch; }; *prefix = sub { my($build, $type, $perl, $site, $vendor) = _args(); my $distname = $build->install_prop->{mm}->{distname}; my $prefix = $type eq 'perl' ? $perl : $type eq 'site' ? $site : $type eq 'vendor' ? $vendor : die "unknown INSTALLDIRS ($type)"; $prefix = Path::Tiny->new($prefix)->child("auto/share/dist/$distname")->absolute->stringify; $build->log("prefix $prefix"); $build->set_prefix($prefix); $build->checkpoint; _touch('prefix'); }; *version = sub { my($build, $version) = _args(); $build->runtime_prop->{perl_module_version} = $version; $build->checkpoint; _touch('version'); }; *download = sub { my($build) = _args(); $build->download; $build->checkpoint; _touch('download'); }; *build = sub { my($build) = _args(); $build->build; my $distname = $build->install_prop->{mm}->{distname}; if($build->meta_prop->{arch}) { my $archdir = Path::Tiny->new("blib/arch/auto/@{[ join '/', split /-/, $distname ]}"); $archdir->mkpath; my $archfile = $archdir->child($archdir->basename . '.txt'); $archfile->spew('Alien based distribution with architecture specific file in share'); } my $cflags = $build->runtime_prop->{cflags}; my $libs = $build->runtime_prop->{libs}; if(($cflags && $cflags !~ /^\s*$/) || ($libs && $libs !~ /^\s*$/)) { my $mod = join '::', split /-/, $distname; my $install_files_pm = Path::Tiny->new("blib/lib/@{[ join '/', split /-/, $distname ]}/Install/Files.pm"); $install_files_pm->parent->mkpath; $install_files_pm->spew( "package ${mod}::Install::Files;\n", "use strict;\n", "use warnings;\n", "require ${mod};\n", "sub Inline { shift; ${mod}->Inline(\@_) }\n", "1;\n", "\n", "=begin Pod::Coverage\n", "\n", " Inline\n", "\n", "=cut\n", ); } $build->checkpoint; _touch('build'); }; *test = sub { my($build) = _args(); $build->test; $build->checkpoint; }; *clean_install = sub { my($build) = _args(); $build->clean_install; $build->checkpoint; }; *dumpprop = sub { my($build, $type) = _args(); my %h = ( meta => $build->meta_prop, install => $build->install_prop, runtime => $build->runtime_prop, ); require Alien::Build::Util; print Alien::Build::Util::_dump($type ? $h{$type} : \%h); } } } } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::MM - Alien::Build installer code for ExtUtils::MakeMaker =head1 VERSION version 2.74 =head1 SYNOPSIS In your C: use ExtUtils::MakeMaker; use Alien::Build::MM; my $abmm = Alien::Build::MM->new; WriteMakefile($abmm->mm_args( ABSTRACT => 'Discover or download and install libfoo', DISTNAME => 'Alien-Libfoo', NAME => 'Alien::Libfoo', VERSION_FROM => 'lib/Alien/Libfoo.pm', ... )); sub MY::postamble { $abmm->mm_postamble(@_); } sub MY::install { $abmm->mm_install(@_); } In your C: package Alien::Libfoo; use parent qw( Alien::Base ); 1; In your alienfile (needs to be named C and should be in the root of your dist): use alienfile; plugin 'PkgConfig' => 'libfoo'; share { start_url 'http://libfoo.org'; ... }; =head1 DESCRIPTION This class allows you to use Alien::Build and Alien::Base with L. It load the L recipe in the root of your L dist, updates the prereqs passed into C if any are specified by your L or its plugins, and adds a postamble to the C that will download/build/test the alienized package as appropriate. The L must be named C. If you are using L to author your L dist, you should consider using the L plugin. I personally don't recommend it, but if you want to use L instead, you can use L. =head1 CONSTRUCTOR =head2 new my $abmm = Alien::Build::MM->new; Create a new instance of L. =head1 PROPERTIES =head2 build my $build = $abmm->build; The L instance. =head2 alienfile_meta my $bool = $abmm->alienfile_meta Set to a false value, in order to turn off the x_alienfile meta =head2 clean_install my $bool = $abmm->clean_install; Set to a true value, in order to clean the share directory prior to installing. If you use this you have to make sure that you install the install handler in your C: $abmm = Alien::Build::MM->new( clean_install => 1, ); ... sub MY::install { $abmm->mm_install(@_); } =head1 METHODS =head2 mm_args my %args = $abmm->mm_args(%args); Adjust the arguments passed into C as needed by L. =head2 mm_postamble my $postamble $abmm->mm_postamble; my $postamble $abmm->mm_postamble($mm); Returns the postamble for the C needed for L. This adds the following C targets which are normally called when you run C, but can be run individually if needed for debugging. =over 4 =item alien_prefix Determines the final install prefix (C<%{.install.prefix}>). =item alien_version Determine the perl_module_version (C<%{.runtime.perl_module_version}>) =item alien_download Downloads the source from the internet. Does nothing for a system install. =item alien_build Build from source (if a share install). Gather configuration (for either system or share install). =item alien_prop, alien_prop_meta, alien_prop_install, alien_prop_runtime Prints the meta, install and runtime properties for the Alien. =item alien_realclean, alien_clean Removes the alien specific files. These targets are executed when you call the C and C targets respectively. =item alien_clean_install Cleans out the Alien's share directory. Caution should be used in invoking this target directly, as if you do not understand what you are doing you are likely to break your already installed Alien. =back =head2 mm_install sub MY::install { $abmm->mm_install(@_); } B Adds an install rule to clean the final install dist directory prior to installing. =head1 SEE ALSO L, L, L, L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Log/Abbreviate.pm000044400000005074152346246300010737 0ustar00package Alien::Build::Log::Abbreviate; use strict; use warnings; use 5.008004; use Term::ANSIColor (); use Path::Tiny qw( path ); use File::chdir; use parent qw( Alien::Build::Log ); # ABSTRACT: Log class for Alien::Build which is less verbose our $VERSION = '2.74'; # VERSION sub _colored { my($code, @out) = @_; -t STDOUT ? Term::ANSIColor::colored($code, @out) : @out; } my $root = path("$CWD"); sub log { my(undef, %args) = @_; my($message) = $args{message}; my ($package, $filename, $line) = @{ $args{caller} }; my $source = $package; $source =~ s/^Alien::Build::Auto::[^:]+::Alienfile/alienfile/; my $expected = $package; $expected .= '.pm' unless $package eq 'alienfile'; $expected =~ s/::/\//g; if($filename !~ /\Q$expected\E$/) { $source = path($filename)->relative($root); } else { $source =~ s/^Alien::Build::Plugin/ABP/; $source =~ s/^Alien::Build/AB/; } print _colored([ "bold on_black" ], '['); print _colored([ "bright_green on_black" ], $source); print _colored([ "on_black" ], ' '); print _colored([ "bright_yellow on_black" ], $line); print _colored([ "bold on_black" ], ']'); print _colored([ "white on_black" ], ' ', $message); print "\n"; } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Log::Abbreviate - Log class for Alien::Build which is less verbose =head1 VERSION version 2.74 =head1 SYNOPSIS =head1 DESCRIPTION =head1 METHODS =head2 log $log->log(%opts); Send single log line to stdout. =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Log/Default.pm000044400000004015152346246300010251 0ustar00package Alien::Build::Log::Default; use strict; use warnings; use 5.008004; use parent qw( Alien::Build::Log ); # ABSTRACT: Default Alien::Build log class our $VERSION = '2.74'; # VERSION sub log { my(undef, %args) = @_; my($message) = $args{message}; my ($package, $filename, $line) = @{ $args{caller} }; print "$package> $message\n"; } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Log::Default - Default Alien::Build log class =head1 VERSION version 2.74 =head1 SYNOPSIS Alien::Build->log("message1"); $build->log("message2"); =head1 DESCRIPTION This is the default log class for L. It does the sensible thing of sending the message to stdout, along with the class that made the log call. For more details about logging with L, see L. =head1 METHODS =head2 log $log->log(%opts); Send single log line to stdout. =head1 SEE ALSO =over 4 =item L =item L =back =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Interpolate/Default.pm000044400000020202152346246300012012 0ustar00package Alien::Build::Interpolate::Default; use strict; use warnings; use 5.008004; use parent qw( Alien::Build::Interpolate ); use File::chdir; use File::Which qw( which ); use Capture::Tiny qw( capture ); # ABSTRACT: Default interpolator for Alien::Build our $VERSION = '2.74'; # VERSION sub _config { $Config::Config{$_[0]}; } sub new { my($class) = @_; my $self = $class->SUPER::new(@_); $self->add_helper( ar => sub { _config 'ar' }, 'Config' ); $self->add_helper( bison => undef, sub { my $helper = shift; if(which 'bison') { $helper->code(sub { 'bison' }); return (); } else { return 'Alien::bison' => '0.17'; } }); $self->add_helper( bzip2 => undef, sub { my $helper = shift; if(which 'bzip2') { $helper->code( sub { 'bzip2' }); return (); } else { return 'Alien::Libbz2' => '0.04'; } }); $self->add_helper( cc => sub { _config 'cc' }, 'Config' ); $self->add_helper( cmake => sub { 'cmake' }, sub { if(which 'cmake') { return (); } else { return 'Alien::CMake' => '0.07'; } }); $self->add_helper( cp => sub { _config 'cp' }, 'Config' ); $self->add_helper( devnull => sub { $^O eq 'MSWin32' ? 'NUL' : '/dev/null' }); $self->add_helper( flex => undef, sub { my $helper = shift; if(which 'flex') { $helper->code(sub { 'flex' }); return (); } else { return 'Alien::flex' => '0.08'; } }); $self->add_helper( gmake => undef, 'Alien::gmake' => '0.11' ); $self->add_helper( install => sub { 'install' }); $self->add_helper( ld => sub { _config 'ld' }, 'Config' ); $self->add_helper( m4 => undef, 'Alien::m4' => '0.08' ); if($^O eq 'MSWin32') { # TL;DR: dmake is bad, and shouldn't be used to build anything but older # versions of Windows Perl that don't support gmake. my $perl_make = _config 'make'; my $my_make; $self->add_helper( make => sub { return $my_make if defined $my_make; if( $perl_make ne 'dmake' && which $perl_make ) { # assume if it is called nmake or gmake that it really is what it # says it is. if( $perl_make eq 'nmake' || $perl_make eq 'gmake' ) { return $my_make = $perl_make; } my $out = capture { system $perl_make, '--version' }; if( $out =~ /GNU make/i || $out =~ /Microsoft \(R\) Program Maintenance/ ) { return $my_make = $perl_make; } } # if we see something that looks like it might be gmake, use that. foreach my $try (qw( gmake mingw32-make )) { return $my_make = $try if which $try; } if( which 'make' ) { my $out = capture { system 'make', '--version' }; if( $out =~ /GNU make/i || $out =~ /Microsoft \(R\) Program Maintenance/ ) { return $my_make = 'make'; } } # if we see something that looks like it might be nmake, use that. foreach my $try (qw( nmake )) { return $my_make = $try if which $try; } $my_make = $perl_make; }); } else { $self->add_helper( make => sub { _config 'make' }, 'Config' ); } $self->add_helper( mkdir_deep => sub { $^O eq 'MSWin32' ? 'md' : 'mkdir -p'}, 'Alien::Build' => '1.04' ); $self->add_helper( make_path => sub { $^O eq 'MSWin32' ? 'md' : 'mkdir -p'}, 'Alien::Build' => '1.05' ); $self->add_helper( nasm => undef, sub { my $helper = shift; if(which 'nasm') { $helper->code(sub { 'nasm' }); return (); } else { return 'Alien::nasm' => '0.11'; } }); $self->add_helper( patch => undef, sub { my $helper = shift; if(which 'patch') { if($^O eq 'MSWin32') { $helper->code(sub { 'patch --binary' }); } else { $helper->code(sub { 'patch' }); } return (); } else { return 'Alien::patch' => '0.09'; } }); $self->add_helper( perl => sub { my $perl = Devel::FindPerl::find_perl_interpreter(); $perl =~ s{\\}{/}g if $^O eq 'MSWin32'; $perl; }, 'Devel::FindPerl' ); $self->add_helper( pkgconf => undef, 'Alien::pkgconf' => 0.06 ); $self->add_helper( cwd => sub { my $cwd = "$CWD"; $cwd =~ s{\\}{/}g if $^O eq 'MSWin32'; $cwd; } ); $self->add_helper( sh => sub { 'sh' }, 'Alien::MSYS' => '0.07' ); $self->add_helper( rm => sub { _config 'rm' }, 'Config' ); $self->add_helper( xz => undef, sub { my $helper = shift; if(which 'xz') { $helper->code(sub { 'xz' }); return (); } else { return 'Alien::xz' => '0.02'; } }); $self; } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Interpolate::Default - Default interpolator for Alien::Build =head1 VERSION version 2.74 =head1 CONSTRUCTOR =head2 new my $intr = Alien::Build::Interpolate::Default->new; =head1 HELPERS =head2 ar %{ar} The ar command. =head2 bison %{bison} Requires: L 0.17 if not already in C. =head2 bzip2 %{bzip2} Requires: L 0.04 if not already in C. =head2 cc %{cc} The C Compiler used to build Perl =head2 cmake %{cmake} Requires: L 0.07 if cmake is not already in C. Deprecated: Use the L plugin instead (which will replace this helper with one that works with L that works better). =head2 cp %{cp} The copy command. =head2 devnull %{devnull} The null device, if available. On Unix style operating systems this will be C on Windows it is C. =head2 flex %{flex} Requires: L 0.08 if not already in C. =head2 gmake %{gmake} Requires: L 0.11 Deprecated: use L instead. =head2 install %{install} The Unix C command. Not normally available on Windows. =head2 ld %{ld} The linker used to build Perl =head2 m4 %{m4} Requires: L 0.08 L should pull in a version of C that will work with Autotools. =head2 make %{make} Make. On Unix this will be the same make used by Perl. On Windows this will be C or C if those are available, and only C if the first two are not available. =head2 make_path %{make_path} Make directory, including all parent directories as needed. This is usually C on Unix and simply C on windows. =head2 nasm %{nasm} Requires: L 0.11 if not already in the C. =head2 patch %{patch} Requires: L 0.09 if not already in the C. On Windows this will normally render C, which makes patch work like it does on Unix. =head2 perl %{perl} Requires: L =head2 pkgconf %{pkgconf} Requires: L 0.06. =head2 cwd %{cwd} =head2 sh %{sh} Unix style command interpreter (/bin/sh). Deprecated: use the L plugin instead. =head2 rm %{rm} The remove command =head2 xz %{xz} Requires: L 0.02 if not already in the C. =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/rc.pm000044400000005517152346246300006560 0ustar00package Alien::Build::rc; use strict; use warnings; use 5.008004; # ABSTRACT: Alien::Build local config our $VERSION = '2.74'; # VERSION sub logx ($) { unshift @_, 'Alien::Build'; goto &Alien::Build::log; } sub preload_plugin { my(@args) = @_; push @Alien::Build::rc::PRELOAD, sub { shift->apply_plugin(@args); }; } sub postload_plugin { my(@args) = @_; push @Alien::Build::rc::POSTLOAD, sub { shift->apply_plugin(@args); }; } sub preload ($) { push @Alien::Build::rc::PRELOAD, $_[0]; } sub postload ($) { push @Alien::Build::rc::POSTLOAD, $_[0]; } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::rc - Alien::Build local config =head1 VERSION version 2.74 =head1 SYNOPSIS in your C<~/.alienbuild/rc.pl>: preload 'Foo::Bar'; postload 'Baz::Frooble'; =head1 DESCRIPTION L will load your C<~/.alienbuild/rc.pl> file, if it exists before running the L recipe. This allows you to alter the behavior of L based Ls if you have local configuration requirements. For example you can prompt before downloading remote content or fetch from a local mirror. =head1 FUNCTIONS =head2 logx log $message; Send a message to the L log. =head2 preload_plugin preload_plugin $plugin, @args; Preload the given plugin, with arguments. =head2 postload_plugin postload_plugin $plugin, @args; Postload the given plugin, with arguments. =head2 preload [deprecated] preload $plugin; Preload the given plugin. =head2 postload [deprecated] postload $plugin; Postload the given plugin. =head1 SEE ALSO =over 4 =item L =item L =item L =item L =back =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Manual/Alien.pod000044400000005527152346246300010570 0ustar00# PODNAME: Alien::Build::Manual::Alien # ABSTRACT: General alien author documentation # VERSION __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Manual::Alien - General alien author documentation =head1 VERSION version 2.74 =head1 SYNOPSIS perldoc Alien::Build::Manual::Alien =head1 DESCRIPTION The goal of the L namespace is to provide non-CPAN dependencies (so called "Alien" dependencies) for CPAN modules. The history and intent of this idea is documented in the documentation-only L module. The C distribution provides a framework for building aliens. The intent is to fix bugs and enhance the interface of a number of common tools so that all aliens may benefit. The distribution is broken up into these parts: =over 4 =item The Alien Installer (configure / build-time) L and L are used to detect and install aliens. They are further documented in L. =item The Alien Runtime (runtime) L is the base class for aliens in the C system. Its use by Alien consumers is documented in L. =item The Plugin system (configure / build-time) Because many packages are implemented using different tools, the detection, build and install logic for a particular L can vary a lot. As such, much of L is implemented as a series of plugins that inherit from L. An overview of building your own plugins is documented in L. =back Additional useful documentation may be found here: =over 4 =item FAQ L =item Contributing L =back =head1 SEE ALSO =over 4 =item L Other L manuals. =back =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Manual/Security.pod000044400000021323152346246300011337 0ustar00# PODNAME: Alien::Build::Manual::Security # ABSTRACT: General alien author documentation # VERSION __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Manual::Security - General alien author documentation =head1 VERSION version 2.74 =head1 SYNOPSIS perldoc Alien::Build::Manual::Security =head1 DESCRIPTION You are rightly concerned that an L might be downloading something random off the internet. This manual will describe some of the real risks and go over how you can mitigate them. =head2 no warranty L provides L authors with tools to add external non-Perl dependencies to CPAN modules. It is open source software that is entirely volunteer driven, meaning the people writing this software are not getting compensated monetarily for the work. As such, we do our best not to intentionally introduce security vulnerabilities into our modules, or their dependencies. But it is also not our responsibility either. If you are operating in an environment where you need absolute security, you need to carefully audit I of the software that you use. =head2 L vs. L I suppose you could argue that L based Ls and Ls in general are inherently less secure than the the Perl modules on L that don't download random stuff off the internet. Worse yet, Ls might be downloading from insecure sources like C or C. This argument falls apart pretty quickly when you realize that =over 4 =item 1 Perl modules from L are in fact random stuff off the internet. Most modules, when installed execute a C which can execute completely arbitrary Perl code. Without a proper audit or firewalls that L code could be making connections to insecure sources like C if they are not themselves doing something nefarious. =item 2 By default, the most frequently used L client L uses C to fetch L modules. So unless you have specifically configured it to connect to a secure source you are downloading even more random stuff than usual off the internet. =back The TL;DR is that if you are using a Perl module, whether it be C, C or C and you are concerned about security you need to audit all of your Perl modules, not just the L ones. =head2 Restricting L by environment Okay, granted you need to audit software for security regardless of if it is L, you still don't like the idea of downloading external dependencies and you can't firewall just the L module installs. L based Ls respect a number of environment variables that at least give you some control over how aggresive L will be at fetching random stuff off the internet. =over 4 =item C This environment variable configures how L will deal with insecure protocols and files that do not include a cryptographic signature. Part of the design of the L system is that it typically tries to download the latest version of a package instead of a fixed version, so that the L doesn't need to be updated when a new alienized package is released. This means that we frequently have to rely on TLS or bundled alienized packages to ensure that the alienized package is fetched securely. Recently (as of L 2.59) we started supporting cryptographic signatures defined in Ls, but they are not yet very common, and they only really work when a single alienized package URL is hard coded into the L instead of the more typical mode of operation where the latest version is downloaded. =over 4 =item warn This mode will warn you if an L based L attempts to fetch a alienized package insecurely. It will also warn you if a package doesn't have a cryptographic signature. Neither of these things wild stop the L from being installed. This is unfortunately currently the default mode of L, for historical reasons. Once plugins and Ls are updated to either use secure fetch (TLS or bundled alienized packages), or cryptographic signatures, the default will be changed to C. =item digest_or_encrypt This mode will require that before an alienized package is extracted that it is either fetched via a secure protocol (C or C), or the package matches a cryptographic signature. This will likely be the default for L in the near future, but it doesn't hurt to set it now, if you don't mind submitting tickets to Ls or L that don't support this mode yet. =back =item C By design Ls should use local installs of libraries and tools before downloading source from the internet. Setting this environment variable to false, will instruct L to not attempt to fetch the alienized package off the internet if it is not available locally or as a bundled package. This is similar to setting C to C (see below), except it does allow Ls that bundle their alienized package inside the L package tarball. Some Ls will not install properly at first, but when they error you can install the system package and try to re-install the L. =item C Setting C to C is similar to setting C to false, except that bundled alienized packages will also be rejected. This environment variable is really intended for use by operating system vendors packaging Ls, or for L developer testing (in CI for example). For some who want to restrict how Ls install this might be the right tool to reach for. =back Note that this is definitely best effort. If the L author makes a mistake or is malicious they could override these environment variables inside the C, so you still need to audit any software to ensure that it doesn't fetch source off the internet. =head2 Security Related Plugins There are a number of plugins that give the user or installer control over how L behaves, and may be useful for rudimentary security. =over 4 =item L This plugin will prompt before fetching any remote files. This only really works when you are installing Ls interactively. =item L This plugin will only allow fetching from hosts that are in an allow list. =item L This plugin will not allow fetching from hosts that are in a block list. =item L This plugin can re-write fetched URLs before the request is made. This can be useful if you have a local mirror of certain sources that you want to use instead of fetching from the wider internet. =item L This plugin can override the C on a perl-Alien basis. This can be useful if you want to install some Ls in C mode, but generally want to enforce C mode. =back =head2 local configuration You can configure the way L based Ls are installed with the local configuration file C<~/.alienbuild/rc.pl>. See L for details. =head1 CAVEATS This whole document is caveats, but if you haven't gotten it by now then, fundamentally if you need to use Perl modules securely then you need to audit the code for security vulnerabilities. If you think that the security of L and the Ls that depend on it, then I. =head1 SEE ALSO =over 4 =item L Other L manuals. =back =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Manual/FAQ.pod000044400000050162152346246300010142 0ustar00# PODNAME: Alien::Build::Manual::FAQ # ABSTRACT: Frequently Asked Questions about Alien::Build # VERSION __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Manual::FAQ - Frequently Asked Questions about Alien::Build =head1 VERSION version 2.74 =head1 SYNOPSIS perldoc Alien::Build::Manual::FAQ =head1 DESCRIPTION This document serves to answer the most frequently asked questions made by developers creating L modules using L. =head1 QUESTIONS =head2 What is Alien, Alien::Base and Alien::Build? Alien in a Perl namespace for defining dependencies in CPAN for libraries and tools which are not "native" to CPAN. For a manifesto style description of the Why, and How see L. L is a base class for the L runtime. L is a tool for probing the operating system for existing libraries and tools, and downloading, building and installing packages. L is a recipe format for describing how to probe, download, build and install a package. =head2 How do I build a package that uses I =head3 autoconf Use the autoconf plugin (L). If your package provides a pkg-config C<.pc> file, then you can also use the PkgConfig plugin (L). use alienfile plugin PkgConfig => 'libfoo'; share { start_url => 'http://example.org/dist'; plugin Download => ( version => qr/libfoo-([0-9\.])\.tar\.gz$/, ); plugin Extract => 'tar.gz'; plugin 'Build::Autoconf'; }; If you need to provide custom flags to configure, you can do that too: share { plugin 'Build::Autoconf'; build [ '%{configure} --disable-shared --enable-foo', '%{make}', '%{make} install', ]; }; If your package requires GNU Make, use C<%{gmake}> instead of C<%{make}>. =head3 autoconf without configure script A number of Open Source projects are using autotools, but do not provide the C script. When alienizing these types of packages you have a few choices: =over 4 =item build configure using autotools The Alien L is designed to provide autotools for building such packages from source. The advantage is that this is how the upstream developers intend on having their package built. The downside is that it is also adds more prereqs to your Alien. The silver lining is that if you require this Alien in the C block (as you should), then these prereqs will only be pulled in during a share install when they are needed. Please see the L documentation for specifics on how it can be used in your L. =item patch the package locally before build You can use the L directive to patch the alienized package locally before building. This can sometimes be challenging because Autotools uses timestamps in order to decide what needs to be rebuilt, and patching can sometimes confuse it into thinking more needs to be rebuilt than what actually does. =item build configure and tarball You can also build the configure script during development of your alien, generate the tarball and provide it somewhere like GitHub and use that as the source instead of the original source. This should usually be a last resort if the other two methods prove too difficult. =back =head3 autoconf-like If you see an error like this: Unknown option "--with-pic". It is because the autoconf plugin uses the C<--with-pic> option by default, since it makes sense most of the time, and autoconf usually ignores options that it does not recognize. Some autoconf style build systems fail when they see an option that they do not recognize. You can turn this behavior off for these packages: plugin 'Build::Autoconf' => ( with_pic => 0, ); Another thing about the autoconf plugin is that it uses C to do a double staged install. If you see an error like "nothing was installed into destdir", that means that your package does not support C. You should instead use the MSYS plugin and use a command sequence to do the build like this: share { plugin 'Build::MSYS'; build [ # explicitly running configure with "sh" will make sure that # it works on windows as well as UNIX. 'sh configure --prefix=%{.install.prefix} --disable-shared', '%{make}', '%{make} install', ]; }; =head3 CMake There is an alien L that provides C 3.x or better (It is preferred to the older L). Though it is recommended that you use the C (L) plugin instead of using L. use alienfile; share { plugin 'Build::CMake'; build [ # this is the default build step, if you do not specify one. [ '%{cmake}', @{ meta->prop->{plugin_build_cmake}->{args} }, # ... put extra cmake args here ... '.' ], '%{make}', '%{make} install', ]; }; =head3 vanilla Makefiles L provides a helper (C<%{make}>) for the C that is used by Perl and L (EUMM). Unfortunately the C supported by Perl and EUMM on Windows (C and C) are not widely supported by most open source projects. (Thankfully recent perls and EUMM support GNU Make on windows now). You can use the C plugin (L) to tell the L system which make the project that you are alienizing requires. plugin 'Build::Make' => 'umake'; # umake makes %{make} either GNU Make or BSD Make on Unix and GNU Make on Windows. build { build [ # You can use the Perl config compiler and cflags using the %{perl.config...} helper [ '%{make}', 'CC=%{perl.config.cc}', 'CFLAGS=%{perl.config.cccdlflags} %{perl.config.optimize}' ], [ '%{make}', 'install', 'PREFIX=%{.install.prefix}' ], ], }; Some open source projects require GNU Make, and you can specify that, and L will be pulled in on platforms that do not already have it. plugin 'Build::Make' => 'gmake'; ... =head2 How do I probe for a package that uses pkg-config? Use the C plugin (L): use alienfile; plugin 'PkgConfig' => ( pkg_name => 'libfoo', ); It will probe for a system version of the library. It will also add the appropriate C C and C properties on either a C or C install. =head2 How do I specify a minimum or exact version requirement for packages that use pkg-config? The various pkg-config plugins all support atleast_version, exact_version and maximum_version fields, which have the same meaning as the C command line interface: use alienfile; plugin 'PkgConfig', pkg_name => 'foo', atleast_version => '1.2.3'; or use alienfile; plugin 'PkgConfig', pkg_name => foo, exact_version => '1.2.3'; =head2 How do I probe for a package that uses multiple .pc files? Each of the C plugins will take an array reference instead of a string: use alienfile; plugin 'PkgConfig' => ( pkg_name => [ 'foo', 'bar', 'baz' ] ); The first C given will be used by default once your alien is installed. To get the configuration for C and C you can use the L: use Alien::libfoo; $cflags = Alien::libfoo->cflags; # compiler flags for 'foo' $cflags = Alien::libfoo->alt('bar')->cflags ; # compiler flags for 'bar' $cflags = Alien::libfoo->alt('baz')->cflags ; # compiler flags for 'baz' =head2 How to create an Alien module for packages that do not support pkg-config? =head3 Packages that provide a configuration script Many packages provide a command that you can use to get the appropriate version, compiler and linker flags. For those packages you can just use the commands in your L. Something like this: use alienfile; probe [ 'foo-config --version' ]; share { ... build [ '%{make} PREFIX=%{.runtime.prefix}', '%{make} install PREFIX=%{.runtime.prefix}', ]; }; gather [ [ 'foo-config', '--version', \'%{.runtime.version}' ], [ 'foo-config', '--cflags', \'%{.runtime.cflags}' ], [ 'foo-config', '--libs', \'%{.runtime.libs}' ], ]; =head3 Packages that require a compile test Some packages just expect you do know that C<-lfoo> will work. For those you can use the C plugin (L). use alienfile; plugin 'Probe::CBuilder' => ( cflags => '-I/opt/libfoo/include', libs => '-L/opt/libfoo/lib -lfoo', ); share { ... gather sub { my($build) = @_; my $prefix = $build->runtime_prop->{prefix}; $build->runtime_prop->{cflags} = "-I$prefix/include "; $build->runtime_prop->{libs} = "-L$prefix/lib -lfoo "; }; } This plugin will build a small program with these flags and test that it works. (There are also options to provide a program that can make simple tests to ensure the library works). If the probe works, it will set the compiler and linker flags. (There are also options for extracting the version from the test program). If you do a share install you will need to set the compiler and linker flags yourself in the gather step, if you aren't using a build plugin that will do that for you. =head2 Can/Should I write a tool oriented Alien module? Certainly. The original intent was to provide libraries, but tools are also quite doable using the L toolset. A good example of how to do this is L. You will want to use the 'Probe::CommandLine': use alienfile; plugin 'Probe::CommandLine' => ( command => 'gzip', ); =head2 How do I test my package once it is built (before it is installed)? Use L. It has extensive documentation, and integrates nicely with L. =head2 How do I patch packages that need alterations? If you have a diff file you can use patch: use alienfile; probe sub { 'share' }; # replace with appropriate probe share { ... patch [ '%{patch} -p1 < %{.install.patch}/mypatch.diff' ]; build [ ... ] ; } ... You can also patch using Perl if that is easier: use alienfile; probe sub { 'share' }; share { ... patch sub { my($build) = @_; # make changes to source prior to build }; build [ ... ]; }; =head2 The flags that a plugin produces are wrong! Sometimes, the compiler or linker flags that the PkgConfig plugin comes up with are not quite right. (Frequently this is actually because a package maintainer is providing a broken C<.pc> file). (Other plugins may also have problems). You could replace the plugin's C step but a better way is to provide a subroutine callback to be called after the gather stage is complete. You can do this with the L C directive: use alienfile; plugin 'PkgConfig' => 'libfoo'; share { ... after 'gather' => sub { my($build) = @_; $build->runtime_prop->{libs} .= " -lbar"; # libfoo also requires libbar $build->runtime_prop->{libs_static} .= " -lbar -lbaz"; # libfoo also requires libbaz under static linkage }; }; Sometimes you only need to do this on certain platforms. You can adjust the logic based on C<$^O> appropriately. use alienfile; plugin 'PkgConfig' => 'libfoo'; share { ... after 'gather' => sub { my($build) = @_; if($^O eq 'MSWin32') { $build->runtime_prop->{libs} .= " -lpsapi"; } }; }; =head2 "cannot open shared object file" trying to load XS The error looks something like this: t/acme_alien_dontpanic2.t ....... 1/? # Failed test 'xs' # at t/acme_alien_dontpanic2.t line 13. # XSLoader failed # Can't load '/home/cip/.cpanm/work/1581635869.456/Acme-Alien-DontPanic2-2.0401/_alien/tmp/test-alien-lyiQNX/auto/Test/Alien/XS/Mod0/Mod0.so' for module Test::Alien::XS::Mod0: libdontpanic.so.0: cannot open shared object file: No such file or directory at /opt/perl/5.30.1/lib/5.30.1/x86_64-linux/DynaLoader.pm line 193. # at /home/cip/perl5/lib/perl5/Test/Alien.pm line 414. # Compilation failed in require at /home/cip/perl5/lib/perl5/Test/Alien.pm line 414. # BEGIN failed--compilation aborted at /home/cip/perl5/lib/perl5/Test/Alien.pm line 414. t/acme_alien_dontpanic2.t ....... Dubious, test returned 1 (wstat 256, 0x100) Failed 1/6 subtests t/acme_alien_dontpanic2__ffi.t .. ok This error happened at test time for the Alien, but depending on your environment and Alien it might happen later and the actual diagnostic wording might vary. This is usually because your XS or Alien tries to use dynamic libraries instead of static ones. Please consult the section about dynamic vs. static libraries in L. The TL;DR is that L might help. If you are the Alien author and the package you are alienizing doesn't have a static option you can use L, but please note the extended set of caveats! =head2 599 Internal Exception errors downloading packages from the internet Alien::Build::Plugin::Fetch::HTTPTiny> 599 Internal Exception fetching http://dist.libuv.org/dist/v1.15.0 Alien::Build::Plugin::Fetch::HTTPTiny> exception: IO::Socket::SSL 1.42 must be installed for https support Alien::Build::Plugin::Fetch::HTTPTiny> exception: Net::SSLeay 1.49 must be installed for https support Alien::Build::Plugin::Fetch::HTTPTiny> An attempt at a SSL URL https was made, but your HTTP::Tiny does not appear to be able to use https. Alien::Build::Plugin::Fetch::HTTPTiny> Please see: https://metacpan.org/pod/Alien::Build::Manual::FAQ#599-Internal-Exception-errors-downloading-packages-from-the-internet error fetching http://dist.libuv.org/dist/v1.15.0: 599 Internal Exception at /Users/ollisg/.perlbrew/libs/perl-5.26.0@test1/lib/perl5/Alien/Build/Plugin/Fetch/HTTPTiny.pm line 68. (Older versions of L produced a less verbose more confusing version of this diagnostic). TL;DR, instead of this: share { start_url => 'http://example.org/dist'; ... }; do this: share { start_url => 'https://example.org/dist'; }; If the website is going to redirect to a secure URL anyway. The "599 Internal Exception" indicates an "internal" exception from L and is not a real HTTP status code or error. This could mean a number of different problems, but most frequently indicates that a SSL request was made without the required modules (L and L). Normally the L and L will make sure that the appropriate modules are added to your prerequisites for you if you specify a C URL. Some websites allow an initial request from C but then redirect to C. If you can it is better to specify C, if you cannot, then you can instead use the C property on either of those two plugins. =head2 Network fetch is turned off If you get an error like this: Alien::Build> install type share requested or detected, but network fetch is turned off Alien::Build> see see https://metacpan.org/pod/Alien::Build::Manual::FAQ#Network-fetch-is-turned-off This is because your environment is setup not to install aliens that require the network. You can turn network fetch back on by setting C to true, or by unsetting it. This environment variable is designed for environments that don't ever want to install aliens that require downloading source packages over the internet. =head2 I would really prefer you not download stuff off the internet The idea of L is to download missing packages and build them automatically to make installing easier. Some people may not like this, or may even have security requirements that they not download random package over the internet (caveat, downloading random stuff off of CPAN may not be any safer, so make sure you audit all of the open source software that you use appropriately). Another reason you may not want to download from the internet is if you are packaging up an alien for an operating system vendor, which will always want to use the system version of a library. In that situation you don't want L to go off and download something from the internet because the probe failed for some reason. This is easy to take care of, simply set C to C and a build from source code will never be attempted. On systems that do not provide system versions of the library or tool you will get an error, allowing you to install the library, and retry the alien install. You can also set the environment variable on just some aliens. % export ALIEN_INSTALL_TYPE=system # for everyone % env ALIEN_INSTALL_TYPE=system cpanm -v Alien::libfoo =head2 For testing I would like to test both system and share installs! You can use the C environment variable. It will force either a C or C install depending on how it is set. For travis you can do something like this: env: matrix: - ALIEN_INSTALL_TYPE=share - ALIEN_INSTALL_TYPE=system =head2 How do I use Alien::Build from Dist::Zilla? For creating L and L based dist from L you can use the dzil plugin L. =head2 Cannot find either a share directory or a ConfigData module If you see an error like this: Cannot find either a share directory or a ConfigData module for Alien::libfoo. (Alien::libfoo loaded from lib/Alien/libfoo.pm) Please see https://metacpan.org/pod/distribution/Alien-Build/lib/Alien/Build/Manual/FAQ.pod#Cannot-find-either-a-share-directory-or-a-ConfigData-module Can't locate Alien/libfoo/ConfigData.pm in @INC (you may need to install the Alien::libfoo::ConfigData module) (@INC contains: ...) it means you are trying to use an Alien that hasn't been properly installed. An L based Alien needs to have either the share directory build during the install process or for older legacy L based Aliens, a ConfigData module generated by L. This usually happens if you try to use an Alien module from the lib directory as part of the Alien's distribution. You need to build the alien and use C instead of C or install the alien and use the installed path. It is also possible that your Alien installer is not set up correctly. Make sure your C is using L correctly. =head2 I have a question not listed here! There are a number of forums available to people working on L, L and L modules: =over 4 =item C<#native> on irc.perl.org This is intended for native interfaces in general so is a good place for questions about L generally or L and L specifically. =item mailing list The C google group is intended for L issues generally, including L and L. L =item Open a support ticket If you have an issue with L itself, then please open a support ticket on the project's GitHub issue tracker. L =back =head1 SEE ALSO =over 4 =item L Other L manuals. =back =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Manual/AlienUser.pod000044400000015215152346246300011422 0ustar00# PODNAME: Alien::Build::Manual::AlienUser # ABSTRACT: Alien user documentation # VERSION __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Manual::AlienUser - Alien user documentation =head1 VERSION version 2.74 =head1 SYNOPSIS perldoc Alien::Build::Manual::AlienUser =head1 DESCRIPTION This document is intended for a user of an L based L module's user. Although specifically geared for L subclasses, it may have some useful hints for L in general. Full working examples of how to use an L module are also bundled with L in the distribution's C directory. Those examples use L, which uses L + L + L. The following documentation will assume you are trying to use an L called C which provides the library C and the command line tool C. Many Ls will only provide one or the other. The best interface to use for using L based aliens is L. This allows you to combine multiple aliens together and handles a number of corner obscure corner cases that using Ls directly does not. Also as of 0.64, L comes bundled with L and L anyway, so it is not an extra dependency. What follows are the main use cases. =head2 ExtUtils::MakeMaker use ExtUtils::MakeMaker; use Alien::Base::Wrapper (); WriteMakefile( Alien::Base::Wrapper->new('Alien::Foo')->mm_args2( NAME => 'FOO::XS', ... ), ); L will take a hash of C arguments and insert the appropriate compiler and linker flags for you. This is recommended over doing this yourself as the exact incantation to get EUMM to work is tricky to get right. The C method will also set your C for L, L and any aliens that you specify. =head2 Module::Build use Module::Build; use Alien::Base::Wrapper qw( Alien::Foo !export ); use Alien::Foo; my $build = Module::Build->new( ... configure_requires => { 'Alien::Base::Wrapper' => '0', 'Alien::Foo' => '0', ... }, Alien::Base::Wrapper->mb_args, ... ); $build->create_build_script; For L you can also use L, but you will have to specify the C yourself. =head2 Inline::C / Inline::CPP use Inline 0.56 with => 'Alien::Foo'; L and L can be configured to use an L based L with the C keyword. =head2 ExtUtils::Depends use ExtUtils::MakeMaker; use ExtUtils::Depends; my $pkg = ExtUtils::Depends->new("Alien::Foo"); WriteMakefile( ... $pkg->get_makefile_vars, ... ); L works similar to L, but uses the L interface under the covers. =head2 Dist::Zilla [@Filter] -bundle = @Basic -remove = MakeMaker [Prereqs / ConfigureRequires] Alien::Foo = 0 [MakeMaker::Awesome] header = use Alien::Base::Wrapper qw( Alien::Foo !export ); WriteMakefile_arg = Alien::Base::Wrapper->mm_args =head2 FFI::Platypus Requires C always: use FFI::Platypus; use Alien::Foo; my $ffi = FFI::Platypus->new( lib => [ Alien::Foo->dynamic_libs ], ); Use C in fallback mode: use FFI::Platypus; use FFI::CheckLib 0.28 qw( find_lib_or_die ); use Alien::Foo; my $ffi = FFI::Platypus->new( lib => [ find_lib_or_die lib => 'foo', alien => ['Alien::Foo'] ], ); If you are going to always require an L you can just call C and pass it into L' lib method. You should consider using L to use the L in fallback mode instead. This way you only need to install the L if the system doesn't provide it. For fallback mode to work correctly you need to be using L 0.28 or better. =head2 Inline::C use Inline with => 'Alien::Foo'; use Inline C => <<~'END'; #include const char *my_foo_wrapper() { foo(); } END sub exported_foo() { my_foo_wrapper(); } =head2 tool use Alien::Foo; use Env qw( @PATH ); unshift @PATH, Alien::Foo->bin_dir; system 'foo', '--bar', '--baz'; Some Ls provide tools instead of or in addition to a library. You need to add them to the C environment variable though. (Unless the tool is already provided by the system, in which case it is already in the path and the C method will return an empty list). =head1 ENVIRONMENT =over 4 =item ALIEN_INSTALL_TYPE Although the recommended way for a consumer to use an L based L is to declare it as a static configure and build-time dependency, some consumers may prefer to fallback on using an L only when the consumer itself cannot detect the necessary package. In some cases the consumer may want the user to opt-in to using an L before requiring it. To keep the interface consistent among Aliens, the consumer of the fallback opt-in L may fallback on the L if the environment variable C is set to any value. The rationale is that by setting this environment variable the user is aware that L modules may be installed and have indicated consent. The actual implementation of this, by its nature would have to be in the consuming CPAN module. This behavior should be documented in the consumer's POD. See L for more details on the usage of this environment variable. =back =head1 SEE ALSO =over 4 =item L Other L manuals. =back =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Manual/Contributing.pod000044400000021745152346246300012207 0ustar00# PODNAME: Alien::Build::Manual::Contributing # ABSTRACT: Over-detailed contributing guide # VERSION __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Manual::Contributing - Over-detailed contributing guide =head1 VERSION version 2.74 =head1 SYNOPSIS perldoc Alien::Build::Manual::Contributing =head1 DESCRIPTION Thank you for considering to contribute to my open source project! If you have a small patch please consider just submitting it. Doing so through the project GitHub is probably the best way: L If you have a more invasive enhancement or bugfix to contribute, please take the time to review these guidelines. In general it is good idea to work closely with the L developers, and the best way to contact them is on the C<#native> IRC channel on irc.perl.org. =head2 History Joel Berger wrote the original L. This distribution included the runtime code L and an installer class L. The significant thing about L was that it provided tools to make it relatively easy for people to roll their own L distributions. Over time, the PerlAlien (github organization) or "Alien::Base team" has taken over development of L with myself (Graham Ollis) being responsible for integration and releases. Joel Berger is still involved in the project. Since the original development of L, L, on which L is based, has been removed from the core of Perl. It seemed worthwhile to write a replacement installer that works with L which IS still bundled with the Perl core. Because this is a significant undertaking it is my intention to integrate the many lessons learned by Joel Berger, myself and the "Alien::Base team" as possible. If the interface seems good then it is because I've stolen the ideas from some pretty good places. =head2 Philosophy =head3 Alien runtime should be as config-only as possible. Ideally the code for an L based L should simply inherit from L, like so: package Alien::libfoo; use parent qw( Alien::Base ); 1; The detection logic should be done by the installer code (L and L) and saved into runtime properties (see L). And as much as possible the runtime should be implemented in the base class (L). Where reasonable, the base class should be expanded to meet the needs of this arrangement. =head3 when downloading a package grab the latest version If the maintainer of an L disappears for a while, and if the version downloaded during a "share" install is hardcoded in the L, it can be problematic for end-users. There are exceptions, of course, in particular when a package provides a very unstable interface from version to version it makes sense to hard code the version and for the Alien developer and Alien consumer developer to coordinate closely. =head3 when installing a package the operating system as a whole should not be affected The convenience of using an L is that a user of a CPAN module that consumes an L doesn't need to know the exact incantation to install the libraries on which it depends (or indeed it may not be easily installed through the package manager anyway). As a corollary, a user of a CPAN module that consumes an L module shouldn't expect operating system level packages to be installed, or for these packages to be installed in common system level directories, like C or C. Instead a "share" directory associated with the Perl install and L module should be used. Plugins that require user opt-in could be written to prompt a user to automatically install operating system packages, but this should never be done by default or without consent by the user. =head3 avoid dependencies One of the challenges with L development is that you are by the nature of the problem, trying to make everyone happy. Developers working out of CPAN just want stuff to work, and some build environments can be hostile in terms of tool availability, so for reliability you end up pulling a lot of dependencies. On the other hand, operating system vendors who are building Perl modules usually want to use the system version of a library so that they do not have to patch libraries in multiple places. Such vendors have to package any extra dependencies and having to do so for packages that the don't even use makes them understandably unhappy. As general policy the L core should have as few dependencies as possible, and should only pull extra dependencies if they are needed. Where dependencies cannot be avoidable, popular and reliable CPAN modules, which are already available as packages in the major Linux vendors (Debian, Red Hat) should be preferred. As such L is hyper aggressive at using dynamic prerequisites. =head3 interface agnostic One of the challenges with L was that L was pulled from the core. In addition, there is a degree of hostility toward L in some corners of the Perl community. I agree with Joel Berger's rationale for choosing L at the time, as I believe its interface more easily lends itself to building L distributions. That said, an important feature of L is that it is installer agnostic. Although it is initially designed to work with L, it has been designed from the ground up to work with any installer (Perl, or otherwise). As an extension of this, although L may have external CPAN dependencies, they should not be exposed to developers USING L. As an example, L is used heavily internally because it does what L does, plus the things that it doesn't, and uses forward slashes on Windows (backslashes are the "correct separator on windows, but actually using them tends to break everything). However, there aren't any interfaces in L that will return a L object (or if there are, then this is a bug). This means that if we ever need to port L to a platform that doesn't support L (such as VMS), then it may require some work to L itself, modules that USE L shouldn't need to be modified. =head3 plugable The actual logic that probes the system, downloads source and builds it should be as pluggable as possible. One of the challenges with L was that it was designed to work well with software that works with C and C. While you can build with other tools, you have to know a bit of how the installer logic works, and which hooks need to be tweaked. L has plugins for C, C (successor of C), vanilla Makefiles, and CMake. If your build system doesn't have a plugin, then all you have to do is write one! Plugins that prove their worth may be merged into the L core. Plugins that after a while feel like maybe not such a good idea may be removed from the core, or even from CPAN itself. In addition, L has a special type of plugin, called a negotiator which picks the best plugin for the particular environment that it is running in. This way, as development of the negotiator and plugins develop over time modules that use L will benefit, without having to change the way they interface with L =head1 ACKNOWLEDGEMENT I would like to that Joel Berger for getting things running in the first place. Also important to thank other members of the "Alien::Base team": Zaki Mughal (SIVOAIS) Ed J (ETJ, mohawk) Also kind thanks to all of the developers who have contributed to L over the years: L =head1 SEE ALSO =over 4 =item L Other L manuals. =back =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Manual/AlienAuthor.pod000044400000061152152346246300011747 0ustar00# PODNAME: Alien::Build::Manual::AlienAuthor # ABSTRACT: Alien author documentation # VERSION __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Manual::AlienAuthor - Alien author documentation =head1 VERSION version 2.74 =head1 SYNOPSIS perldoc Alien::Build::Manual::AlienAuthor =head1 DESCRIPTION B: Please read the entire document before you get started in writing your own L. The section on dynamic vs. static libraries will likely save you a lot of grief if you read it now! This document is intended to teach L authors how to build their own L distribution using L and L. Such an L distribution consists of three essential parts: =over 4 =item An L This is a recipe for how to 1) detect an already installed version of the library or tool you are alienizing 2) download and build the library or tool that you are alienizing and 3) gather the configuration settings necessary for the use of that library or tool. =item An installer C or C or a C if you are using L This is a thin layer between your L recipe, and the Perl installer (either L or L. =item A Perl class (.pm file) that inherits from L For most Ls this does not need to be customized at all, since L usually does what you need. =back For example if you were alienizing a library called libfoo, you might have these files: Alien-Libfoo-1.00/Makefile.PL Alien-Libfoo-1.00/alienfile Alien-Libfoo-1.00/lib/Alien/Libfoo.pm This document will focus mainly on instructing you how to construct an L, but we will also briefly cover making a simple C or C to go along with it. We will also touch on when you might want to extend your subclass to add non-standard functionality. =head2 Using commands Most software libraries and tools will come with instructions for how to install them in the form of commands that you are intended to type into a shell manually. The easiest way to automate those instructions is to just put the commands in your L. For example, lets suppose that libfoo is built using autoconf and provides a C C<.pc> file. We will also later discuss plugins. For common build systems like autoconf or CMake, it is usually better to use the appropriate plugin because they will handle corner cases better than a simple set of commands. We're going to take a look at commands first because it's easier to understand the different phases with commands. (Aside, autoconf is a series of tools and macros used to configure (usually) a C or C++ library or tool by generating any number of Makefiles. It is the C equivalent to L, if you will. Basically, if your library or tool instructions start with './configure' it is most likely an autoconf based library or tool). (Aside2, C is a standard-ish way to provide the compiler and linker flags needed for compiling and linking against the library. If your tool installs a C<.pc> file, usually in C<$PREFIX/lib/pkgconfig> then, your tool uses C). Here is the L that you might have: use alienfile; probe [ 'pkg-config --exists libfoo' ]; share { start_url 'http://www.libfoo.org/src/libfoo-1.00.tar.gz'; download [ 'wget %{.meta.start_url}' ]; extract [ 'tar zxf %{.install.download}' ]; build [ [ './configure --prefix=%{.install.prefix} --disable-shared' ], [ '%{make}' ], [ '%{make} install' ], ]; }; gather [ [ 'pkg-config --modversion libfoo', \'%{.runtime.version}' ], [ 'pkg-config --cflags libfoo', \'%{.runtime.cflags}' ], [ 'pkg-config --libs libfoo', \'%{.runtime.libs}' ], ]; There is a lot going on here, so lets decode it a little bit. An L is just some Perl with some alien specific sugar. The first line use alienfile; imports the sugar into the L. It also is a flag for the reader to see that this is an L and not some other kind of Perl script. The second line is the probe directive: probe [ 'pkg-config --exists libfoo' ]; is used to see if the library is already installed on the target system. If C is in the path, and if libfoo is installed, this should exit with a success (0) and tell L to use the system library. If either C in the PATH, or if libfoo is not installed, then it will exist with non-success (!= 0) and tells L to download and build from source. You can provide as many probe directives as you want. This is useful if there are different ways to probe for the system. L will stop on the first successfully found system library found. Say our library libfoo comes with a C<.pc> file for use with C and also provides a C program to find the same values. You could then specify this in your L probe [ 'pkg-config --exists libfoo' ]; probe [ 'foo-config --version' ]; Other directives can be specified multiple times if there are different methods that can be tried for the various steps. Sometimes it is easier to probe for a library from Perl rather than with a command. For that you can use a code reference. For example, another way to call C would be from Perl: probe sub { my($build) = @_; # $build is the Alien::Build instance. system 'pkg-config --exists libfoo'; $? == 0 ? 'system' : 'share'; }; The Perl code should return 'system' if the library is installed, and 'share' if not. (Other directives should return a true value on success, and a false value on failure). You can also throw an exception with C to indicate a failure. The next part of the L is the C block, which is used to group the directives which are used to download and install the library or tool in the event that it is not already installed. share { start_url 'http://www.libfoo.org/src/libfoo-1.00.tar.gz'; download [ 'wget %{.meta.start_url}' ]; extract [ 'tar zxf %{.install.download}' ]; build [ [ './configure --prefix=%{.install.prefix} --disable-shared' ], [ '%{make}' ], [ '%{make} install' ], ]; }; The start_url specifies where to find the package that you are alienizing. It should be either a tarball (or zip file, or what have you) or an HTML index. The download directive as you might imagine specifies how to download the library or tool. The extract directive specifies how to extract the archive once it is downloaded. In the extract step, you can use the variable C<%{.install.download}> as a placeholder for the archive that was downloaded in the download step. This is also accessible if you use a code reference from the L instance: share { ... requires 'Archive::Extract'; extract sub { my($build) = @_; my $tarball = $build->install_prop->{download}; my $ae = Archive::Extract->new( archive => $tarball ); $ae->extract; 1; } ... }; The build directive specifies how to build the library or tool once it has been downloaded and extracted. Note the special variable C<%{.install.prefix}> is the location where the library should be installed. C<%{make}> is a helper which will be replaced by the appropriate C, which may be called something different on some platforms (on Windows for example, it frequently may be called C or C). The final part of the L has a gather directive which specifies how to get the details on how to compile and link against the library. For this, once again we use the C command: gather [ [ 'pkg-config --modversion libfoo', \'%{.runtime.version}' ], [ 'pkg-config --cflags libfoo', \'%{.runtime.cflags}' ], [ 'pkg-config --libs libfoo', \'%{.runtime.libs}' ], ]; The scalar reference as the final item in the command list tells L that the output from the command should be stored in the given variable. The runtime variables are the ones that will be available to C once it is installed. (Install properties, which are the ones that we have seen up till now are thrown away once the L distribution is installed. You can also provide a C block for directives that should be used when a system install is detected. Normally you only need to do this if the gather step is different between share and system installs. For example, the above is equivalent to: build { ... gather [ [ 'pkg-config --modversion libfoo', \'%{.runtime.version}' ], [ 'pkg-config --cflags libfoo', \'%{.runtime.cflags}' ], [ 'pkg-config --libs libfoo', \'%{.runtime.libs}' ], ]; }; sys { gather [ [ 'pkg-config --modversion libfoo', \'%{.runtime.version}' ], [ 'pkg-config --cflags libfoo', \'%{.runtime.cflags}' ], [ 'pkg-config --libs libfoo', \'%{.runtime.libs}' ], ]; }; (Aside3, the reason it is called C and not C is so that it does not conflict with the built in C function)! =head2 Using plugins The first example is a good way of showing the full manual path that you can choose, but there is a lot of repetition, if you are doing many Ls that use autoconf and C (which are quite common. L allows you to use plugins. See L for a list of some of the plugin categories. For now, I will just show you how to write the L for libfoo above using L, L, L, and L use alienfile; plugin 'PkgConfig' => ( pkg_name => 'libfoo', ); share { start_url 'http://www.libfoo.org/src'; plugin 'Download' => ( filter => qr/^libfoo-[0-9\.]+\.tar\.gz$/, version => qr/^libfoo-([0-9\.]+)\.tar\.gz$/, ); plugin 'Extract' => 'tar.gz'; plugin 'Build::Autoconf'; build [ '%{configure} --disable-shared', '%{make}', '%{make} install', ]; }; The first plugin that we use is the C negotiation plugin. A negotiation plugin is one which doesn't do the actual work but selects the best one from a set of plugins depending on your platform and environment. (In the case of L, it may choose to use command line tools, a pure Perl implementation (L), or libpkgconf, depending on what is available). When using negotiation plugins you may omit the C<::Negotiate> suffix. So as you can see using the plugin here is an advantage because it is more reliable than just specifying a command which may not be installed! Next we use the download negotiation plugin. This is also better than the version above, because again, C my not be installed on the target system. Also you can specify a URL which will be scanned for links, and use the most recent version. We use the Extract negotiation plugin to use either command line tools, or Perl libraries to extract from the archive once it is downloaded. Finally we use the Autoconf plugin (L). This is a lot more sophisticated and reliable than in the previous example, for a number of reasons. This version will even work on Windows assuming the library or tool you are alienizing supports that platform! Strictly speaking the build directive is not necessary, because the autoconf plugin provides a default which is reasonable. The only reason that you would want to include it is if you need to provide additional flags to the configure step. share { ... build [ '%{configure} --enable-bar --enable-baz --disable-shared', '%{make}', '%{make} install', ]; }; =head2 Multiple .pc files Some packages come with multiple libraries paired with multiple C<.pc> files. In this case you want to provide the L with an array reference of package names. plugin 'PkgConfig' => ( pkg_name => [ 'foo', 'bar', 'baz' ], ); All packages must be found in order for the C install to succeed. Once installed the first C will be used by default (in this example C), and you can retrieve any other C using the L. =head2 A note about dynamic vs. static libraries If you are using your L to build an XS module, it is important that you use static libraries if possible. If you have a package that refuses to build a static library, then you can use L. Actually let me back up a minute. For a C install it is best to use static libraries to build your XS extension. This is because if your L is ever upgraded to a new version it can break your existing XS modules. For a C install shared libraries are usually best because you can often get security patches without having to re-build anything in perl land. If you looked closely at the "Using commands" and "Using plugins" sections above, you may notice that we went out of our way where possible to tell Autotools to build only static libraries using the C<--disable-shared> command. The Autoconf plugin also does this by default. Sometimes though you will have a package that builds both, or maybe you I both static and dynamic libraries to work with XS and FFI. For that case, there is the L plugin. use alienfile; ... plugin 'Gather::IsolateDynamic'; What it does, is that it moves the dynamic libraries (usually .so on Unix and .DLL on Windows) to a place where they can be found by FFI, and where they won't be used by the compiler for building XS. It usually doesn't do any harm to include this plugin, so if you are just starting out you might want to add it anyway. Arguably it should have been the default behavior from the beginning. If you have already published an Alien that does not isolate its dynamic libraries, then you might get some fails from old upgraded aliens because the share directory isn't cleaned up by default (this is perhaps a design bug in the way that share directories work, but it is a long standing characteristic). One work around for this is to use the C property on L, which will clean out the share directory on upgrade, and possibly save you a lot of grief. =head2 Verifying and debugging your alienfile You could feed your alienfile directly into L, or L, but it is sometimes useful to test your alienfile using the C command (it does not come with L, you need to install L). By default C will use the C in the current directory (just as C uses the C in the current directory; just like C you can use the C<-f> option to specify a different L). You can test your L in dry run mode: % af install --dry-run Alien::Build::Plugin::Core::Legacy> adding legacy hash to config Alien::Build::Plugin::Core::Gather> mkdir -p /tmp/I2YXRyxb0r/_alien --- cflags: '' cflags_static: '' install_type: system legacy: finished_installing: 1 install_type: system name: libfoo original_prefix: /tmp/7RtAusykNN version: 1.2.3 libs: '-lfoo ' libs_static: '-lfoo ' prefix: /tmp/7RtAusykNN version: 1.2.3 You can use the C<--type> option to force a share install (download and build from source): % af install --type=share --dry-run Alien::Build::Plugin::Core::Download> decoding html Alien::Build::Plugin::Core::Download> candidate *https://www.libfoo.org/download/libfoo-1.2.4.tar.gz Alien::Build::Plugin::Core::Download> candidate https://www.libfoo.org/download/libfoo-1.2.3.tar.gz Alien::Build::Plugin::Core::Download> candidate https://www.libfoo.org/download/libfoo-1.2.2.tar.gz Alien::Build::Plugin::Core::Download> candidate https://www.libfoo.org/download/libfoo-1.2.1.tar.gz Alien::Build::Plugin::Core::Download> candidate https://www.libfoo.org/download/libfoo-1.2.0.tar.gz Alien::Build::Plugin::Core::Download> candidate https://www.libfoo.org/download/libfoo-1.1.9.tar.gz Alien::Build::Plugin::Core::Download> candidate https://www.libfoo.org/download/libfoo-1.1.8.tar.gz Alien::Build::Plugin::Core::Download> candidate https://www.libfoo.org/download/libfoo-1.1.7.tar.gz Alien::Build::Plugin::Core::Download> candidate ... Alien::Build::Plugin::Core::Download> setting version based on archive to 1.2.4 Alien::Build::Plugin::Core::Download> downloaded libfoo-1.2.4.tar.gz Alien::Build::CommandSequence> + ./configure --prefix=/tmp/P22WEXj80r --with-pic --disable-shared ... snip ... Alien::Build::Plugin::Core::Gather> mkdir -p /tmp/WsoLAQ889w/_alien --- cflags: '' cflags_static: '' install_type: share legacy: finished_installing: 1 install_type: share original_prefix: /tmp/P22WEXj80r version: 1.2.4 libs: '-L/tmp/P22WEXj80r/lib -lfoo ' libs_static: '-L/tmp/P22WEXj80r/lib -lfoo ' prefix: /tmp/P22WEXj80r version: 1.2.4 You can also use the C<--before> and C<--after> options to take a peek at what the build environment looks like at different stages as well, which can sometimes be useful: % af install --dry-run --type=share --before build bash Alien::Build::Plugin::Core::Download> decoding html Alien::Build::Plugin::Core::Download> candidate *https://www.libfoo.org/download/libfoo-1.2.4.tar.gz Alien::Build::Plugin::Core::Download> candidate https://www.libfoo.org/download/libfoo-1.2.3.tar.gz Alien::Build::Plugin::Core::Download> candidate https://www.libfoo.org/download/libfoo-1.2.2.tar.gz Alien::Build::Plugin::Core::Download> candidate https://www.libfoo.org/download/libfoo-1.2.1.tar.gz Alien::Build::Plugin::Core::Download> candidate https://www.libfoo.org/download/libfoo-1.2.0.tar.gz Alien::Build::Plugin::Core::Download> candidate https://www.libfoo.org/download/libfoo-1.1.9.tar.gz Alien::Build::Plugin::Core::Download> candidate https://www.libfoo.org/download/libfoo-1.1.8.tar.gz Alien::Build::Plugin::Core::Download> candidate https://www.libfoo.org/download/libfoo-1.1.7.tar.gz Alien::Build::Plugin::Core::Download> candidate ... Alien::Build::Plugin::Core::Download> setting version based on archive to 1.2.4 Alien::Build::Plugin::Core::Download> downloaded libfoo-1.2.4.tar.gz App::af::install> [ before build ] + bash /tmp/fbVPu4LRTs/build_5AVn/libfoo-1.2.4$ ls CHANGES Makefile autoconf.ac lib /tmp/fbVPu4LRTs/build_5AVn/libfoo-1.2.4$ There are a lot of other useful things that you can do with the C command. See L for details. =head2 Integrating with MakeMaker Once you have a working L you can write your C. use ExtUtils::MakeMaker; use Alien::Build::MM; my $abmm = Alien::Build::MM->new; WriteMakefile($abmm->mm_args( ABSTRACT => 'Discover or download and install libfoo', DISTNAME => 'Alien-Libfoo', NAME => 'Alien::Libfoo', VERSION_FROM => 'lib/Alien/Libfoo.pm', CONFIGURE_REQUIRES => { 'Alien::Build::MM' => 0, }, BUILD_REQUIRES => { 'Alien::Build::MM' => 0, }, PREREQ_PM => { 'Alien::Base' => 0, }, # If you are going to write the recommended # tests you will will want these: TEST_REQUIRES => { 'Test::Alien' => 0, 'Test2::V0' => 0, }, )); sub MY::postamble { $abmm->mm_postamble; } The C that goes along with it is very simple: package Alien::Libfoo; use strict; use warnings; use parent qw( Alien::Base ); 1; You are done and can install it normally: % perl Makefile.PL % make % make test % make install =head2 Integrating with Module::Build Please don't! Okay if you have to there is L. =head2 Non standard configuration L support most of the things that your L will need, like compiler flags (cflags), linker flags (libs) and binary directory (bin_dir). Your library or tool may have other configuration items which are not supported by default. You can store the values in the L into the runtime properties: gather [ # standard: [ 'foo-config --version libfoo', \'%{.runtime.version}' ], [ 'foo-config --cflags libfoo', \'%{.runtime.cflags}' ], [ 'foo-config --libs libfoo', \'%{.runtime.libs}' ], # non-standard [ 'foo-config --bar-baz libfoo', \'%{.runtime.bar_baz}' ], ]; then you can expose them in your L subclass: package Alien::Libfoo; use strict; use warnings; use parent qw( Alien::Base ); sub bar_baz { my($self) = @_; $self->runtime_prop->{bar_baz}, }; 1; =head2 Testing (optional, but highly recommended) You should write a test using L to make sure that your alien will work with any XS modules that are going to use it: use Test2::V0; use Test::Alien; use Alien::Libfoo; alien_ok 'Alien::Libfoo'; xs_ok do { local $/; }, with_subtest { is Foo::something(), 1, 'Foo::something() returns 1'; }; done_testing; __DATA__ #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include MODULE = Foo PACKAGE = Foo int something() You can also use L to test tools instead of libraries: use Test2::V0; use Test::Alien; use Alien::Libfoo; alien_ok 'Alien::Libfoo'; run_ok(['foo', '--version']) ->exit_is(0); done_testing; You can also write tests specifically for L, if your alien is going to be used to write FFI bindings. (the test below is the FFI equivalent to the XS example above). use Test2::V0; use Test::Alien; use Alien::Libfoo; alien_ok 'Alien::Libfoo'; ffi_ok { symbols => [ 'something' ] }, with_subtest { # $ffi is an instance of FFI::Platypus with the lib # set appropriately. my($ffi) = @_; my $something = $ffi->function( something => [] => 'int' ); is $something->call(), 1, 'Foo::something() returns 1'; }; If you do use C you want to make sure that your alien reliably produces dynamic libraries. If it isn't consistent (if for example some platforms tend not to provide or build dynamic libraries), you can check that C doesn't return an empty list. ... alien_ok 'Alien::Libfoo'; SKIP: { skip "This test requires a dynamic library" unless Alien::Libfoo->dynamic_libs; ffi_ok { symbols [ 'something' ] }, with_subtest { ... }; } More details on testing L modules can be found in the L documentation. You can also run the tests that come with the package that you are alienizing, by using a C block in your L. Keep in mind that some packages use testing tools or have other prerequisites that will not be available on your users machines when they attempt to install your alien. So you do not want to blindly add a test block without checking what the prereqs are. For Autoconf style packages you typically test a package using the C command: use alienfile; plugin 'PkgConfig' => 'libfoo'; share { ... # standard build steps. test [ '%{make} check' ]; }; =head2 Dist::Zilla (optional, mildly recommended) You can also use the L L plugin L: name = Alien-Libfoo author = E. Xavier Ample license = Perl_5 copyright_holder = E. Xavier Ample copyright_year = 2017 version = 0.01 [@Basic] [AlienBuild] The plugin takes care of a lot of details like making sure that the correct minimum versions of L and L are used. See the plugin documentation for additional details. =head2 Using your Alien Once you have installed you can use your Alien. See L for guidance on that. =head1 SEE ALSO =over 4 =item L Other L manuals. =back =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Manual/PluginAuthor.pod000044400000052341152346246300012155 0ustar00# PODNAME: Alien::Build::Manual::PluginAuthor # ABSTRACT: Alien::Build plugin author documentation # VERSION __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Manual::PluginAuthor - Alien::Build plugin author documentation =head1 VERSION version 2.74 =head1 SYNOPSIS your plugin: package Alien::Build::Plugin::Build::MyPlugin; use strict; use warnings; use Alien::Build::Plugin; has arg1 => 'default_for arg1'; has arg2 => sub { [ 'default', 'for', 'arg2' ] }; sub init { my($self, $meta) = @_; ... } 1; and then from L: use alienfile; plugin 'Build::MyPlugin' => ( arg1 => 'override for arg1', arg2 => [ 'something', 'else' ], ); =for html

flowchart

Notes: The colored blocks indicate alienfile blocks. Hooks are indicated as predefined process (rectangle with double struck vertical edges). Hooks that can easily be implemented from an alienfile are indicated in blue (Note that [] is used to indicate passing in an array reference, but a subroutine reference can also be used). For simplicity, the the flowchart does not include when required modules are loaded. Except for configure time requirements, they are loaded when the corresponding alienfile blocks are entered. It is not shown, but generally any plugin can cause a Fail by throwing an exception with die.

Perlish pseudo code for how plugins are called: my $probe; my $override = override(); if($override eq 'system') { $probe = probe(); if($probe ne 'system') { die 'system tool or library not found'; } } elsif($override eq 'default') { $probe = probe(); } else { # $override eq 'share' # note that in this instance the # probe hook is never called $probe = 'share'; } if($probe eq 'system') { gather_system(); } else { # $probe eq 'share' download(); extract(); patch(); build(); gather_share(); # Check to see if there isa build_ffi hook if(defined &build_ffi) { patch_ffi(); build_ffi(); gather_ffi(); } } # By default this just returns the value of $ENV{ALIEN_INSTALL_TYPE} sub override { return $ENV{ALIEN_INSTALL_TYPE}; } # Default download implementation; can be # replaced by specifying a different download # hook. See Alien::Build::Plugin::Core::Download # for detailed implementation. sub download { my $response = fetch(); if($response->{type} eq 'html' || $response->{type} eq 'dir_listing') { # decode will transform an HTML listing (html) or a FTP directory # listing (dir_listing) into a regular list $response = decode($response); } if($response->{type} eq 'list') { # prefer will filter bad entries in the list # and sort them so that the first one is # the one that we want $response = prefer($response); my $first_preferred = $res->{list}->[0]; # prefer can sometimes infer the version from the # filename. if(defined $first_preferred->{version}) { # not a hook runtime_prop->{version} = $first_preferred->{version}; } $response = fetch($first_preferred); } if($response->{type} eq 'file') { # not a hook write_file_to_disk $response; } } =head1 DESCRIPTION This document explains how to write L plugins using the L base class. =head2 Writing plugins Plugins use L, which sets the appropriate base class, and provides you with the C property builder. C takes two arguments, the name of the property and the default value. (As with L and L, you should use a code reference to specify default values for non-string defaults). No B set this as your plugin's base class directly: use parent qw( Alien::Build::Plugin ); # wrong use Alien::Build::Plugin; # right The only method that you need to implement is C. From this method you can add hooks to change the behavior of the L recipe. This is a very simple example of a probe hook, with the actual probe logic removed: sub init { my($self, $meta) = @_; $meta->register_hook( probe => sub { my($build) = @_; if( ... ) { return 'system'; } else { return 'share'; } }, ); } Hooks get the L instance as their first argument, and depending on the hook may get additional arguments. =head2 Modifying hooks You can also modify hooks using C, C and C, similar to L modifiers: sub init { my($self, $meta) = @_; $meta->before_hook( build => sub { my($build) = @_; $build->log('this runs before the build'); }, ); $meta->after_hook( build => sub { my($build) = @_; $build->log('this runs after the build'); }, ); $meta->around_hook( build => sub { my $orig = shift; # around hooks are useful for setting environment variables local $ENV{CPPFLAGS} = '-I/foo/include'; $orig->(@_); }, ); } =head2 Testing plugins You can and should write tests for your plugin. The best way to do this is using L, which allows you to write an inline L in your test. Here is an example: use Test::V0; use Test::Alien::Build; my $build = alienfile_ok q{ use alienfile; plugin 'Build::MyPlugin' => ( arg1 => 'override for arg1', arg2 => [ 'something', 'else' ], ); ... }; # you can interrogate $build, it is an instance of L. my $alien = alien_build_ok; # you can interrogate $alien, it is an instance of L. =head2 Negotiator plugins A Negotiator plugin doesn't itself typically implement anything on its own, but picks the best plugin to achieve a particular goal. The "best" plugin can in some cases vary depending on the platform or tools that are available. For example The L might choose to use the fetch plugin that relies on the command line C, or it might choose the fetch plugin that relies on the Perl module L depending on the platform and what is already installed. (For either to be useful they have to support SSL). The Negotiator plugin is by convention named something like C, but is typically invoked without the C<::Negotiate> suffix. For example: plugin 'Download'; # is short for Alien::Build::Plugin::Download::Negotiator Here is a simple example of a negotiator which picks C if already installed and L otherwise. (The actual download plugin is a lot smarter and complicated than this, but this is a good simplified example). package Alien::Build::Plugin::Download::Negotiate; use strict; use warnings; use Alien::Build::Plugin; use File::Which qw( which ); sub init { my($self, $meta) = @_; if(which('curl')) { $meta->apply_plugin('Fetch::Curl'); } else { $meta->apply_plugin('Fetch::HTTPTiny'); } } =head2 Hooks The remainder of this document is a reference for the hooks that you can register. Generally speaking you can register any hook that you like, but some care must be taken as some hooks have default behavior that will be overridden when you register a hook. The hooks are presented in alphabetical order. The execution order is shown in the flowchart above (if you are browsing the HTML version of this document), or the Perlish pseudo code in the synopsis section. =head1 HOOKS =head2 build hook $meta->register_hook( build => sub { my($build) = @_; ... }); This does the main build of the alienized project and installs it into the staging area. The current directory is the build root. You need to run whatever tools are necessary for the project, and install them into C<$build->install_prop->{prefix}> (C<%{.install.prefix}>). =head2 build_ffi hook $meta->register_hook( build_ffi => sub { my($build) = @_; ... }); This is the same as L, except it fires only on a FFI build. =head2 decode hook $meta->register_hook( decode => sub { my($build, $res) = @_; ... } This hook takes a response hash reference from the C hook above with a type of C or C and converts it into a response hash reference of type C. In short it takes an HTML or FTP file listing response from a fetch hook and converts it into a list of filenames and links that can be used by the prefer hook to choose the correct file to download. See the L for the specification of the input and response hash references. =head2 check_digest hook # implement the well known FOO-92 digest $meta->register_hook( check_digest => sub { my($build, $file, $algorithm, $digest) = @_; if($algorithm ne 'FOO92') { return 0; } my $actual = foo92_hex_digest($file); if($actual eq $digest) { return 1; } else { die "Digest FOO92 does not match: got $actual, expected $digest"; } }); This hook should check the given C<$file> (the format is the same as used by L) matches the given C<$digest> using the given C<$algorithm>. If the plugin does not support the given algorithm, then it should return a false value. If the digest does not match, it should throw an exception. If the digest matches, it should return a true value. =head2 clean_install $meta->register_hook( clean_install => sub { my($build) = @_; }); This hook allows you to remove files from the final install location before the files are installed by the installer layer (examples: L, L or L). This hook is not called by default, and must be enabled via the interface to the installer layer (example: L). This hook SHOULD NOT remove the C<_alien> directory or its content from the install location. The default implementation removes all the files EXCEPT the C<_alien> directory and its content. =head2 download hook $meta->register_hook( download => sub { my($build) = @_; ... }); This hook is used to download from the internet the source. Either as an archive (like tar, zip, etc), or as a directory of files (C, etc). When the hook is called, the current working directory will be a new empty directory, so you can save the download to the current directory. If you store a single file in the directory, L will assume that it is an archive, which will be processed by the L. If you store multiple files, L will assume the current directory is the source root. If no files are stored at all, an exception with an appropriate diagnostic will be thrown. B: If you register this hook, then the fetch, decode and prefer hooks will NOT be called, unless you call them yourself from this hook. =head2 extract hook $meta->register_hook( extract => sub { my($build, $archive) = @_; ... }); This hook is used to extract an archive that has already been downloaded. L already has plugins for the most common archive formats, so you will likely only need this to add support for new or novel archive formats. When this hook is called, the current working directory will be a new empty directory, so you can save the content of the archive to the current directory. If a single directory is written to the current directory, L will assume that is the root directory of the package. If multiple files and/or directories are present, that will indicate that the current working directory is the root of the package. The logic typically handles correctly the default behavior for tar (where packages are typically extracted to a subdirectory) and for zip (where packages are typically extracted to the current directory). =head2 fetch hook package Alien::Build::Plugin::MyPlugin; use strict; use warnings; use Alien::Build::Plugin; use Carp (); has '+url' => sub { Carp::croak "url is required property" }; sub init { my($self, $meta) = @_; $meta->register_hook( fetch => sub { my($build, $url, %options) = @_; ... } } 1; Used to fetch a resource. The first time it will be called without an argument (or with C<$url> set to C, so the configuration used to find the resource should be specified by the plugin's properties. On subsequent calls the first argument will be a URL. The C<%options> hash may contain these options: =over 4 =item http_headers HTTP request headers, if an appropriate protocol is being used. The headers are provided as an array reference of key/value pairs, which allows for duplicate header keys with multiple values. If a non-HTTP protocol is used, or if the plugin cannot otherwise send HTTP request headers, the plugin SHOULD issue a warning using the C<< $build->log >> method, but because this option wasn't part of the original spec, the plugin MAY no issue that warning while ignoring it. =back Note that versions of L prior to 2.39 did not pass the options hash into the fetch plugin. Normally the first fetch will be to either a file or a directory listing. If it is a file then the content should be returned as a hash reference with the following keys: # content of file stored in Perl return { type => 'file', filename => $filename, content => $content, version => $version, # optional, if known protocol => $protocol, # AB 2.60 optional, but recommended }; # content of file stored in the filesystem return { type => 'file', filename => $filename, path => $path, # full file system path to file version => $version, # optional, if known tmp => $tmp, # optional protocol => $protocol, # AB 2.60 optional, but recommended }; C<$tmp> if set will indicate if the file is temporary or not, and can be used by L to save a copy in some cases. The default is true, so L assumes the file or directory is temporary if you don't tell it otherwise. Probably the most common situation when you would set C to false, is when the file is bundled inside the L distribution. See L for example. If the URL points to a directory listing you should return it as either a hash reference containing a list of files: return { type => 'list', list => [ # filename: each filename should be just the # filename portion, no path or url. # url: each url should be the complete url # needed to fetch the file. # version: OPTIONAL, may be provided by some fetch or prefer { filename => $filename1, url => $url1, version => $version1 }, { filename => $filename2, url => $url2, version => $version2 }, ], protocol => $protocol, # AB 2.60 optional, but recommended }; or if the listing is in HTML format as a hash reference containing the HTML information: return { type => 'html', charset => $charset, # optional base => $base, # the base URL: used for computing relative URLs content => $content, # the HTML content protocol => $protocol, # optional, but recommended }; or a directory listing (usually produced by an FTP servers) as a hash reference: return { type => 'dir_listing', base => $base, content => $content, protocol => $protocol, # AB 2.60 optional, but recommended }; [version 2.60] For all of these responses C<$protocol> is optional, since it was not part of the original spec, however it is strongly recommended that you include this field, because future versions of L will use this to determine if a file was downloaded securely (that is via a secure protocol such as SSL). Some plugins (like L) trans late a file hash from one type to another, they should maintain the C<$protocol> from the old to the new representation of the file. =head2 gather_ffi hook $meta->register_hook( gather_ffi => sub { my($build) = @_; $build->runtime_prop->{cflags} = ...; $build->runtime_prop->{libs} = ...; $build->runtime_prop->{version} = ...; }); This hook is called for a FFI build to determine the properties necessary for using the library or tool. These properties should be stored in the L hash as shown above. Typical properties that are needed for libraries are cflags and libs. If at all possible you should also try to determine the version of the library or tool. =head2 gather_share hook $meta->register_hook( gather_share => sub { my($build) = @_; $build->runtime_prop->{cflags} = ...; $build->runtime_prop->{libs} = ...; $build->runtime_prop->{version} = ...; }); This hook is called for a share install to determine the properties necessary for using the library or tool. These properties should be stored in the L hash as shown above. Typical properties that are needed for libraries are cflags and libs. If at all possible you should also try to determine the version of the library or tool. =head2 gather_system hook $meta->register_hook( gather_system => sub { my($build) = @_; $build->runtime_prop->{cflags} = ...; $build->runtime_prop->{libs} = ...; $build->runtime_prop->{version} = ...; }); This hook is called for a system install to determine the properties necessary for using the library or tool. These properties should be stored in the L hash as shown above. Typical properties that are needed for libraries are cflags and libs. If at all possible you should also try to determine the version of the library or tool. =head2 override hook $meta->register_hook( override => sub { my($build) = @_; return $ENV{ALIEN_INSTALL_TYPE} || ''; }); This allows you to alter the override logic. It should return one of C, C, C or C<''>. The default implementation is shown above. L and L are examples of how you can use this hook. =head2 patch hook $meta->register_hook( patch => sub { my($build) = @_; ... }); This hook is completely optional. If registered, it will be triggered after extraction and before build. It allows you to apply any patches or make any modifications to the source if they are necessary. =head2 patch_ffi hook $meta->register_hook( patch_ffi => sub { my($build) = @_; ... }); This hook is exactly like the L, except it fires only on an FFI build. =head2 prefer hook $meta->register_hook( prefer => sub { my($build, $res) = @_; return { type => 'list', list => [sort @{ $res->{list} }], }; } This hook sorts candidates from a listing generated from either the C or C hooks. It should return a new list hash reference with the candidates sorted from best to worst. It may also remove candidates that are totally unacceptable. =head2 probe hook $meta->register_hook( probe => sub { my($build) = @_; return 'system' if ...; # system install return 'share'; # otherwise }); $meta->register_hook( probe => [ $command ] ); This hook should return the string C if the operating system provides the library or tool. It should return C otherwise. You can also use a command that returns true when the tool or library is available. For example for use with C: $meta->register_hook( probe => [ '%{pkgconf} --exists libfoo' ] ); Or if you needed a minimum version: $meta->register_hook( probe => [ '%{pkgconf} --atleast-version=1.00 libfoo' ] ); Note that this hook SHOULD NOT gather system properties, such as cflags, libs, versions, etc, because the probe hook will be skipped in the event the environment variable C is set. The detection of these properties should instead be done by the L hook. Multiple probe hooks can be given. These will be used in sequence, stopping at the first that detects a system installation. =head1 SEE ALSO =over 4 =item L Other L manuals. =back =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Manual.pod000044400000004613152346246300007533 0ustar00# PODNAME: Alien::Build::Manual # ABSTRACT: The Alien::Build Manual # VERSION __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Manual - The Alien::Build Manual =head1 VERSION version 2.74 =head1 SYNOPSIS perldoc Alien::Build::Manual::Alien perldoc Alien::Build::Manual::AlienAuthor perldoc Alien::Build::Manual::AlienUser perldoc Alien::Build::Manual::Contributing perldoc Alien::Build::Manual::FAQ perldoc Alien::Build::Manual::PluginAuthor =head1 DESCRIPTION L comes with a number of manuals that are useful depending on how you are using L. =over 4 =item L General alien author documentation. =item L Alien author documentation. =item L Alien user documentation. =item L Overly-detailed contributing guide. =item L Frequently Asked Questions about L. =item L L plugin author documentation — or how to extend L with the plugin system. =item L Documents some of the challenges and configuration tools related to security of Ls. =back =head1 SEE ALSO =over 4 =item L =item L =item L =back =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin.pm000044400000014651152346246300007411 0ustar00package Alien::Build::Plugin; use strict; use warnings; use 5.008004; use Data::Dumper (); use Carp (); use Digest::SHA (); our @CARP_NOT = qw( alienfile Alien::Build Alien::Build::Meta ); # ABSTRACT: Plugin base class for Alien::Build our $VERSION = '2.74'; # VERSION sub new { my $class = shift; my %args = @_ == 1 ? ($class->meta->default => $_[0]) : @_; my $instance_id = Digest::SHA::sha1_hex(Data::Dumper->new([$class, \%args])->Sortkeys(1)->Dump); my $self = bless { instance_id => $instance_id }, $class; my $prop = $self->meta->prop; foreach my $name (keys %$prop) { $self->{$name} = defined $args{$name} ? delete $args{$name} : ref($prop->{$name}) eq 'CODE' ? $prop->{$name}->() : $prop->{$name}; } foreach my $name (keys %args) { Carp::carp "$class has no $name property"; } $self; } sub instance_id { shift->{instance_id} } sub init { my($self) = @_; $self; } sub import { my($class) = @_; return if $class ne __PACKAGE__; my $caller = caller; { no strict 'refs'; @{ "${caller}::ISA" } = __PACKAGE__ } my $meta = $caller->meta; my $has = sub { my($name, $default) = @_; $meta->add_property($name, $default); }; { no strict 'refs'; *{ "${caller}::has" } = $has } } my %meta; sub meta { my($class) = @_; $class = ref $class if ref $class; $meta{$class} ||= Alien::Build::PluginMeta->new( class => $class ); } package Alien::Build::PluginMeta; sub new { my($class, %args) = @_; my $self = bless { prop => {}, %args, }, $class; } sub default { my($self) = @_; $self->{default} || do { Carp::croak "No default for @{[ $self->{class} ]}"; }; } sub add_property { my($self, $name, $default) = @_; my $single = $name =~ s{^(\+)}{}; $self->{default} = $name if $single; $self->{prop}->{$name} = $default; my $accessor = sub { my($self, $new) = @_; $self->{$name} = $new if defined $new; $self->{$name}; }; # add the accessor { no strict 'refs'; *{ $self->{class} . '::' . $name} = $accessor } $self; } sub prop { shift->{prop}; } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin - Plugin base class for Alien::Build =head1 VERSION version 2.74 =head1 SYNOPSIS Create your plugin: package Alien::Build::Plugin::Type::MyPlugin; use Alien::Build::Plugin; use Carp (); has prop1 => 'default value'; has prop2 => sub { 'default value' }; has prop3 => sub { Carp::croak 'prop3 is a required property' }; sub init { my($self, $meta) = @_; my $prop1 = $self->prop1; my $prop2 = $self->prop2; my $prop3 = $self->prop3; $meta->register_hook(sub { build => [ '%{make}', '%{make} install' ], }); } From your L use alienfile; plugin 'Type::MyPlugin' => ( prop2 => 'different value', prop3 => 'need to provide since it is required', ); =head1 DESCRIPTION This document describes the L plugin base class. For details on how to write a plugin, see L. Listed are some common types of plugins: =over 4 =item L Tools for building. =item L Tools already included. =item L Normally use Download plugins which will pick the correct Decode plugins. =item L Tools for checking cryptographic signatures during a C install. =item L Methods for retrieving from the internet. =item L Extract from archives that have been downloaded. =item L Normally use Download plugins which will pick the correct Fetch plugins. =item L Plugins that modify or enhance the gather step. =item L Plugins that work with C or libraries that provide the same functionality. =item L Normally use Download plugins which will pick the correct Prefer plugins. =item L Look for packages already installed on the system. =item L Plugins useful for unit testing L itself, or plugins for it. =back =head1 CONSTRUCTOR =head2 new my $plugin = Alien::Build::Plugin->new(%props); =head2 PROPERTIES =head2 instance_id my $id = $plugin->instance_id; Returns an instance id for the plugin. This is computed from the class and arguments that are passed into the plugin constructor, so technically two instances with the exact same arguments will have the same instance id, but in practice you should never have two instances with the exact same arguments. =head1 METHODS =head2 init $plugin->init($ab_class->meta); # $ab is an Alien::Build class name You provide the implementation for this. The intent is to register hooks and set meta properties on the L class. =head2 has has $prop_name; has $prop_name => $default; Specifies a property of the plugin. You may provide a default value as either a string scalar, or a code reference. The code reference will be called to compute the default value, and if you want the default to be a list or hash reference, this is how you want to do it: has foo => sub { [1,2,3] }; =head2 meta my $meta = $plugin->meta; Returns the plugin meta object. =head1 SEE ALSO L, L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Log.pm000044400000006222152346246300006667 0ustar00package Alien::Build::Log; use strict; use warnings; use 5.008004; use Carp (); # ABSTRACT: Alien::Build logging our $VERSION = '2.74'; # VERSION my $log_class; my $self; sub new { my($class) = @_; Carp::croak("Cannot instantiate base class") if $class eq 'Alien::Build::Log'; return bless {}, $class; } sub default { $self || do { my $class = $log_class || $ENV{ALIEN_BUILD_LOG} || 'Alien::Build::Log::Default'; unless(eval { $class->can('new') }) { my $pm = "$class.pm"; $pm =~ s/::/\//g; require $pm; } $class->new; } } sub set_log_class { my(undef, $class) = @_; return if defined $class && ($class eq ($log_class || '')); $log_class = $class; undef $self; } sub log { Carp::croak("AB Log base class"); } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Log - Alien::Build logging =head1 VERSION version 2.74 =head1 SYNOPSIS Create your custom log class: package Alien::Build::Log::MyLog; use parent qw( Alien::Build::Log ); sub log { my(undef, %opt) = @_; my($package, $filename, $line) = @{ $opt{caller} }; my $message = $opt{message}; ...; } override log class: % env ALIEN_BUILD_LOG=Alien::Build::Log::MyLog cpanm Alien::libfoo =head1 DESCRIPTION =head1 CONSTRUCTORS =head2 new my $log = Alien::Build::Log->new; Create an instance of the log class. =head2 default my $log = Alien::Build::Log->default; Return singleton instance of log class used by L. =head1 METHODS =head2 set_log_class Alien::Build::Log->set_log_class($class); Set the default log class used by L. This method will also reset the default instance used by L. If not specified, L will be used. =head2 log $log->log(%options); Overridable method which does the actual work of the log class. Options: =over 4 =item caller Array references containing the package, file and line number of where the log was called. =item message The message to log. =back =head1 ENVIRONMENT =over 4 =item ALIEN_BUILD_LOG The default log class used by L. =back =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Probe/Vcpkg.pm000044400000015405152346246310011531 0ustar00package Alien::Build::Plugin::Probe::Vcpkg; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; # ABSTRACT: Probe for system libraries using Vcpkg our $VERSION = '2.74'; # VERSION has '+name'; has 'lib'; has 'ffi_name'; has 'include'; sub init { my($self, $meta) = @_; if(defined $self->include) { $meta->add_requires('configure' => 'Alien::Build::Plugin::Probe::Vcpkg' => '2.16' ); } elsif(defined $self->ffi_name) { $meta->add_requires('configure' => 'Alien::Build::Plugin::Probe::Vcpkg' => '2.14' ); } else { $meta->add_requires('configure' => 'Alien::Build::Plugin::Probe::Vcpkg' => '0' ); } if($meta->prop->{platform}->{compiler_type} eq 'microsoft') { $meta->register_hook( probe => sub { my($build) = @_; $build->hook_prop->{probe_class} = __PACKAGE__; $build->hook_prop->{probe_instance_id} = $self->instance_id; eval { require Win32::Vcpkg; require Win32::Vcpkg::List; require Win32::Vcpkg::Package; Win32::Vcpkg->VERSION('0.02'); }; if(my $error = $@) { $build->log("unable to load Win32::Vcpkg: $error"); return 'share'; } my $package; if($self->name) { $package = Win32::Vcpkg::List->new ->search($self->name, include => $self->include); } elsif($self->lib) { $package = eval { Win32::Vcpkg::Package->new( lib => $self->lib, include => $self->include) }; return 'share' if $@; } else { $build->log("you must provode either name or lib property for Probe::Vcpkg"); return 'share'; } my $version = $package->version; $version = 'unknown' unless defined $version; $build->install_prop->{plugin_probe_vcpkg}->{$self->instance_id} = { version => $version, cflags => $package->cflags, libs => $package->libs, }; $build->hook_prop->{version} = $version; $build->install_prop->{plugin_probe_vcpkg}->{$self->instance_id}->{ffi_name} = $self->ffi_name if defined $self->ffi_name; return 'system'; }, ); $meta->register_hook( gather_system => sub { my($build) = @_; return if $build->hook_prop->{name} eq 'gather_system' && ($build->install_prop->{system_probe_instance_id} || '') ne $self->instance_id; if(my $c = $build->install_prop->{plugin_probe_vcpkg}->{$self->instance_id}) { $build->runtime_prop->{version} = $c->{version} unless defined $build->runtime_prop->{version}; $build->runtime_prop->{$_} = $c->{$_} for grep { defined $c->{$_} } qw( cflags libs ffi_name ); } }, ); } } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Probe::Vcpkg - Probe for system libraries using Vcpkg =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; plugin 'Probe::Vcpkg' => 'libffi'; =head1 DESCRIPTION This plugin probe can be used to find "system" packages using Microsoft's C package manager for Visual C++ builds of Perl. C is a package manager for Visual C++ that includes a number of open source packages. Although C does also support Linux and macOS, this plugin does not support finding C packages on those platforms. For more details on C, see the project github page here: L Here is the quick start guide for getting L to work with C: # install Vcpkg C:\> git clone https://github.com/Microsoft/vcpkg.git C:\> cd vcpkg C:\vcpkg> .\bootstrap-vcpkg.bat C:\vcpkg> .\vcpkg integrate install # update PATH to include the bin directory # so that .DLL files can be found by Perl C:\vcpkg> path c:\vcpkg\installed\x64-windows\bin;%PATH% # install the packages that you want C:\vcpkg> .\vcpkg install libffi # install the alien that uses it C:\vcpkg> cpanm Alien::FFI If you are using 32 bit build of Perl, then substitute C for C. If you do not want to add the C directory to the C, then you can use C instead, which will provide static libraries. (As of this writing static libraries for 32 bit Windows are not available). The main downside to using C is that Aliens that require dynamic libraries for FFI will not be installable. If you do not want to install C user wide (the C command above), then you can use the C environment variable instead: # install Vcpkg C:\> git clone https://github.com/Microsoft/vcpkg.git C:\> cd vcpkg C:\vcpkg> .\bootstrap-vcpkg.bat C:\vcpkg> set PERL_WIN32_VCPKG_ROOT=c:\vcpkg =head1 PROPERTIES =head2 name Specifies the name of the Vcpkg. This should not be used with the C property below, choose only one. This is the default property, so these two are equivalent: plugin 'Probe::Vcpkg' => (name => 'foo'); and plugin 'Probe::Vcpkg' => 'foo'; =head2 lib Specifies the list of libraries that make up the Vcpkg. This should not be used with the C property above, choose only one. Note that using this detection method, the version number of the package will not be automatically determined (since multiple packages could potentially make up the list of libraries), so you need to determine the version number another way if you need it. This must be an array reference. Do not include the C<.lib> extension. plugin 'Probe::Vcpkg' => (lib => ['foo','bar']); =head2 ffi_name Specifies an alternate ffi_name for finding dynamic libraries. =head1 SEE ALSO L, L, L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Probe/CommandLine.pm000044400000012745152346246310012651 0ustar00package Alien::Build::Plugin::Probe::CommandLine; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; use Carp (); use Capture::Tiny qw( capture ); use File::Which (); use Alien::Util qw( version_cmp ); # ABSTRACT: Probe for tools or commands already available our $VERSION = '2.74'; # VERSION has '+command' => sub { Carp::croak "@{[ __PACKAGE__ ]} requires command property" }; has 'args' => []; has 'secondary' => 0; has 'match' => undef; has 'match_stderr' => undef; has 'version' => undef; has 'version_stderr' => undef; has 'atleast_version' => undef; sub init { my($self, $meta) = @_; my $check = sub { my($build) = @_; unless(File::Which::which($self->command)) { die 'Command not found ' . $self->command; } if(defined $self->match || defined $self->match_stderr || defined $self->version || defined $self->version_stderr) { my($out,$err,$ret) = capture { system( $self->command, @{ $self->args } ); }; die 'Command did not return a true value' if $ret; die 'Command output did not match' if defined $self->match && $out !~ $self->match; die 'Command standard error did not match' if defined $self->match_stderr && $err !~ $self->match_stderr; if (defined $self->version or defined $self->version_stderr) { my $found_version = '0'; if(defined $self->version) { if($out =~ $self->version) { $found_version = $1; $build->runtime_prop->{version} = $found_version; } } if(defined $self->version_stderr) { if($err =~ $self->version_stderr) { $found_version = $1; $build->hook_prop->{version} = $found_version; $build->runtime_prop->{version} = $found_version; } } if (my $atleast_version = $self->atleast_version) { if(version_cmp ($found_version, $self->atleast_version) < 0) { # reset the versions $build->runtime_prop->{version} = undef; $build->hook_prop->{version} = undef; die "CommandLine probe found version $found_version, but at least $atleast_version is required."; } } } } $build->runtime_prop->{command} = $self->command; 'system'; }; if($self->secondary) { $meta->around_hook( probe => sub { my $orig = shift; my $build = shift; my $type = $orig->($build, @_); return $type unless $type eq 'system'; $check->($build); }, ); } else { $meta->register_hook( probe => $check, ); } } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Probe::CommandLine - Probe for tools or commands already available =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; plugin 'Probe::CommandLine' => ( command => 'gzip', args => [ '--version' ], match => qr/gzip/, version => qr/gzip ([0-9\.]+)/, ); =head1 DESCRIPTION This plugin probes for the existence of the given command line program. =head1 PROPERTIES =head2 command The name of the command. =head2 args The arguments to pass to the command. =head2 secondary If you are using another probe plugin (such as L or L) to detect the existence of a library, but also need a program to exist, then you should set secondary to a true value. For example when you need both: use alienfile; # requires both liblzma library and xz program plugin 'PkgConfig' => 'liblzma'; plugin 'Probe::CommandLine' => ( command => 'xz', secondary => 1, ); When you don't: use alienfile; plugin 'Probe::CommandLine' => ( command => 'gzip', secondary => 0, # default ); =head2 match Regular expression for which the program output should match. =head2 match_stderr Regular expression for which the program standard error should match. =head2 version Regular expression to parse out the version from the program output. The regular expression should store the version number in C<$1>. =head2 version_stderr Regular expression to parse out the version from the program standard error. The regular expression should store the version number in C<$1>. =head2 atleast_version The minimum required version as provided by the system. =head1 SEE ALSO L, L, L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Probe/CBuilder.pm000044400000015034152346246310012146 0ustar00package Alien::Build::Plugin::Probe::CBuilder; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; use File::chdir; use File::Temp (); use Capture::Tiny qw( capture_merged capture ); use Alien::Util qw( version_cmp ); # ABSTRACT: Probe for system libraries by guessing with ExtUtils::CBuilder our $VERSION = '2.74'; # VERSION has options => sub { {} }; has cflags => ''; has libs => ''; has program => 'int main(int argc, char *argv[]) { return 0; }'; has version => undef; has 'atleast_version' => undef; has aliens => []; has lang => 'C'; sub init { my($self, $meta) = @_; $meta->add_requires('configure' => 'ExtUtils::CBuilder' => 0 ); if(@{ $self->aliens }) { die "You can't specify both 'aliens' and either 'cflags' or 'libs' for the Probe::CBuilder plugin" if $self->cflags || $self->libs; $meta->add_requires('configure' => $_ => 0 ) for @{ $self->aliens }; $meta->add_requires('Alien::Build::Plugin::Probe::CBuilder' => '0.53'); my $cflags = ''; my $libs = ''; foreach my $alien (@{ $self->aliens }) { my $pm = "$alien.pm"; $pm =~ s/::/\//g; require $pm; $cflags .= $alien->cflags . ' '; $libs .= $alien->libs . ' '; } $self->cflags($cflags); $self->libs($libs); } my @cpp; if($self->lang ne 'C') { $meta->add_requires('Alien::Build::Plugin::Probe::CBuilder' => '0.53'); @cpp = ('C++' => 1) if $self->lang eq 'C++'; } $meta->register_hook( probe => sub { my($build) = @_; $build->hook_prop->{probe_class} = __PACKAGE__; $build->hook_prop->{probe_instance_id} = $self->instance_id; local $CWD = File::Temp::tempdir( CLEANUP => 1, DIR => $CWD ); open my $fh, '>', 'mytest.c'; print $fh $self->program; close $fh; $build->log("trying: cflags=@{[ $self->cflags ]} libs=@{[ $self->libs ]}"); my $cb = ExtUtils::CBuilder->new(%{ $self->options }); my($out1, $obj) = capture_merged { eval { $cb->compile( source => 'mytest.c', extra_compiler_flags => $self->cflags, @cpp, ); } }; if(my $error = $@) { $build->log("compile failed: $error"); $build->log("compile failed: $out1"); die $error; } my($out2, $exe) = capture_merged { eval { $cb->link_executable( objects => [$obj], extra_linker_flags => $self->libs, ); } }; if(my $error = $@) { $build->log("link failed: $error"); $build->log("link failed: $out2"); die $error; } my($out, $err, $ret) = capture { system($^O eq 'MSWin32' ? $exe : "./$exe") }; die "execute failed" if $ret; my $cflags = $self->cflags; my $libs = $self->libs; $cflags =~ s{\s*$}{ }; $libs =~ s{\s*$}{ }; $build->install_prop->{plugin_probe_cbuilder_gather}->{$self->instance_id} = { cflags => $cflags, libs => $libs, }; if(defined $self->version) { my($version) = $out =~ $self->version; if (defined $self->atleast_version) { if(version_cmp ($version, $self->atleast_version) < 0) { die "CBuilder probe found version $version, but at least @{[ $self->atleast_version ]} is required."; } } $build->hook_prop->{version} = $version; $build->install_prop->{plugin_probe_cbuilder_gather}->{$self->instance_id}->{version} = $version; } 'system'; } ); $meta->register_hook( gather_system => sub { my($build) = @_; return if $build->hook_prop->{name} eq 'gather_system' && ($build->install_prop->{system_probe_instance_id} || '') ne $self->instance_id; if(my $p = $build->install_prop->{plugin_probe_cbuilder_gather}->{$self->instance_id}) { $build->runtime_prop->{$_} = $p->{$_} for keys %$p; } }, ); } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Probe::CBuilder - Probe for system libraries by guessing with ExtUtils::CBuilder =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; plugin 'Probe::CBuilder' => ( cflags => '-I/opt/libfoo/include', libs => '-L/opt/libfoo/lib -lfoo', ); alternately: ues alienfile; plugin 'Probe::CBuilder' => ( aliens => [ 'Alien::libfoo', 'Alien::libbar' ], ); =head1 DESCRIPTION This plugin probes for compiler and linker flags using L. This is a useful alternative to L for packages that do not provide a pkg-config C<.pc> file, or for when those C<.pc> files may not be available. (For example, on FreeBSD, C is a core part of the operating system, but doesn't include a C<.pc> file which is usually provided when you install the C package on Linux). =head1 PROPERTIES =head2 options Any extra options that you want to have passed into the constructor to L. =head2 cflags The compiler flags. =head2 libs The linker flags =head2 program The program to use in the test. =head2 version This is a regular expression to parse the version out of the output from the test program. =head2 atleast_version The minimum required version as provided by the system. =head2 aliens List of aliens to query fro compiler and linker flags. =head2 lang The programming language to use. One of either C or C. =head1 SEE ALSO L, L, L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Test.pod000044400000003257152346246310010477 0ustar00# PODNAME: Alien::Build::Plugin::Test # ABSTRACT: Probe Alien::Build plugins # VERSION __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Test - Probe Alien::Build plugins =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; plugin 'Test::Mock' => ( probe => 'share', download => 1, extract => 1, build => 1, gather => 1, ); =head1 DESCRIPTION Test plugins are used in unit tests for L and possibly its plugins. =over 4 =item L Mocks common steps in an L. =back =head1 SEE ALSO L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Test/Mock.pm000044400000026471152346246310011225 0ustar00package Alien::Build::Plugin::Test::Mock; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; use Carp (); use Path::Tiny (); use File::chdir; # ABSTRACT: Mock plugin for testing our $VERSION = '2.74'; # VERSION has 'probe'; has 'download'; has 'extract'; has 'build'; has 'gather'; has check_digest => 1; sub init { my($self, $meta) = @_; if(my $probe = $self->probe) { if($probe =~ /^(share|system)$/) { $meta->register_hook( probe => sub { $probe; }, ); } elsif($probe eq 'die') { $meta->register_hook( probe => sub { die "fail"; }, ); } else { Carp::croak("usage: plugin 'Test::Mock' => ( probe => $probe ); where $probe is one of share, system or die"); } } if(my $download = $self->download) { $download = { 'foo-1.00.tar.gz' => _tarball() } unless ref $download eq 'HASH'; $meta->register_hook( download => sub { my($build) = @_; _fs($build, $download, 1); }, ); } if(my $extract = $self->extract) { $extract = { 'foo-1.00' => { 'configure' => _tarball_configure(), 'foo.c' => _tarball_foo_c(), }, } unless ref $extract eq 'HASH'; $meta->register_hook( extract => sub { my($build) = @_; _fs($build, $extract); }, ); } if(my $build = $self->build) { $build = [ { 'foo.o', => _build_foo_o(), 'libfoo.a' => _build_libfoo_a(), }, { 'lib' => { 'libfoo.a' => _build_libfoo_a(), 'pkgconfig' => { 'foo.pc' => sub { my($build) = @_; "prefix=$CWD\n" . "exec_prefix=\${prefix}\n" . "libdir=\${prefix}/lib\n" . "includedir=\${prefix}/include\n" . "\n" . "Name: libfoo\n" . "Description: libfoo\n" . "Version: 1.0.0\n" . "Cflags: -I\${includedir}\n" . "Libs: -L\${libdir} -lfoo\n"; }, }, }, }, ] unless ref $build eq 'ARRAY'; my($build_dir, $install_dir) = @$build; $meta->register_hook( build => sub { my($build) = @_; _fs($build, $build_dir); local $CWD = $build->install_prop->{prefix}; _fs($build, $install_dir); }, ); } if(my $gather = $self->gather) { $meta->register_hook( $_ => sub { my($build) = @_; if(ref $gather eq 'HASH') { foreach my $key (keys %$gather) { $build->runtime_prop->{$key} = $gather->{$key}; } } else { my $prefix = $build->runtime_prop->{prefix}; $build->runtime_prop->{cflags} = "-I$prefix/include"; $build->runtime_prop->{libs} = "-L$prefix/lib -lfoo"; } }, ) for qw( gather_share gather_system ); } if(my $cd = $self->check_digest) { $meta->register_hook( check_digest => ref($cd) eq 'CODE' ? $cd : sub { my($build, $file, $algorithm, $digest) = @_; if($algorithm ne 'FOO92') { return 'FAKE'; } if($digest eq 'deadbeaf') { return 1; } else { die "Digest FAKE does not match: got deadbeaf, expected $digest"; } } ); $meta->register_hook( check_download => sub { my($build) = @_; my $path = $build->install_prop->{download}; if(defined $path) { $build->check_digest($path); } }, ); } } sub _fs { my($build, $hash, $download) = @_; foreach my $key (sort keys %$hash) { my $val = $hash->{$key}; if(ref $val eq 'HASH') { mkdir $key; local $CWD = $key; _fs($build,$val); } elsif(ref $val eq 'CODE') { my $path = Path::Tiny->new($key)->absolute; $path->spew_raw($val->($build)); if($download) { $build->install_prop->{download_detail}->{"$path"}->{protocol} = 'file'; $build->install_prop->{download_detail}->{"$path"}->{digest} = [ FAKE => 'deadbeaf' ]; } } elsif(defined $val) { my $path = Path::Tiny->new($key)->absolute; $path->spew_raw($val); if($download) { $build->install_prop->{download_detail}->{"$path"}->{protocol} = 'file'; $build->install_prop->{download_detail}->{"$path"}->{digest} = [ FAKE => 'deadbeaf' ]; } } } } sub _tarball { return unpack 'u', <<'EOF'; M'XL(`+DM@5@``^V4P4K$,!"&>YZGF-V]J*SM9#=)#RN^B'BHV;0)U`32U(OX M[D;0*LJREZVRF.\R?TA@)OS\TWI_S4JBJI@/(JJ%P%19+>AKG4"V)4Z;C922 M(;T=6(%BQIDFQB$V(8WB^]X.W>%WQ^[?_S'5,Z']\%]YU]IN#/KT/8[ZO^6? M_B=-C-=<%$BG'^4G_]S_U:)ZL*X:#(!6QN/26(Q&![W M'BD/DO/#^6W@)2^*3":3.3]>`:%LBYL`#@`` ` EOF } sub _tarball_configure { return unpack 'u', <<'EOF'; <(R$O8FEN+W-H"@IE8VAO(")H:2!T:&5R92(["@`` ` EOF } sub _tarball_foo_c { return unpack 'u', <<'EOF'; M(VEN8VQU9&4@/'-T9&EO+F@^"@II;G0*;6%I;BAI;G0@87)G8RP@8VAA'0`````````````7U]415A4```````````` M````````````"`````````#0`0``!`````````````````0`@``````````` M`````%]?8V]M<&%C=%]U;G=I;F1?7TQ$````````````````"``````````@ M`````````-@!```#````.`(```$````````"````````````````7U]E:%]F ME(``7@0`1`,!PB0`0``)````!P```"X____ M_____P@``````````$$.$(8"0PT&```````````````!```&`0````\!```` /``````````!?;6%I;@`` ` EOF } sub _build_libfoo_a { return unpack 'u', <<'EOF'; M(3QA ( probe => 'share', download => 1, extract => 1, build => 1, gather => 1, ); =head1 DESCRIPTION This plugin is used for testing L plugins. Usually you only want to test one or two phases in an L for your plugin, but you still have to have a fully formed L that contains all required phases. This plugin lets you fill in the other phases with the appropriate hooks. This is usually better than using real plugins which may pull in additional dynamic requirements that you do not want to rely on at test time. =head1 PROPERTIES =head2 probe plugin 'Test::Mock' => ( probe => $probe, ); Override the probe behavior by one of the following: =over =item share For a C build. =item system For a C build. =item die To throw an exception in the probe hook. This will usually cause L to try the next probe hook, if available, or to assume a C install. =back =head2 download plugin 'Test::Mock' => ( download => \%fs_spec, ); plugin 'Test::Mock' => ( download => 1, ); Mock out a download. The C<%fs_spec> is a hash where the hash values are directories and the string values are files. This a spec like this: plugin 'Test::Mock' => ( download => { 'foo-1.00' => { 'README.txt' => "something to read", 'foo.c' => "#include \n", "int main() {\n", " printf(\"hello world\\n\");\n", "}\n", } }, ); Would generate two files in the directory 'foo-1.00', a C and a C file named C. The default, if you provide a true non-hash value is to generate a single tarball with the name C. =head2 extract plugin 'Test::Mock' => ( extract => \%fs_spec, ); plugin 'Test::Mock' => ( extract => 1, ); Similar to C above, but for the C phase. =head2 build plugin 'Test::Mock' => ( build => [ \%fs_spec_build, \%fs_spec_install ], ); plugin 'Test::Mock' => ( build => 1, ); =head2 gather plugin 'Test::Mock' => ( gather => \%runtime_prop, ); plugin 'Test::Mock' => ( gather => 1, ); This adds a gather hook (for both C and C) that adds the given runtime properties, or if a true non-hash value is provided, some reasonable runtime properties for testing. =head2 check_digest plugin 'Test::Mock' => ( check_digest => 1, # the default ); This adds a check_digest hook that uses fake algorithm FAKE that hashes everything to C. The mock download above will set the digest for download_details so that this will pass the signature check. plugin 'Test::Mock' => ( check_digest => sub { my($build, $file, $algo, $digest) = @_; ... }, ); If you give it a code reference then you can write your own faux digest. See the L in L for details. =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Download/Negotiate.pm000044400000020736152346246310013101 0ustar00package Alien::Build::Plugin::Download::Negotiate; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; use Alien::Build::Util qw( _has_ssl ); use Carp (); # ABSTRACT: Download negotiation plugin our $VERSION = '2.74'; # VERSION has '+url' => undef; has 'filter' => undef; has 'version' => undef; has 'ssl' => 0; has 'passive' => 0; has 'scheme' => undef; has 'bootstrap_ssl' => 0; has 'prefer' => 1; has 'decoder' => undef; sub pick { my($self) = @_; my($fetch, @decoders) = $self->_pick; if($self->decoder) { @decoders = ref $self->decoder ? @{ $self->decoder } : ($self->decoder); } ($fetch, @decoders); } sub _pick_decoder { my($self) = @_; if(eval { require Mojo::DOM58; Mojo::DOM58->VERSION(1.00); 1 }) { return "Decode::Mojo" } elsif(eval { require Mojo::DOM; require Mojolicious; Mojolicious->VERSION('7.00'); 1 }) { return "Decode::Mojo" } elsif(eval { require HTML::LinkExtor; 1; }) { return "Decode::HTML" } else { return "Decode::Mojo" } } sub _pick { my($self) = @_; $self->scheme( $self->url !~ m!(ftps?|https?|file):!i ? 'file' : $self->url =~ m!^([a-z]+):!i ) unless defined $self->scheme; if($self->scheme eq 'https' || ($self->scheme eq 'http' && $self->ssl)) { if($self->bootstrap_ssl && ! _has_ssl) { return (['Fetch::CurlCommand','Fetch::Wget'], __PACKAGE__->_pick_decoder); } elsif(_has_ssl) { return ('Fetch::HTTPTiny', __PACKAGE__->_pick_decoder); } elsif(do { require Alien::Build::Plugin::Fetch::CurlCommand; Alien::Build::Plugin::Fetch::CurlCommand->protocol_ok('https') }) { return ('Fetch::CurlCommand', __PACKAGE__->_pick_decoder); } else { return ('Fetch::HTTPTiny', __PACKAGE__->_pick_decoder); } } elsif($self->scheme eq 'http') { return ('Fetch::HTTPTiny', __PACKAGE__->_pick_decoder); } elsif($self->scheme eq 'ftp') { if($ENV{ftp_proxy} || $ENV{all_proxy}) { return $self->scheme =~ /^ftps?/ ? ('Fetch::LWP', 'Decode::DirListing', __PACKAGE__->_pick_decoder) : ('Fetch::LWP', __PACKAGE__->_pick_decoder); } else { return ('Fetch::NetFTP'); } } elsif($self->scheme eq 'file') { return ('Fetch::Local'); } else { die "do not know how to handle scheme @{[ $self->scheme ]} for @{[ $self->url ]}"; } } sub init { my($self, $meta) = @_; unless(defined $self->url) { if(defined $meta->prop->{start_url}) { $self->url($meta->prop->{start_url}); } else { Carp::croak "url is a required property unless you use the start_url directive"; } } $meta->add_requires('share' => 'Alien::Build::Plugin::Download::Negotiate' => '0.61') if $self->passive; $meta->prop->{plugin_download_negotiate_default_url} = $self->url; my($fetch, @decoders) = $self->pick; $fetch = [ $fetch ] unless ref $fetch; foreach my $fetch (@$fetch) { my @args; push @args, ssl => $self->ssl; # For historical reasons, we pass the URL into older fetch plugins, because # this used to be the interface. Using start_url is now preferred! push @args, url => $self->url if $fetch =~ /^Fetch::(HTTPTiny|LWP|Local|LocalDir|NetFTP|CurlCommand)$/; push @args, passive => $self->passive if $fetch eq 'Fetch::NetFTP'; push @args, bootstrap_ssl => $self->bootstrap_ssl if $self->bootstrap_ssl; $meta->apply_plugin($fetch, @args); } if($self->version) { $meta->apply_plugin($_) for @decoders; if(defined $self->prefer && ref($self->prefer) eq 'CODE') { $meta->add_requires('share' => 'Alien::Build::Plugin::Download::Negotiate' => '1.30'); $meta->register_hook( prefer => $self->prefer, ); } elsif($self->prefer) { $meta->apply_plugin('Prefer::SortVersions', (defined $self->filter ? (filter => $self->filter) : ()), version => $self->version, ); } else { $meta->add_requires('share' => 'Alien::Build::Plugin::Download::Negotiate' => '1.30'); } } } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Download::Negotiate - Download negotiation plugin =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; share { start_url 'http://ftp.gnu.org/gnu/make'; plugin 'Download' => ( filter => qr/^make-.*\.tar\.gz$/, version => qr/([0-9\.]+)/, ); }; =head1 DESCRIPTION This is a negotiator plugin for downloading packages from the internet. This plugin picks the best Fetch, Decode and Prefer plugins to do the actual work. Which plugins are picked depend on the properties you specify, your platform and environment. It is usually preferable to use a negotiator plugin rather than the Fetch, Decode and Prefer plugins directly from your L. =head1 PROPERTIES =head2 url [DEPRECATED] use C instead. The Initial URL for your package. This may be a directory listing (either in HTML or ftp listing format) or the final tarball intended to be downloaded. =head2 filter This is a regular expression that lets you filter out files that you do not want to consider downloading. For example, if the directory listing contained tarballs and readme files like this: foo-1.0.0.tar.gz foo-1.0.0.readme You could specify a filter of C to make sure only tarballs are considered for download. =head2 version Regular expression to parse out the version from a filename. The regular expression should store the result in C<$1>. Note: if you provide a C property, this plugin will assume that you will be downloading an initial index to select package downloads from. Depending on the protocol (and typically this is the case for http and HTML) that may bring in additional dependencies. If start_url points to a tarball or other archive directly (without needing to do through an index selection process), it is recommended that you not specify this property. =head2 ssl If your initial URL does not need SSL, but you know ahead of time that a subsequent request will need it (for example, if your directory listing is on C, but includes links to C URLs), then you can set this property to true, and the appropriate Perl SSL modules will be loaded. =head2 passive If using FTP, attempt a passive mode transfer first, before trying an active mode transfer. =head2 bootstrap_ssl If set to true, then the download negotiator will avoid using plugins that have a dependency on L, or other Perl SSL modules. The intent for this option is to allow OpenSSL to be alienized and be a useful optional dependency for L. The implementation may improve over time, but as of this writing, this option relies on you having a working C or C with SSL support in your C. =head2 prefer How to sort candidates for selection. This should be one of three types of values: =over 4 =item code reference This will be used as the prefer hook. =item true value Use L. =item false value Don't set any preference at all. A hook must be installed, or another prefer plugin specified. =back =head2 decoder Override the detected decoder. =head1 METHODS =head2 pick my($fetch, @decoders) = $plugin->pick; Returns the fetch plugin and any optional decoders that should be used. =head1 SEE ALSO L, L L, L, L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Download/GitLab.pm000044400000013513152346246310012317 0ustar00package Alien::Build::Plugin::Download::GitLab; use strict; use warnings; use 5.008004; use Carp qw( croak ); use URI; use JSON::PP qw( decode_json ); use URI::Escape qw( uri_escape ); use Alien::Build::Plugin; use File::Basename qw( basename ); use Path::Tiny qw( path ); # ABSTRACT: Alien::Build plugin to download from GitLab our $VERSION = '0.01'; # VERSION has gitlab_host => 'https://gitlab.com'; has gitlab_user => undef; has gitlab_project => undef; has type => 'source'; # source or link has format => 'tar.gz'; has version_from => 'tag_name'; # tag_name or name has convert_version => undef; has link_name => undef; sub init { my($self, $meta) = @_; croak("No gitlab_user provided") unless defined $self->gitlab_user; croak("No gitlab_project provided") unless defined $self->gitlab_project; croak("Don't set set a start_url with the Download::GitLab plugin") if defined $meta->prop->{start_url}; $meta->add_requires('configure' => 'Alien::Build::Plugin::Download::GitLab' => 0 ); my $url = URI->new($self->gitlab_host); $url->path("/api/v4/projects/@{[ uri_escape(join '/', $self->gitlab_user, $self->gitlab_project) ]}/releases"); $meta->prop->{start_url} ||= "$url"; $meta->apply_plugin('Download'); $meta->apply_plugin('Extract', format => $self->format ); # we assume that GitLab returns the releases in reverse # chronological order. $meta->register_hook( prefer => sub { my($build, $res) = @_; return $res; }, ); croak "type must be one of source or link" if $self->type !~ /^(source|link)$/; croak "version_from must be one of tag_name or name" if $self->version_from !~ /^(tag_name|name)$/; ## TODO insert tokens as header if possible ## This may help with rate limiting (or if not then don't bother) # curl --header "PRIVATE-TOKEN: " "https://gitlab.example.com/api/v4/projects/24/releases" $meta->around_hook( fetch => sub { my $orig = shift; my($build, $url, @the_rest) = @_; # only modify the response if we are using the GitLab API # to get the release list return $orig->($build, $url, @the_rest) if defined $url && $url ne $meta->prop->{start_url}; my $res = $orig->($build, $url, @the_rest); my $res2 = { type => 'list', list => [], }; $res2->{protocol} = $res->{protocol} if exists $res->{protocol}; my $rel; if($res->{content}) { $rel = decode_json $res->{content}; } elsif($res->{path}) { $rel = decode_json path($res->{path})->slurp_raw; } else { croak("malformed response object: no content or path"); } foreach my $release (@$rel) { my $version = $self->version_from eq 'name' ? $release->{name} : $release->{tag_name}; $version = $self->convert_version->($version) if $self->convert_version; if($self->type eq 'source') { foreach my $source (@{ $release->{assets}->{sources} }) { next unless $source->{format} eq $self->format; my $url = URI->new($source->{url}); my $filename = basename $url->path; push @{ $res2->{list} }, { filename => $filename, url => $source->{url}, version => $version, }; } } else # link { foreach my $link (@{ $release->{assets}->{links} }) { my $url = URI->new($link->{url}); my $filename => basename $url->path; if($self->link_name) { next unless $filename =~ $self->link_name; } push @{ $res2->{list} }, { filename => $filename, url => $link->{url}, version => $version, }; } } } return $res2; }, ); } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Download::GitLab - Alien::Build plugin to download from GitLab =head1 VERSION version 0.01 =head1 SYNOPSIS use alienfile; plugin 'Download::GitLab' => ( gitlab_user => 'plicease', gitlab_project => 'dontpanic', ); =head1 DESCRIPTION This plugin is designed for downloading assets from a GitLab instance. =head1 PROPERTIES =head2 gitlab_host The host to fetch from L by default. =head2 gitlab_user The user to fetch from. =head2 gitlab_project The project to fetch from. =head2 type The asset type to fetch. This must be one of C or C. =head2 format The expected format of the asset. This should be one that L understands. The default is C. =head2 version_from Where to compute the version from. This should be one of C or C. The default is C. =head2 convert_version This is an optional code reference, which can be used to modify the version. For example, if tags have a C prefix you could remove it like so: plugin 'Download::GitLab' => ( gitlab_user => 'plicease', gitlab_project => 'dontpanic', convert_version => sub { my $version = shift; $version =~ s/^v//; return $version; }, ); =head2 link_name For C types, this is a regular expression that filters the asset filenames. For example, if there are multiple archive formats provided, you can get just the gzip'd tarball by setting this to C. =head1 SEE ALSO =over 4 =item L =item L =item L =item L =back =head1 AUTHOR Graham Ollis =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Decode.pod000044400000004771152346246310010745 0ustar00# PODNAME: Alien::Build::Plugin::Decode # ABSTRACT: Decode Alien::Build plugins # VERSION __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Decode - Decode Alien::Build plugins =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; plugin 'Decode::HTML'; plugin 'Decode::DirListing'; =head1 DESCRIPTION Decode plugins decode HTML and FTP file listings. Normally you will want to use the L plugin which will automatically load the appropriate Decode plugins. =over 4 =item L Default decoder for FTP file listings, that uses the pure-perl L. =item L Another decoder for FTP file listings, that uses the XS module L. =item L Older decoder for HTML file listings, which uses the XS module L. This used to be the default decoder until L version 1.75. In some cases, this will be used as the HTML decoder if you configure with L prior to 1.75 and but upgrade to a more recent version for the build stage of your L =item L Newer decoder for HTML file listings, which uses the pure-perl L or L. This became the default decoder at L version 1.75. =back =head1 SEE ALSO L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Extract/CommandLine.pm000044400000032531152346246310013207 0ustar00package Alien::Build::Plugin::Extract::CommandLine; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; use Path::Tiny (); use File::Which (); use File::chdir; use File::Temp qw( tempdir ); use Capture::Tiny qw( capture_merged ); # ABSTRACT: Plugin to extract an archive using command line tools our $VERSION = '2.74'; # VERSION has '+format' => 'tar'; sub gzip_cmd { _which('gzip') ? 'gzip' : undef; } sub _which { scalar File::Which::which(@_) } sub bzip2_cmd { _which('bzip2') ? 'bzip2' : undef; } sub xz_cmd { _which('xz') ? 'xz' : undef; } { my $bsd_tar; # Note: GNU tar can be iffy to very bad on windows, where absolute # paths get confused with remote tars. We used to assume that 'tar.exe' # is borked on Windows, but recent versions of Windows 10 come bundled # with bsdtar (libarchive) named 'tar.exe', and we should definitely # prefer that to ptar. sub _windows_tar_is_bsdtar { return 1 if $^O ne 'MSWin32'; return $bsd_tar if defined $bsd_tar; my($out) = capture_merged { system 'tar', '--version'; }; return $bsd_tar = $out =~ /bsdtar/ ? 1 : 0 } } sub tar_cmd { _which('bsdtar') ? 'bsdtar' # Slowlaris /usr/bin/tar doesn't seem to like pax global header # but seems to have gtar in the path by default, which is okay with it : $^O eq 'solaris' && _which('gtar') ? 'gtar' # See note above for Windows logic. : _which('tar') && _windows_tar_is_bsdtar() ? 'tar' : _which('ptar') ? 'ptar' : undef; }; sub unzip_cmd { if($^O eq 'MSWin32' && _which('tar') && _windows_tar_is_bsdtar()) { (_which('tar'), 'xf'); } else { _which('unzip') ? 'unzip' : undef; } } sub _run { my(undef, $build, @cmd) = @_; $build->log("+ @cmd"); system @cmd; die "execute failed" if $?; } sub _cp { my(undef, $build, $from, $to) = @_; require File::Copy; $build->log("copy $from => $to"); File::Copy::cp($from, $to) || die "unable to copy: $!"; } sub _mv { my(undef, $build, $from, $to) = @_; $build->log("move $from => $to"); rename($from, $to) || die "unable to rename: $!"; } sub _dcon { my($self, $src) = @_; my $name; my $cmd; if($src =~ /\.(gz|tgz|Z|taz)$/) { $self->gzip_cmd(_which('gzip')) unless defined $self->gzip_cmd; if($src =~ /\.(gz|tgz)$/) { $cmd = $self->gzip_cmd unless $self->_tar_can('tar.gz'); } elsif($src =~ /\.(Z|taz)$/) { $cmd = $self->gzip_cmd unless $self->_tar_can('tar.Z'); } } elsif($src =~ /\.(bz2|tbz)$/) { $self->bzip2_cmd(_which('bzip2')) unless defined $self->bzip2_cmd; $cmd = $self->bzip2_cmd unless $self->_tar_can('tar.bz2'); } elsif($src =~ /\.(xz|txz)$/) { $self->xz_cmd(_which('xz')) unless defined $self->xz_cmd; $cmd = $self->xz_cmd unless $self->_tar_can('tar.xz'); } if($cmd && $src =~ /\.(gz|bz2|xz|Z)$/) { $name = $src; $name =~ s/\.(gz|bz2|xz|Z)$//g; } elsif($cmd && $src =~ /\.(tgz|tbz|txz|taz)$/) { $name = $src; $name =~ s/\.(tgz|tbz|txz|taz)$/.tar/; } ($name,$cmd); } sub handles { my($class, $ext) = @_; my $self = ref $class ? $class : __PACKAGE__->new; $ext = 'tar.Z' if $ext eq 'taz'; $ext = 'tar.gz' if $ext eq 'tgz'; $ext = 'tar.bz2' if $ext eq 'tbz'; $ext = 'tar.xz' if $ext eq 'txz'; return 1 if $ext eq 'tar.gz' && $self->_tar_can('tar.gz'); return 1 if $ext eq 'tar.Z' && $self->_tar_can('tar.Z'); return 1 if $ext eq 'tar.bz2' && $self->_tar_can('tar.bz2'); return 1 if $ext eq 'tar.xz' && $self->_tar_can('tar.xz'); return 0 if $ext =~ s/\.(gz|Z)$// && (!$self->gzip_cmd); return 0 if $ext =~ s/\.bz2$// && (!$self->bzip2_cmd); return 0 if $ext =~ s/\.xz$// && (!$self->xz_cmd); return 1 if $ext eq 'tar' && $self->_tar_can('tar'); return 1 if $ext eq 'zip' && $self->_tar_can('zip'); return 0; } sub available { my(undef, $ext) = @_; # this is actually the same as handles __PACKAGE__->handles($ext); } sub init { my($self, $meta) = @_; if($self->format eq 'tar.xz' && !$self->handles('tar.xz')) { $meta->add_requires('share' => 'Alien::xz' => '0.06'); } elsif($self->format eq 'tar.bz2' && !$self->handles('tar.bz2')) { $meta->add_requires('share' => 'Alien::Libbz2' => '0.22'); } elsif($self->format =~ /^tar\.(gz|Z)$/ && !$self->handles($self->format)) { $meta->add_requires('share' => 'Alien::gzip' => '0.03'); } elsif($self->format eq 'zip' && !$self->handles('zip')) { $meta->add_requires('share' => 'Alien::unzip' => '0'); } $meta->register_hook( extract => sub { my($build, $src) = @_; my($dcon_name, $dcon_cmd) = _dcon($self, $src); if($dcon_name) { unless($dcon_cmd) { die "unable to decompress $src"; } # if we have already decompressed, then keep it. unless(-f $dcon_name) { # we don't use pipes, because that may not work on Windows. # keep the original archive, in case another extract # plugin needs it. keep the decompressed archive # in case WE need it again. my $src_tmp = Path::Tiny::path($src) ->parent ->child('x'.Path::Tiny::path($src)->basename); my $dcon_tmp = Path::Tiny::path($dcon_name) ->parent ->child('x'.Path::Tiny::path($dcon_name)->basename); $self->_cp($build, $src, $src_tmp); $self->_run($build, $dcon_cmd, "-d", $src_tmp); $self->_mv($build, $dcon_tmp, $dcon_name); } $src = $dcon_name; } if($src =~ /\.zip$/i) { $self->_run($build, $self->unzip_cmd, $src); } elsif($src =~ /\.tar/ || $src =~ /(\.tgz|\.tbz|\.txz|\.taz)$/i) { $self->_run($build, $self->tar_cmd, '-xf', $src); } else { die "not sure of archive type from extension"; } } ); } my %tars; sub _tar_can { my($self, $ext) = @_; unless(%tars) { my $name = ''; local $_; # to avoid dynamically scoped read-only $_ from upper scopes while(my $line = ) { if($line =~ /^\[ (.*) \]$/) { $name = $1; } else { $tars{$name} .= $line; } } foreach my $key (keys %tars) { $tars{$key} = unpack "u", $tars{$key}; } } my $name = "xx.$ext"; return 0 unless $tars{$name}; local $CWD = tempdir( CLEANUP => 1 ); my $cleanup = sub { my $save = $CWD; unlink $name; unlink 'xx.txt'; $CWD = '..'; rmdir $save; }; Path::Tiny->new($name)->spew_raw($tars{$name}); my @cmd = ($self->tar_cmd, 'xf', $name); if($ext eq 'zip') { @cmd = ($self->unzip_cmd, $name); } my(undef, $exit) = capture_merged { system(@cmd); $?; }; if($exit) { $cleanup->(); return 0; } my $content = eval { Path::Tiny->new('xx.txt')->slurp }; $cleanup->(); return defined $content && $content eq "xx\n"; } 1; =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Extract::CommandLine - Plugin to extract an archive using command line tools =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; plugin 'Extract::CommandLine' => ( format => 'tar.gz', ); =head1 DESCRIPTION Note: in most case you will want to use L instead. It picks the appropriate Extract plugin based on your platform and environment. In some cases you may need to use this plugin directly instead. This plugin extracts from an archive in various formats using command line tools. =head1 PROPERTIES =head2 format Gives a hint as to the expected format. =head2 gzip_cmd The C command, if available. C if not available. =head2 bzip2_cmd The C command, if available. C if not available. =head2 xz_cmd The C command, if available. C if not available. =head2 tar_cmd The C command, if available. C if not available. =head2 unzip_cmd The C command, if available. C if not available. =head1 METHODS =head2 handles Alien::Build::Plugin::Extract::CommandLine->handles($ext); $plugin->handles($ext); Returns true if the plugin is able to handle the archive of the given format. =head2 available Alien::Build::Plugin::Extract::CommandLine->available($ext); Returns true if the plugin is available to extract without installing anything new. =head1 SEE ALSO L, L, L, L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut __DATA__ [ xx.tar ] M>'@N='AT```````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````#`P,#8T-"``,#`P-S8U(``P,#`P,C0@`#`P,#`P,#`P,#`S M(#$S-#,U,#0S-#(R(#`Q,C`H````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` 7```````````````````````````````` [ xx.tar.Z ] M'YV0>/"XH(.'#H"#"!,J7,BPH<.'$"-*1`BCH@T:-$``J`CCAHT:&CG"D)%Q MH\B3,T#$F$%C1@T8+6G(D`$"1@P9-V#,`%!SHL^?0(,*!5!G#ITPO8,.*'1I0P=BS:-.J7//JWD#0)SI*Z'R%H*J"&3@H]P@J>U$F5BMHOC`$L-"8C!(V I"`'?*WA:(9*4U)@4)+"(V%.G]#W(_E6B'J8G]D`/Q=R13A0D%(,+ID`` [ xx.tar.gz ] M'XL("!)'=%P``WAX+G1A<@"KJ-`KJ2AAH"DP,#`P,S%1`-'F9J9@VL`(PH<" M8P5#8Q-C4P,38Q,C(P4#0R-S`V,&!0/:.@L"2HM+$HN`3LG/RM#J@L E+0V/.1"/*,#I(0(J*K@&V@FC8!2,@E$P"@8````U:,3F``@````` [ xx.tar.xz ] M_3=Z6%H```3FUK1&`@`A`18```!T+^6CX`?_`&!=`#Q@M.AX.4O&N38V648. M[J6L\\<_[3M*R;CASOTX?B.F\V:^)+G;\YY4"!4MLF9`*\N40G=O+K,J0"NF M0VU7J%NN(A,R^DM8@/(_YGR5CAO+1CS_YNHE:,1!G%6L1\GT``"[$^?"O*"! 9`P`!?(`0````:OY*7K'$9_L"``````196@`` [ xx.zip ] M4$L#!`H``````%5V64X:^I"B`P````,````&`!P`>'@N='AT550)``,21W1< M$D=T7'5X"P`!!/4!```$%````'AX"E!+`0(>`PH``````%5V64X:^I"B`P`` M``,````&`!@```````$```"D@0````!X>"YT>'155`4``Q)'=%QU>`L``03U >`0``!!0```!02P4&``````$``0!,````0P`````` Build/Plugin/Extract/Negotiate.pm000044400000007335152346246310012744 0ustar00package Alien::Build::Plugin::Extract::Negotiate; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; use Alien::Build::Plugin::Extract::ArchiveTar; use Alien::Build::Plugin::Extract::ArchiveZip; use Alien::Build::Plugin::Extract::CommandLine; use Alien::Build::Plugin::Extract::Directory; # ABSTRACT: Extraction negotiation plugin our $VERSION = '2.74'; # VERSION has '+format' => 'tar'; sub init { my($self, $meta) = @_; my $format = $self->format; $format = 'tar.gz' if $format eq 'tgz'; $format = 'tar.bz2' if $format eq 'tbz'; $format = 'tar.xz' if $format eq 'txz'; my $plugin = $self->pick($format); $meta->apply_plugin($plugin, format => $format); $self; } sub pick { my(undef, $format) = @_; if($format =~ /^tar(\.(gz|bz2))?$/) { if(Alien::Build::Plugin::Extract::ArchiveTar->available($format)) { return 'Extract::ArchiveTar'; } else { return 'Extract::CommandLine'; } } elsif($format eq 'zip') { # Archive::Zip is not that reliable. But if it is already installed it is probably working if(Alien::Build::Plugin::Extract::ArchiveZip->available($format)) { return 'Extract::ArchiveZip'; } # If it isn't available, then use the command-line unzip. Alien::unzip will be used # as necessary in environments where it isn't already installed. else { return 'Extract::CommandLine'; } } elsif($format eq 'tar.xz' || $format eq 'tar.Z') { return 'Extract::CommandLine'; } elsif($format eq 'd') { return 'Extract::Directory'; } elsif($format eq 'f') { return 'Extract::File'; } else { die "do not know how to handle format: $format"; } } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Extract::Negotiate - Extraction negotiation plugin =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; plugin 'Extract' => ( format => 'tar.gz', ); =head1 DESCRIPTION This is a negotiator plugin for extracting packages downloaded from the internet. This plugin picks the best Extract plugin to do the actual work. Which plugins are picked depend on the properties you specify, your platform and environment. It is usually preferable to use a negotiator plugin rather than using a specific Extract Plugin from your L. =head1 PROPERTIES =head2 format The expected format for the download. Possible values include: C, C, C, C, C, C. =head1 METHODS =head2 pick my $name = Alien::Build::Plugin::Extract::Negotiate->pick($format); Returns the name of the best plugin for the given format. =head1 SEE ALSO L, L, L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Extract/ArchiveZip.pm000044400000006170152346246310013065 0ustar00package Alien::Build::Plugin::Extract::ArchiveZip; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; # ABSTRACT: Plugin to extract a tarball using Archive::Zip our $VERSION = '2.74'; # VERSION has '+format' => 'zip'; sub handles { my($class, $ext) = @_; return 1 if $ext eq 'zip'; return 0; } sub available { my(undef, $ext) = @_; !! ( $ext eq 'zip' && eval { require Archive::Zip; 1} ); } sub init { my($self, $meta) = @_; $meta->add_requires('share' => 'Archive::Zip' => 0); $meta->register_hook( extract => sub { my($build, $src) = @_; my $zip = Archive::Zip->new; $zip->read($src); $zip->extractTree; } ); } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Extract::ArchiveZip - Plugin to extract a tarball using Archive::Zip =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; plugin 'Extract::ArchiveZip' => ( format => 'zip', ); =head1 DESCRIPTION Note: in most case you will want to use L instead. It picks the appropriate Extract plugin based on your platform and environment. In some cases you may need to use this plugin directly instead. B: Seriously do NOT use this plugin! L is pretty unreliable and breaks all-the-time. If you use the negotiator plugin mentioned above, then it will prefer installing L, which is much more reliable than L. This plugin extracts from an archive in zip format using L. =head2 format Gives a hint as to the expected format. This should always be C. =head1 METHODS =head2 handles Alien::Build::Plugin::Extract::ArchiveZip->handles($ext); $plugin->handles($ext); Returns true if the plugin is able to handle the archive of the given format. =head2 available Alien::Build::Plugin::Extract::ArchiveZip->available($ext); Returns true if the plugin has what it needs right now to extract from the given format =head1 SEE ALSO L, L, L, L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Extract/Directory.pm000044400000006620152346246310012765 0ustar00package Alien::Build::Plugin::Extract::Directory; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; use Alien::Build::Util qw( _mirror ); use Path::Tiny (); # ABSTRACT: Plugin to extract a downloaded directory to a build directory our $VERSION = '2.74'; # VERSION has '+format' => 'd'; sub handles { my(undef, $ext) = @_; $ext eq 'd' ? 1 : (); } sub available { my(undef, $ext) = @_; __PACKAGE__->handles($ext); } sub init { my($self, $meta) = @_; $meta->register_hook( extract => sub { my($build, $src) = @_; die "not a directory: $src" unless -d $src; if($build->meta_prop->{out_of_source}) { $build->install_prop->{extract} = Path::Tiny->new($src)->absolute->stringify; } else { my $dst = Path::Tiny->new('.')->absolute; # Please note: _mirror and Alien::Build::Util are ONLY # allowed to be used by core plugins. If you are writing # a non-core plugin it may be removed. That is why it # is private. _mirror $src => $dst, { verbose => 1 }; } } ); } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Extract::Directory - Plugin to extract a downloaded directory to a build directory =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; plugin 'Extract::Directory'; =head1 DESCRIPTION Some Download or Fetch plugins may produce a directory instead of an archive file. This plugin is used to mirror the directory from the Download step into a fresh directory in the Extract step. An example of when you might use this plugin is if you were using the C command in the Download step, which results in a directory hierarchy. =head1 PROPERTIES =head2 format Should always set to C (for directories). =head1 METHODS =head2 handles Alien::Build::Plugin::Extract::Directory->handles($ext); $plugin->handles($ext); Returns true if the plugin is able to handle the archive of the given format. Only returns true for C (for directory). =head2 available Alien::Build::Plugin::Extract::Directory->available($ext); $plugin->available($ext); Returns true if the plugin can extract the given format with what is already installed. =head1 SEE ALSO L, L, L, L, L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Extract/ArchiveTar.pm000044400000010717152346246310013053 0ustar00package Alien::Build::Plugin::Extract::ArchiveTar; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; use File::chdir; use File::Temp (); use Path::Tiny (); # ABSTRACT: Plugin to extract a tarball using Archive::Tar our $VERSION = '2.74'; # VERSION has '+format' => 'tar'; sub handles { my(undef, $ext) = @_; return 1 if $ext =~ /^(tar|tar.gz|tar.bz2|tbz|taz)$/; return 0; } sub available { my(undef, $ext) = @_; if($ext eq 'tar.gz') { return !! eval { require Archive::Tar; Archive::Tar->has_zlib_support }; } elsif($ext eq 'tar.bz2') { return !! eval { require Archive::Tar; Archive::Tar->has_bzip2_support && __PACKAGE__->_can_bz2 }; } else { return $ext eq 'tar'; } } sub init { my($self, $meta) = @_; $meta->add_requires('share' => 'Archive::Tar' => 0); if($self->format eq 'tar.gz' || $self->format eq 'tgz') { $meta->add_requires('share' => 'IO::Zlib' => 0); } elsif($self->format eq 'tar.bz2' || $self->format eq 'tbz') { $meta->add_requires('share' => 'IO::Uncompress::Bunzip2' => 0); $meta->add_requires('share' => 'IO::Compress::Bzip2' => 0); } $meta->register_hook( extract => sub { my($build, $src) = @_; my $tar = Archive::Tar->new; $tar->read($src); $tar->extract; } ); } sub _can_bz2 { # even when Archive::Tar reports that it supports bz2, I can sometimes get this error: # 'Cannot read enough bytes from the tarfile', so lets just probe for actual support! my $dir = Path::Tiny->new(File::Temp::tempdir( CLEANUP => 1 )); eval { local $CWD = $dir; my $tarball = unpack "u", q{M0EIH.3%!62936=+(]$0``$A[D-$0`8!``7^``!!AI)Y`!```""``=!JGIH-(MT#0]0/2!**---&F@;4#0&:D;X?(6@JH(2<%'N$%3VHC-9E>S/N@"6&I*1@GNJNHCC2>$I5(<0BKR.=XBZ""HVZ;T,CV\LJ!K&*?9`#\7new('xx.tar.bz2')->spew_raw($tarball); require Archive::Tar; my $tar = Archive::Tar->new; $tar->read('xx.tar.bz2'); $tar->extract; my $content = Path::Tiny->new('xx.txt')->slurp; die unless $content && $content eq "xx\n"; }; my $error = $@; $dir->remove_tree; !$error; } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Extract::ArchiveTar - Plugin to extract a tarball using Archive::Tar =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; plugin 'Extract::ArchiveTar' => ( format => 'tar.gz', ); =head1 DESCRIPTION Note: in most case you will want to use L instead. It picks the appropriate Extract plugin based on your platform and environment. In some cases you may need to use this plugin directly instead. This plugin extracts from an archive in tarball format (optionally compressed by either gzip or bzip2) using L. =head1 PROPERTIES =head2 format Gives a hint as to the expected format. This helps make sure the prerequisites are set correctly, since compressed archives require extra Perl modules to be installed. =head1 METHODS =head2 handles Alien::Build::Plugin::Extract::ArchiveTar->handles($ext); $plugin->handles($ext); Returns true if the plugin is able to handle the archive of the given format. =head2 available Alien::Build::Plugin::Extract::ArchiveTar->available($ext); Returns true if the plugin has what it needs right now to extract from the given format =head1 SEE ALSO L, L, L, L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Extract/File.pm000044400000006212152346246310011675 0ustar00package Alien::Build::Plugin::Extract::File; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; use Alien::Build::Util qw( _mirror ); use Path::Tiny (); # ABSTRACT: Plugin to extract a downloaded file to a build directory our $VERSION = '2.74'; # VERSION has '+format' => 'f'; sub handles { my(undef, $ext) = @_; $ext eq 'f' ? 1 : (); } sub available { my(undef, $ext) = @_; __PACKAGE__->handles($ext); } sub init { my($self, $meta) = @_; $meta->register_hook( extract => sub { my($build, $src) = @_; die "not a file: $src" unless -f $src; $src = Path::Tiny->new($src)->absolute->parent;; my $dst = Path::Tiny->new('.')->absolute; # Please note: _mirror and Alien::Build::Util are ONLY # allowed to be used by core plugins. If you are writing # a non-core plugin it may be removed. That is why it # is private. $build->log("extracting $src => $dst"); _mirror $src => $dst, { verbose => 1 }; } ); } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Extract::File - Plugin to extract a downloaded file to a build directory =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; plugin 'Extract::File'; =head1 DESCRIPTION Some Download or Fetch plugins may produce a single file (usually an executable) instead of an archive file. This plugin is used to mirror the file from the Download step into a fresh directory in the Extract step. =head1 PROPERTIES =head2 format Should always set to C (for file). =head1 METHODS =head2 handles Alien::Build::Plugin::Extract::File->handles($ext); $plugin->handles($ext); Returns true if the plugin is able to handle the archive of the given format. Only returns true for C (for file). =head2 available Alien::Build::Plugin::Extract::File->available($ext); $plugin->available($ext); Returns true if the plugin can extract the given format with what is already installed. =head1 SEE ALSO L, L, L, L, L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Extract.pod000044400000004435152346246310011171 0ustar00# PODNAME: Alien::Build::Plugin::Extract # ABSTRACT: Extract Alien::Build plugins # VERSION __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Extract - Extract Alien::Build plugins =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile share { plugin 'Extract' => 'tar.gz'; }; =head1 DESCRIPTION Extract plugins extract packages that have been downloaded from the internet. Unless you are doing something unusual you will likely want to use the L plugin to select the best Extract plugin available. =over 4 =item L Extract using C. Typically also works with compressed tarballs like C. =item L Extract using L. =item L Extract using command line tools like C or C. =item L Extract a local directory. =item L "Extract" a single file. =item L Pick the best extract plugin based on the extension of the package archive. =back =head1 SEE ALSO L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Digest/SHA.pm000044400000004406152346246310011241 0ustar00package Alien::Build::Plugin::Digest::SHA; use strict; use warnings; use Alien::Build::Plugin; # ABSTRACT: Plugin to check SHA digest with Digest::SHA our $VERSION = '2.74'; # VERSION sub init { my($self, $meta) = @_; $meta->add_requires('configure' => 'Alien::Build' => "2.57" ); $meta->register_hook( check_digest => sub { my($build, $file, $algo, $expected_digest) = @_; return 0 unless $algo =~ /^SHA[0-9]+$/; my $sha = Digest::SHA->new($algo); return 0 unless defined $sha; if(defined $file->{content}) { $sha->add($file->{content}); } elsif(defined $file->{path}) { $sha->addfile($file->{path}, "b"); } else { die "unknown file type"; } my $actual_digest = $sha->hexdigest; return 1 if $expected_digest eq $actual_digest; die "@{[ $file->{filename} ]} SHA@{[ $sha->algorithm ]} digest does not match: got $actual_digest, expected $expected_digest"; }); } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Digest::SHA - Plugin to check SHA digest with Digest::SHA =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; plugin 'Digest::SHA'; =head1 DESCRIPTION This plugin is experimental. =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Digest/Negotiate.pm000044400000007451152346246310012550 0ustar00package Alien::Build::Plugin::Digest::Negotiate; use strict; use warnings; use Alien::Build::Plugin; # ABSTRACT: Plugin negotiator for cryptographic signatures our $VERSION = '2.74'; # VERSION has '+sig' => sub { {} }; has check_fetch => 1; has check_download => 1; has allow_listing => 1; sub init { my($self, $meta) = @_; $meta->add_requires('configure' => 'Alien::Build::Plugin::Digest::Negotiate' => "0" ); $meta->prop->{check_digest} = 1; my $sigs = $meta->prop->{digest} ||= {}; if(ref($self->sig) eq 'HASH') { foreach my $filename (keys %{ $self->sig }) { my $signature = $self->sig->{$filename}; my($algo) = @$signature; die "Unknown digest algorithm $algo" unless $algo =~ /^SHA(1|224|256|384|512|512224|512256)$/; # reportedly what is supported by Digest::SHA $sigs->{$filename} = $signature; } } elsif(ref($self->sig) eq 'ARRAY') { my $signature = $self->sig; my($algo) = @$signature; die "Unknown digest algorithm $algo" unless $algo =~ /^SHA(1|224|256|384|512|512224|512256)$/; # reportedly what is supported by Digest::SHA $sigs->{'*'} = $signature; } # In the future if this negotiator supports algorithms other # than SHA, we should probably ajust this to keep track of # which ones we actually need when we are looping through them # above. Also technically you could call this plugin without # any sigs, and we shouldn't in theory need to apply Digest::SHA, # but stuff won't work that way so that is a corner case we # are not going to worry about. $meta->apply_plugin('Digest::SHA'); $meta->around_hook( fetch => sub { my($orig, $build, @rest) = @_; my $res = $orig->($build, @rest); if($res->{type} eq 'file') { $build->check_digest($res); } else { die "listing fetch not allowed" unless $self->allow_listing; } $res; }, ) if $self->check_fetch; # Note that check_download hook is currently undocumented and # may change in the future. $meta->register_hook( check_download => sub { my($build) = @_; my $path = $build->install_prop->{download}; die "Checking cryptographic signatures on download only works for single archive" unless defined $path; $build->check_digest($path); }, ) if $self->check_download; } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Digest::Negotiate - Plugin negotiator for cryptographic signatures =head1 VERSION version 2.74 =head1 SYNOPSIS for a single file: use alienfile; plugin 'Digest' => [ SHA256 => $digest ]; or for multiple files: use alienfile; plugin 'Digest' => { file1 => [ SHA256 => $digest1 ], file2 => [ SHA256 => $digest2 ], }; =head1 DESCRIPTION This plugin is experimental. =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Digest/SHAPP.pm000044400000004564152346246310011506 0ustar00package Alien::Build::Plugin::Digest::SHAPP; use strict; use warnings; use Alien::Build::Plugin; # ABSTRACT: Plugin to check SHA digest with Digest::SHA::PurePerl our $VERSION = '2.74'; # VERSION sub init { my($self, $meta) = @_; $meta->add_requires('configure' => 'Alien::Build' => "2.57" ); $meta->add_requires('share' => 'Digest::SHA::PurePerl' => "0" ); $meta->register_hook( check_digest => sub { my($build, $file, $algo, $expected_digest) = @_; return 0 unless $algo =~ /^SHA[0-9]+$/; my $sha = Digest::SHA::PurePerl->new($algo); return 0 unless defined $sha; if(defined $file->{content}) { $sha->add($file->{content}); } elsif(defined $file->{path}) { $sha->addfile($file->{path}, "b"); } else { die "unknown file type"; } my $actual_digest = $sha->hexdigest; return 1 if $expected_digest eq $actual_digest; die "@{[ $file->{filename} ]} SHA@{[ $sha->algorithm ]} digest does not match: got $actual_digest, expected $expected_digest"; }); } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Digest::SHAPP - Plugin to check SHA digest with Digest::SHA::PurePerl =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; plugin 'Digest::SHAPP'; =head1 DESCRIPTION This plugin is experimental. =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Core.pod000044400000004202152346246310010437 0ustar00# PODNAME: Alien::Build::Plugin::Core # ABSTRACT: Core Alien::Build plugins # VERSION __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Core - Core Alien::Build plugins =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; # core plugins are already loaded =head1 DESCRIPTION Core plugins are special plugins that are always loaded, usually first. =over 4 =item L =item L This contains the default machinery for downloading packages, if no other download plugin or commands are provided. =item L =item L =item L Add interoperability with L =item L The machinery which allows you to override the type of install with the C environment variable. =item L =item L =back =head1 SEE ALSO L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Fetch/NetFTP.pm000044400000012767152346246310011551 0ustar00package Alien::Build::Plugin::Fetch::NetFTP; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; use Carp (); use File::Temp (); use Path::Tiny qw( path ); # ABSTRACT: Plugin for fetching files using Net::FTP our $VERSION = '2.74'; # VERSION has '+url' => ''; has ssl => 0; has passive => 0; sub init { my($self, $meta) = @_; $meta->prop->{start_url} ||= $self->url; $self->url($meta->prop->{start_url}); $self->url || Carp::croak('url is a required property'); $meta->add_requires('share' => 'Net::FTP' => 0 ); $meta->add_requires('share' => 'URI' => 0 ); $meta->add_requires('share' => 'Alien::Build::Plugin::Fetch::NetFTP' => '0.61') if $self->passive; $meta->register_hook( fetch => sub { my($build, $url, %options) = @_; $url ||= $self->url; $build->log("plugin Fetch::NetFTP does not support http_headers option") if $options{http_headers}; $url = URI->new($url); die "Fetch::NetFTP does not support @{[ $url->scheme ]}" unless $url->scheme eq 'ftp'; $build->log("trying passive mode FTP first") if $self->passive; my $ftp = _ftp_connect($url, $self->passive); my $path = $url->path; unless($path =~ m!/$!) { my(@parts) = split /\//, $path; my $filename = pop @parts; my $dir = join '/', @parts; my $path = eval { $ftp->cwd($dir) or die; my $tdir = File::Temp::tempdir( CLEANUP => 1); my $path = path("$tdir/$filename")->stringify; unless(eval { $ftp->get($filename, $path) }) # NAT problem? try to use passive mode { $ftp->quit; $build->log("switching to @{[ $self->passive ? 'active' : 'passive' ]} mode"); $ftp = _ftp_connect($url, !$self->passive); $ftp->cwd($dir) or die; $ftp->get($filename, $path) or die; } $path; }; if(defined $path) { return { type => 'file', filename => $filename, path => $path, protocol => 'ftp', }; } $path .= "/"; } $ftp->quit; $ftp = _ftp_connect($url, $self->passive); $ftp->cwd($path) or die "unable to fetch $url as either a directory or file"; my $list = eval { $ftp->ls }; unless(defined $list) # NAT problem? try to use passive mode { $ftp->quit; $build->log("switching to @{[ $self->passive ? 'active' : 'passive' ]} mode"); $ftp = _ftp_connect($url, !$self->passive); $ftp->cwd($path) or die "unable to fetch $url as either a directory or file"; $list = $ftp->ls; die "cannot list directory $path on $url" unless defined $list; } die "no files found at $url" unless @$list; $path .= '/' unless $path =~ /\/$/; return { type => 'list', protocol => 'ftp', list => [ map { my $filename = $_; my $furl = $url->clone; $furl->path($path . $filename); my %h = ( filename => $filename, url => $furl->as_string, ); \%h; } sort @$list, ], }; }); $self; } sub _ftp_connect { my $url = shift; my $is_passive = shift || 0; my $ftp = Net::FTP->new( $url->host, Port =>$url->port, Passive =>$is_passive, ) or die "error fetching $url: $@"; $ftp->login($url->user, $url->password) or die "error on login $url: @{[ $ftp->message ]}"; $ftp->binary; $ftp; } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Fetch::NetFTP - Plugin for fetching files using Net::FTP =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; share { start_url 'ftp://ftp.gnu.org/gnu/make'; plugin 'Fetch::NetFTP'; }; =head1 DESCRIPTION Note: in most case you will want to use L instead. It picks the appropriate fetch plugin based on your platform and environment. In some cases you may need to use this plugin directly instead. This fetch plugin fetches files and directory listings via the C, protocol using L. =head1 PROPERTIES =head2 url The initial URL to fetch. This may be a directory or the final file. =head2 ssl This property is for compatibility with other fetch plugins, but is not used. =head2 passive If set to true, try passive mode FIRST. By default it will try an active mode, then passive mode. =head1 SEE ALSO L, L, L, L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Fetch/Local.pm000044400000010263152346246310011470 0ustar00package Alien::Build::Plugin::Fetch::Local; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; use File::chdir; use Path::Tiny (); # ABSTRACT: Plugin for fetching a local file our $VERSION = '2.74'; # VERSION has '+url' => ''; has root => undef; has ssl => 0; sub init { my($self, $meta) = @_; $meta->prop->{start_url} ||= $self->url; $self->url($meta->prop->{start_url} || 'patch'); if($self->url =~ /^file:/) { $meta->add_requires('share' => 'URI' => 0 ); $meta->add_requires('share' => 'URI::file' => 0 ); $meta->add_requires('share' => 'URI::Escape' => 0 ); } { my $root = $self->root; if(defined $root) { $root = Path::Tiny->new($root)->absolute->stringify; } else { $root = "$CWD"; } $self->root($root); } $meta->register_hook( fetch => sub { my($build, $path, %options) = @_; $build->log("plugin Fetch::Local does not support http_headers option") if $options{http_headers}; $path ||= $self->url; if($path =~ /^file:/) { my $root = URI::file->new($self->root); my $url = URI->new_abs($path, $root); $path = URI::Escape::uri_unescape($url->path); $path =~ s{^/([a-z]:)}{$1}i if $^O eq 'MSWin32'; } $path = Path::Tiny->new($path)->absolute($self->root); if(-d $path) { return { type => 'list', protocol => 'file', list => [ map { { filename => $_->basename, url => $_->stringify } } sort { $a->basename cmp $b->basename } $path->children, ], }; } elsif(-f $path) { return { type => 'file', filename => $path->basename, path => $path->stringify, tmp => 0, protocol => 'file', }; } else { die "no such file or directory $path"; } }); } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Fetch::Local - Plugin for fetching a local file =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; share { start_url 'patch/libfoo-1.00.tar.gz'; plugin 'Fetch::Local'; }; =head1 DESCRIPTION Note: in most case you will want to use L instead. It picks the appropriate fetch plugin based on your platform and environment. In some cases you may need to use this plugin directly instead. This fetch plugin fetches files from the local file system. It is mostly useful if you intend to bundle packages (as tarballs or zip files) with your Alien. If you intend to bundle a source tree, use L. =head1 PROPERTIES =head2 url The initial URL to fetch. This may be a C style URL, or just the path on the local system. =head2 root The directory from which the URL should be relative. The default is usually reasonable. =head2 ssl This property is for compatibility with other fetch plugins, but is not used. =head1 SEE ALSO =over 4 =item L =item L =item L =item L =item L =item L =back =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Fetch/LWP.pm000044400000010411152346246310011073 0ustar00package Alien::Build::Plugin::Fetch::LWP; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; use Carp (); # ABSTRACT: Plugin for fetching files using LWP our $VERSION = '2.74'; # VERSION has '+url' => ''; has ssl => 0; sub init { my($self, $meta) = @_; $meta->add_requires('share' => 'LWP::UserAgent' => 0 ); $meta->prop->{start_url} ||= $self->url; $self->url($meta->prop->{start_url}); $self->url || Carp::croak('url is a required property'); if($self->url =~ /^https:/ || $self->ssl) { $meta->add_requires('share' => 'LWP::Protocol::https' => 0 ); } $meta->register_hook( fetch => sub { my($build, $url, %options) = @_; $url ||= $self->url; my @headers; if(my $headers = $options{http_headers}) { if(ref $headers eq 'ARRAY') { @headers = @$headers; } else { $build->log("Fetch for $url with http_headers that is not an array reference"); } } my $ua = LWP::UserAgent->new; $ua->env_proxy; my $res = $ua->get($url, @headers); my($protocol) = $url =~ /^([a-z]+):/; die "error fetching $url: @{[ $res->status_line ]}" unless $res->is_success; my($type, $charset) = $res->content_type_charset; my $base = $res->base; my $filename = $res->filename; if($type eq 'text/html') { return { type => 'html', charset => $charset, base => "$base", content => $res->decoded_content || $res->content, protocol => $protocol, }; } elsif($type eq 'text/ftp-dir-listing') { return { type => 'dir_listing', base => "$base", content => $res->decoded_content || $res->content, protocol => $protocol, }; } else { return { type => 'file', filename => $filename || 'downloadedfile', content => $res->content, protocol => $protocol, }; } }); $self; } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Fetch::LWP - Plugin for fetching files using LWP =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; share { start_url 'http://ftp.gnu.org/gnu/make'; plugin 'Fetch::LWP'; }; =head1 DESCRIPTION Note: in most case you will want to use L instead. It picks the appropriate fetch plugin based on your platform and environment. In some cases you may need to use this plugin directly instead. This fetch plugin fetches files and directory listings via the C C, C, C protocol using L. If the URL specified uses the C scheme, then the required SSL modules will automatically be injected as requirements. If your initial URL is not C, but you know that it will be needed on a subsequent request you can use the ssl property below. =head1 PROPERTIES =head2 url The initial URL to fetch. This may be a directory listing (in HTML) or the final file. =head2 ssl If set to true, then the SSL modules required to make an C connection will be added as prerequisites. =head1 SEE ALSO L, L, L, L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Fetch/LocalDir.pm000044400000007565152346246310012142 0ustar00package Alien::Build::Plugin::Fetch::LocalDir; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; use File::chdir; use Path::Tiny (); # ABSTRACT: Plugin for fetching a local directory our $VERSION = '2.74'; # VERSION has root => undef; has ssl => 0; sub init { my($self, $meta) = @_; my $url = $meta->prop->{start_url} || 'patch'; $meta->add_requires('configure' => 'Alien::Build::Plugin::Fetch::LocalDir' => '0.72' ); if($url =~ /^file:/) { $meta->add_requires('share' => 'URI' => 0 ); $meta->add_requires('share' => 'URI::file' => 0 ); } { my $root = $self->root; if(defined $root) { $root = Path::Tiny->new($root)->absolute->stringify; } else { $root = "$CWD"; } $self->root($root); } $meta->register_hook( fetch => sub { my($build, $path, %options) = @_; $build->log("plugin Fetch::LocalDir does not support http_headers option") if $options{http_headers}; $path ||= $url; if($path =~ /^file:/) { my $root = URI::file->new($self->root); my $url = URI->new_abs($path, $root); $path = $url->path; $path =~ s{^/([a-z]:)}{$1}i if $^O eq 'MSWin32'; } $path = Path::Tiny->new($path)->absolute($self->root); if(-d $path) { return { type => 'file', filename => $path->basename, path => $path->stringify, tmp => 0, protocol => 'file', }; } else { $build->log("path $path is not a directory"); $build->log("(you specified $url with root @{[ $self->root ]})"); die "$path is not a directory"; } } ); } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Fetch::LocalDir - Plugin for fetching a local directory =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; share { start_url 'patch/libfoo-1.00/'; plugin 'Fetch::LocalDir'; }; =head1 DESCRIPTION Note: in most case you will want to use L instead. It picks the appropriate fetch plugin based on your platform and environment. In some cases you may need to use this plugin directly instead. This fetch plugin fetches files from the local file system. It is mostly useful if you intend to bundle source with your Alien. If you are bundling tarballs see L. =head1 PROPERTIES =head2 root The directory from which the start URL should be relative. The default is usually reasonable. =head2 ssl This property is for compatibility with other fetch plugins, but is not used. =head1 SEE ALSO =over 4 =item L =item L =item L =item L =item L =item L =back =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Fetch/HTTPTiny.pm000044400000014320152346246310012057 0ustar00package Alien::Build::Plugin::Fetch::HTTPTiny; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; use File::Basename (); use Alien::Build::Util qw( _ssl_reqs ); use Carp (); # ABSTRACT: Plugin for fetching files using HTTP::Tiny our $VERSION = '2.74'; # VERSION has '+url' => ''; has ssl => 0; # ignored for compatability has bootstrap_ssl => 1; sub init { my($self, $meta) = @_; $meta->add_requires('share' => 'HTTP::Tiny' => '0.044' ); $meta->add_requires('share' => 'URI' => '0' ); $meta->add_requires('share' => 'Mozilla::CA' => '0' ); $meta->prop->{start_url} ||= $self->url; $self->url($meta->prop->{start_url}); $self->url || Carp::croak('url is a required property'); if($self->url =~ /^https:/ || $self->ssl) { my $reqs = _ssl_reqs; foreach my $mod (sort keys %$reqs) { $meta->add_requires('share' => $mod => $reqs->{$mod}); } } $meta->register_hook( fetch => sub { my($build, $url, %options) = @_; $url ||= $self->url; $url = URI->new($url) unless ref($url) && $url->isa('URI'); my %headers; if(my $headers = $options{http_headers}) { if(ref $headers eq 'ARRAY') { my @headers = @$headers; while(@headers) { my $key = shift @headers; my $value = shift @headers; unless(defined $key && defined $value) { $build->log("Fetch for $url with http_headers contains undef key or value"); next; } push @{ $headers{$key} }, $value; } } else { $build->log("Fetch for $url with http_headers that is not an array reference"); } } my $ua = HTTP::Tiny->new( agent => "Alien-Build/@{[ $Alien::Build::VERSION || 'dev' ]} ", verify_SSL => $build->download_rule =~ /encrypt/ ? 1 : 0, ); my $res = $ua->get($url, { headers => \%headers }); unless($res->{success}) { my $status = $res->{status} || '---'; my $reason = $res->{reason} || 'unknown'; $build->log("$status $reason fetching $url"); if($status == 599) { $build->log("exception: $_") for split /\n/, $res->{content}; my($can_ssl, $why_ssl) = HTTP::Tiny->can_ssl; if(! $can_ssl) { if($res->{redirects}) { foreach my $redirect (@{ $res->{redirects} }) { if(defined $redirect->{headers}->{location} && $redirect->{headers}->{location} =~ /^https:/) { $build->log("An attempt at a SSL URL https was made, but your HTTP::Tiny does not appear to be able to use https."); $build->log("Please see: https://metacpan.org/pod/Alien::Build::Manual::FAQ#599-Internal-Exception-errors-downloading-packages-from-the-internet"); } } } } } die "error fetching $url: $status $reason"; } my($type) = split /;/, $res->{headers}->{'content-type'}; $type = lc $type; my $base = URI->new($res->{url}); my $filename = File::Basename::basename do { my $name = $base->path; $name =~ s{/$}{}; $name }; # TODO: this doesn't get exercised by t/bin/httpd if(my $disposition = $res->{headers}->{"content-disposition"}) { # Note: from memory without quotes does not match the spec, # but many servers actually return this sort of value. if($disposition =~ /filename="([^"]+)"/ || $disposition =~ /filename=([^\s]+)/) { $filename = $1; } } if($type eq 'text/html') { return { type => 'html', base => $base->as_string, content => $res->{content}, protocol => $url->scheme, }; } else { return { type => 'file', filename => $filename || 'downloadedfile', content => $res->{content}, protocol => $url->scheme, }; } }); $self; } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Fetch::HTTPTiny - Plugin for fetching files using HTTP::Tiny =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; share { start_url 'http://ftp.gnu.org/gnu/make'; plugin 'Fetch::HTTPTiny'; }; =head1 DESCRIPTION Note: in most case you will want to use L instead. It picks the appropriate fetch plugin based on your platform and environment. In some cases you may need to use this plugin directly instead. This fetch plugin fetches files and directory listings via the C and C protocol using L. If the URL specified uses the C scheme, then the required SSL modules will automatically be injected as requirements. If your initial URL is not C, but you know that it will be needed on a subsequent request you can use the ssl property below. =head1 PROPERTIES =head2 url The initial URL to fetch. This may be a directory listing (in HTML) or the final file. =head2 ssl If set to true, then the SSL modules required to make an C connection will be added as prerequisites. =head1 SEE ALSO L, L, L, L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Fetch/Wget.pm000044400000012344152346246310011346 0ustar00package Alien::Build::Plugin::Fetch::Wget; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; use File::Temp qw( tempdir ); use Path::Tiny qw( path ); use File::Which qw( which ); use Capture::Tiny qw( capture capture_merged ); use File::chdir; use List::Util qw( pairmap ); # ABSTRACT: Plugin for fetching files using wget our $VERSION = '2.74'; # VERSION sub _wget { my $wget = defined $ENV{WGET} ? which($ENV{WGET}) : which('wget'); return undef unless defined $wget; my $output = capture_merged { system $wget, '--help' }; # The wget that BusyBox implements does not follow that same interface # as GNU wget and may not check ssl certs which is not good. return undef if $output =~ /BusyBox/; return $wget; } has wget_command => sub { _wget() }; has ssl => 0; # when bootstrapping we have to specify this plugin as a prereq # 1 is the default so that when this plugin is used directly # you also get the prereq has bootstrap_ssl => 1; sub init { my($self, $meta) = @_; $meta->add_requires('configure', 'Alien::Build::Plugin::Fetch::Wget' => '1.19') if $self->bootstrap_ssl; $meta->register_hook( fetch => sub { my($build, $url, %options) = @_; $url ||= $meta->prop->{start_url}; my($scheme) = $url =~ /^([a-z0-9]+):/i; if($scheme eq 'http' || $scheme eq 'https') { local $CWD = tempdir( CLEANUP => 1 ); my @headers; if(my $headers = $options{http_headers}) { if(ref $headers eq 'ARRAY') { my @copy = @$headers; my %headers; while(@copy) { my $key = shift @copy; my $value = shift @copy; push @{ $headers{$key} }, $value; } @headers = pairmap { "--header=$a: @{[ join ', ', @$b ]}" } %headers; } else { $build->log("Fetch for $url with http_headers that is not an array reference"); } } my($stdout, $stderr) = $self->_execute( $build, $self->wget_command, '-k', '--content-disposition', '-S', @headers, $url, ); my($path) = path('.')->children; die "no file found after wget" unless $path; my($type) = $stderr =~ /Content-Type:\s*(.*?)$/m; $type =~ s/;.*$// if $type; if($type eq 'text/html') { return { type => 'html', base => $url, content => scalar $path->slurp, protocol => $scheme, }; } else { return { type => 'file', filename => $path->basename, path => $path->absolute->stringify, protocol => $scheme, }; } } else { die "scheme $scheme is not supported by the Fetch::Wget plugin"; } }, ) if $self->wget_command; } sub _execute { my($self, $build, @command) = @_; $build->log("+ @command"); my($stdout, $stderr, $err) = capture { system @command; $?; }; if($err) { chomp $stderr; $stderr = [split /\n/, $stderr]->[-1]; die "error in wget fetch: $stderr"; } ($stdout, $stderr); } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Fetch::Wget - Plugin for fetching files using wget =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; share { start_url 'https://www.openssl.org/source/'; plugin 'Fetch::Wget'; }; =head1 DESCRIPTION B: This plugin is somewhat experimental at this time. This plugin provides a fetch based on the C command. It works with other fetch plugins (that is, the first one which succeeds will be used). Most of the time the best plugin to use will be L, but for some SSL bootstrapping it may be desirable to try C first. Protocols supported: C, C =head1 PROPERTIES =head2 wget_command The full path to the C command. The default is usually correct. =head2 ssl Ignored by this plugin. Provided for compatibility with some other fetch plugins. =head1 SEE ALSO =over 4 =item L =item L =back =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Fetch/CurlCommand.pm000044400000020311152346246310012635 0ustar00package Alien::Build::Plugin::Fetch::CurlCommand; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; use File::Which qw( which ); use Path::Tiny qw( path ); use Capture::Tiny qw( capture ); use File::Temp qw( tempdir ); use List::Util 1.33 qw( any pairmap ); use File::chdir; # ABSTRACT: Plugin for fetching files using curl our $VERSION = '2.74'; # VERSION sub curl_command { defined $ENV{CURL} ? scalar which($ENV{CURL}) : scalar which('curl'); } has ssl => 0; has _see_headers => 0; has '+url' => ''; # when bootstrapping we have to specify this plugin as a prereq # 1 is the default so that when this plugin is used directly # you also get the prereq has bootstrap_ssl => 1; sub protocol_ok { my($class, $protocol) = @_; my $curl = $class->curl_command; return 0 unless defined $curl; my($out, $err, $exit) = capture { system $curl, '--version'; }; { # make sure curl supports the -J option. # CentOS 6 for example is recent enough # that it does not. gh#147, gh#148, gh#149 local $CWD = tempdir( CLEANUP => 1 ); my $file1 = path('foo/foo.txt'); $file1->parent->mkpath; $file1->spew("hello world\n"); my $url = 'file://' . $file1->absolute; my($out, $err, $exit) = capture { system $curl, '-O', '-J', $url; }; my $file2 = $file1->parent->child($file1->basename); unlink "$file1"; unlink "$file2"; rmdir($file1->parent); return 0 if $exit; } foreach my $line (split /\n/, $out) { if($line =~ /^Protocols:\s*(.*)\s*$/) { my %proto = map { $_ => 1 } split /\s+/, $1; return $proto{$protocol} if $proto{$protocol}; } } return 0; } sub init { my($self, $meta) = @_; $meta->prop->{start_url} ||= $self->url; $self->url($meta->prop->{start_url}); $self->url || Carp::croak('url is a required property'); $meta->add_requires('configure', 'Alien::Build::Plugin::Fetch::CurlCommand' => '1.19') if $self->bootstrap_ssl; $meta->register_hook( fetch => sub { my($build, $url, %options) = @_; $url ||= $self->url; my($scheme) = $url =~ /^([a-z0-9]+):/i; if($scheme =~ /^https?$/) { local $CWD = tempdir( CLEANUP => 1 ); my @writeout = ( "ab-filename :%{filename_effective}", "ab-content_type :%{content_type}", "ab-url :%{url_effective}", ); $build->log("writeout: $_\\n") for @writeout; path('writeout')->spew(join("\\n", @writeout)); my @headers; if(my $headers = $options{http_headers}) { if(ref $headers eq 'ARRAY') { @headers = pairmap { -H => "$a: $b" } @$headers; } else { $build->log("Fetch for $url with http_headers that is not an array reference"); } } my @command = ( $self->curl_command, '-L', '-f', '-O', '-J', -w => '@writeout', @headers, ); push @command, -D => 'head' if $self->_see_headers; push @command, $url; my($stdout, $stderr) = $self->_execute($build, @command); my %h = map { /^ab-(.*?)\s*:(.*)$/ ? ($1 => $2) : () } split /\n/, $stdout; if(-e 'head') { $build->log(" ~ $_ => $h{$_}") for sort keys %h; $build->log(" header: $_") for path('headers')->lines; } my($type) = split /;/, $h{content_type}; if($type eq 'text/html') { return { type => 'html', base => $h{url}, content => scalar path($h{filename})->slurp, protocol => $scheme, }; } else { return { type => 'file', filename => $h{filename}, path => path($h{filename})->absolute->stringify, protocol => $scheme, }; } } # elsif($scheme eq 'ftp') # { # if($url =~ m{/$}) # { # my($stdout, $stderr) = $self->_execute($build, $self->curl_command, -l => $url); # chomp $stdout; # return { # type => 'list', # list => [ # map { { filename => $_, url => "$url$_" } } sort split /\n/, $stdout, # ], # }; # } # # my $first_error; # # { # local $CWD = tempdir( CLEANUP => 1 ); # # my($filename) = $url =~ m{/([^/]+)$}; # $filename = 'unknown' if (! defined $filename) || ($filename eq ''); # my($stdout, $stderr) = eval { $self->_execute($build, $self->curl_command, -o => $filename, $url) }; # $first_error = $@; # if($first_error eq '') # { # return { # type => 'file', # filename => $filename, # path => path($filename)->absolute->stringify, # }; # } # } # # { # my($stdout, $stderr) = eval { $self->_execute($build, $self->curl_command, -l => "$url/") }; # if($@ eq '') # { # chomp $stdout; # return { # type => 'list', # list => [ # map { { filename => $_, url => "$url/$_" } } sort split /\n/, $stdout, # ], # }; # }; # } # # $first_error ||= 'unknown error'; # die $first_error; # # } else { die "scheme $scheme is not supported by the Fetch::CurlCommand plugin"; } }, ) if $self->curl_command; $self; } sub _execute { my($self, $build, @command) = @_; $build->log("+ @command"); my($stdout, $stderr, $err) = capture { system @command; $?; }; if($err) { chomp $stderr; $build->log($_) for split /\n/, $stderr; if($stderr =~ /Remote filename has no length/ && !!(any { /^-O$/ } @command)) { my @new_command = map { /^-O$/ ? ( -o => 'index.html' ) : /^-J$/ ? () : ($_) } @command; return $self->_execute($build, @new_command); } die "error in curl fetch"; } ($stdout, $stderr); } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Fetch::CurlCommand - Plugin for fetching files using curl =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; share { start_url 'https://www.openssl.org/source/'; plugin 'Fetch::CurlCommand'; }; =head1 DESCRIPTION This plugin provides a fetch based on the C command. It works with other fetch plugins (that is, the first one which succeeds will be used). Most of the time the best plugin to use will be L, but for some SSL bootstrapping it may be desirable to try C first. Protocols supported: C, C C support requires that curl was built with SSL support. =head1 PROPERTIES =head2 curl_command The full path to the C command. The default is usually correct. =head2 ssl Ignored by this plugin. Provided for compatibility with some other fetch plugins. =head1 METHODS =head2 protocol_ok my $bool = $plugin->protocol_ok($protocol); my $bool = Alien::Build::Plugin::Fetch::CurlCommand->protocol_ok($protocol); =head1 SEE ALSO =over 4 =item L =item L =back =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Probe.pod000044400000004473152346246310010630 0ustar00# PODNAME: Alien::Build::Plugin::Probe # ABSTRACT: Probe Alien::Build plugins # VERSION __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Probe - Probe Alien::Build plugins =head1 VERSION version 2.74 =head1 SYNOPSIS look for libraries in known location: use alienfile; plugin 'Probe::CBuilder' => ( cflags => '-I/opt/libfoo/include', libs => '-L/opt/libfoo/lib -lfoo', ); look for tools in the path: use alienfile; plugin 'Probe::CommandLine' => ( command => 'gzip', args => [ '--version' ], match => qr/gzip/, version => qr/gzip ([0-9\.]+)/, ); Use C for Visual C++ Perl: use alienfile; plugin 'Probe::Vcpkg' => 'libffi'; =head1 DESCRIPTION Probe plugins try to find existing libraries and tools I installed on the system. If found they can be used instead of downloading the source from the internet and building. =over 4 =item L Use L to probe for existing installed library. =item L Execute commands to probe for existing tools. =item L Use L to probe for existing installed library. =back =head1 SEE ALSO L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Decode/DirListing.pm000044400000005547152346246310012651 0ustar00package Alien::Build::Plugin::Decode::DirListing; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; use File::Basename (); # ABSTRACT: Plugin to extract links from a directory listing our $VERSION = '2.74'; # VERSION sub init { my($self, $meta) = @_; $meta->add_requires('share' => 'File::Listing' => 0); $meta->add_requires('share' => 'URI' => 0); $meta->register_hook( decode => sub { my(undef, $res) = @_; die "do not know how to decode @{[ $res->{type} ]}" unless $res->{type} eq 'dir_listing'; my $base = URI->new($res->{base}); return { type => 'list', list => [ map { my($name) = @$_; my $basename = $name; $basename =~ s{/$}{}; my %h = ( filename => File::Basename::basename($basename), url => URI->new_abs($name, $base)->as_string, ); \%h; } File::Listing::parse_dir($res->{content}) ], }; }); $self; } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Decode::DirListing - Plugin to extract links from a directory listing =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; plugin 'Decode::DirListing'; =head1 DESCRIPTION Note: in most case you will want to use L instead. It picks the appropriate decode plugin based on your platform and environment. In some cases you may need to use this plugin directly instead. This plugin decodes a ftp file listing into a list of candidates for your Prefer plugin. It is useful when fetching from an FTP server via L. =head1 SEE ALSO L, L, L, L, L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Decode/Mojo.pm000044400000010440152346246310011471 0ustar00package Alien::Build::Plugin::Decode::Mojo; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; # ABSTRACT: Plugin to extract links from HTML using Mojo::DOM or Mojo::DOM58 our $VERSION = '2.74'; # VERSION sub _load ($;$) { my($class, $version) = @_; my $pm = "$class.pm"; $pm =~ s/::/\//g; eval { require $pm }; return 0 if $@; if(defined $version) { eval { $class->VERSION($version) }; return 0 if $@; } return 1; } has _class => sub { return 'Mojo::DOM58' if _load 'Mojo::DOM58'; return 'Mojo::DOM' if _load 'Mojo::DOM' and _load 'Mojolicious', 7.00; return 'Mojo::DOM58'; }; sub init { my($self, $meta) = @_; $meta->add_requires('share' => 'URI' => 0); $meta->add_requires('share' => 'URI::Escape' => 0); my $class = $meta->prop->{plugin_decode_mojo_class} ||= $self->_class; if($class eq 'Mojo::DOM58') { $meta->add_requires('share' => 'Mojo::DOM58' => '1.00'); } elsif($class eq 'Mojo::DOM') { $meta->add_requires('share' => 'Mojolicious' => '7.00'); $meta->add_requires('share' => 'Mojo::DOM' => '0'); } else { die "bad class"; } $meta->register_hook( decode => sub { my(undef, $res) = @_; die "do not know how to decode @{[ $res->{type} ]}" unless $res->{type} eq 'html'; my $dom = $class->new($res->{content}); my $base = URI->new($res->{base}); if(my $base_element = $dom->find('head base')->first) { my $href = $base_element->attr('href'); $base = URI->new($href) if defined $href; } my @list = map { my $url = URI->new_abs($_, $base); my $path = $url->path; $path =~ s{/$}{}; # work around for Perl 5.8.7- gh#8 { filename => URI::Escape::uri_unescape(File::Basename::basename($path)), url => URI::Escape::uri_unescape($url->as_string), } } grep !/^\.\.?\/?$/, map { $_->attr('href') || () } @{ $dom->find('a')->to_array }; return { type => 'list', list => \@list, }; }) } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Decode::Mojo - Plugin to extract links from HTML using Mojo::DOM or Mojo::DOM58 =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; plugin 'Decode::Mojo'; Force using C via the download negotiator: use alienfile 1.68; configure { requires 'Alien::Build::Plugin::Decode::Mojo'; }; plugin 'Download' => ( ... decoder => 'Decode::Mojo', ); =head1 DESCRIPTION Note: in most cases you will want to use L instead. It picks the appropriate decode plugin based on your platform and environment. In some cases you may need to use this plugin directly instead. This plugin decodes an HTML file listing into a list of candidates for your Prefer plugin. It works just like L except it uses either L or L to do its job. This plugin is much lighter than The C plugin, and doesn't require XS. It is the default decode plugin used by L if it detects that you need to parse an HTML index. =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Decode/DirListingFtpcopy.pm000044400000006433152346246310014211 0ustar00package Alien::Build::Plugin::Decode::DirListingFtpcopy; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; use File::Basename (); # ABSTRACT: Plugin to extract links from a directory listing using ftpcopy our $VERSION = '2.74'; # VERSION sub init { my($self, $meta) = @_; $meta->add_requires('share' => 'File::Listing::Ftpcopy' => 0); $meta->add_requires('share' => 'URI' => 0); $meta->register_hook( decode => sub { my(undef, $res) = @_; die "do not know how to decode @{[ $res->{type} ]}" unless $res->{type} eq 'dir_listing'; my $base = URI->new($res->{base}); return { type => 'list', list => [ map { my($name) = @$_; my $basename = $name; $basename =~ s{/$}{}; my %h = ( filename => File::Basename::basename($basename), url => URI->new_abs($name, $base)->as_string, ); \%h; } File::Listing::Ftpcopy::parse_dir($res->{content}) ], }; }); $self; } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Decode::DirListingFtpcopy - Plugin to extract links from a directory listing using ftpcopy =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; plugin 'Decode::DirListingFtpcopy'; =head1 DESCRIPTION Note: in most case you will want to use L instead. It picks the appropriate decode plugin based on your platform and environment. In some cases you may need to use this plugin directly instead. This plugin decodes a ftp file listing into a list of candidates for your Prefer plugin. It is useful when fetching from an FTP server via L. It is different from the similarly named L in that it uses L instead of L. The rationale for the C version is that it supports a different set of FTP servers, including OpenVMS. In most cases, however, you probably want to use the non C version since it is pure perl. =head1 SEE ALSO L, L, L, L, L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Decode/HTML.pm000044400000006063152346246310011337 0ustar00package Alien::Build::Plugin::Decode::HTML; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; use File::Basename (); # ABSTRACT: Plugin to extract links from HTML our $VERSION = '2.74'; # VERSION sub init { my($self, $meta) = @_; $meta->add_requires('share' => 'HTML::LinkExtor' => 0); $meta->add_requires('share' => 'URI' => 0); $meta->add_requires('share' => 'URI::Escape' => 0); $meta->register_hook( decode => sub { my(undef, $res) = @_; die "do not know how to decode @{[ $res->{type} ]}" unless $res->{type} eq 'html'; my $base = URI->new($res->{base}); my @list; my $p = HTML::LinkExtor->new(sub { my($tag, %links) = @_; if($tag eq 'base' && $links{href}) { $base = URI->new($links{href}); } elsif($tag eq 'a' && $links{href}) { my $href = $links{href}; return if $href =~ m!^\.\.?/?$!; my $url = URI->new_abs($href, $base); my $path = $url->path; $path =~ s{/$}{}; # work around for Perl 5.8.7- gh#8 push @list, { filename => URI::Escape::uri_unescape(File::Basename::basename($path)), url => URI::Escape::uri_unescape($url->as_string), }; } }); $p->parse($res->{content}); return { type => 'list', list => \@list, }; }); $self; } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Decode::HTML - Plugin to extract links from HTML =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; plugin 'Decode::HTML'; =head1 DESCRIPTION Note: in most case you will want to use L instead. It picks the appropriate decode plugin based on your platform and environment. In some cases you may need to use this plugin directly instead. This plugin decodes an HTML file listing into a list of candidates for your Prefer plugin. =head1 SEE ALSO L, L, L, L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/PkgConfig/MakeStatic.pm000044400000006547152346246310013313 0ustar00package Alien::Build::Plugin::PkgConfig::MakeStatic; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; use Path::Tiny (); # ABSTRACT: Convert .pc files into static our $VERSION = '2.74'; # VERSION has path => undef; sub _convert { my($self, $build, $path) = @_; die "unable to read $path" unless -r $path; die "unable to write $path" unless -w $path; $build->log("converting $path to static"); my %h = map { my($key, $value) = /^(.*?):(.*?)$/; $value =~ s{^\s+}{}; $value =~ s{\s+$}{}; ($key => $value); } grep /^(?:Libs|Cflags)(?:\.private)?:/, $path->lines; $h{Cflags} = '' unless defined $h{Cflags}; $h{Libs} = '' unless defined $h{Libs}; $h{Cflags} .= ' ' . $h{"Cflags.private"} if defined $h{"Cflags.private"}; $h{Libs} .= ' ' . $h{"Libs.private"} if defined $h{"Libs.private"}; $h{"Cflags.private"} = ''; $h{"Libs.private"} = ''; $path->edit_lines(sub { if(/^(.*?):/) { my $key = $1; if(defined $h{$key}) { s/^(.*?):.*$/$1: $h{$key} /; delete $h{$key}; } } }); $path->append("$_: $h{$_}\n") foreach keys %h; } sub _recurse { my($self, $build, $dir) = @_; foreach my $child ($dir->children) { if(-d $child) { $self->_recurse($build, $child); } elsif($child->basename =~ /\.pc$/) { $self->_convert($build, $child); } } } sub init { my($self, $meta) = @_; $meta->add_requires('configure' => 'Alien::Build::Plugin::Build::SearchDep' => '0.35'); $meta->before_hook( gather_share => sub { my($build) = @_; if($self->path) { $self->_convert($build, Path::Tiny->new($self->path)->absolute); } else { $self->_recurse($build, Path::Tiny->new(".")->absolute); } }, ); } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::PkgConfig::MakeStatic - Convert .pc files into static =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; plugin 'PkgConfig::MakeStatic' => ( path => 'lib/pkgconfig/foo.pc', ); =head1 DESCRIPTION Convert C<.pc> file to use static linkage by default. This is an experimental plugin, so use with caution. =head1 PROPERTIES =head2 path The path to the C<.pc> file. If not provided, all C<.pc> files in the stage directory will be converted. =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/PkgConfig/CommandLine.pm000044400000016332152346246310013445 0ustar00package Alien::Build::Plugin::PkgConfig::CommandLine; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; use Carp (); # ABSTRACT: Probe system and determine library or tool properties using the pkg-config command line interface our $VERSION = '2.74'; # VERSION has '+pkg_name' => sub { Carp::croak "pkg_name is a required property"; }; # NOT used, for compat with other PkgConfig plugins has register_prereqs => 1; sub _bin_name { # We prefer pkgconf to pkg-config because it seems to be the future. require File::Which; File::Which::which($ENV{PKG_CONFIG}) ? $ENV{PKG_CONFIG} : File::Which::which('pkgconf') ? 'pkgconf' : File::Which::which('pkg-config') ? 'pkg-config' : undef; }; has bin_name => \&_bin_name; has atleast_version => undef; has exact_version => undef; has max_version => undef; has minimum_version => undef; sub _val { my($build, $args, $prop_name) = @_; my $string = $args->{out}; chomp $string; $string =~ s{^\s+}{}; if($prop_name =~ /version$/) { $string =~ s{\s*$}{} } else { $string =~ s{\s*$}{ } } if($prop_name =~ /^(.*?)\.(.*?)\.(.*?)$/) { $build->runtime_prop->{$1}->{$2}->{$3} = $string } else { $build->runtime_prop->{$prop_name} = $string } (); } sub available { !!_bin_name(); } sub init { my($self, $meta) = @_; my @probe; my @gather; my $pkgconf = $self->bin_name; unless(defined $meta->prop->{env}->{PKG_CONFIG}) { $meta->prop->{env}->{PKG_CONFIG} = $pkgconf; } my($pkg_name, @alt_names) = (ref $self->pkg_name) ? (@{ $self->pkg_name }) : ($self->pkg_name); push @probe, map { [$pkgconf, '--exists', $_] } ($pkg_name, @alt_names); if(defined $self->minimum_version) { push @probe, [ $pkgconf, '--atleast-version=' . $self->minimum_version, $pkg_name ]; } elsif(defined $self->atleast_version) { push @probe, [ $pkgconf, '--atleast-version=' . $self->atleast_version, $pkg_name ]; } if(defined $self->exact_version) { push @probe, [ $pkgconf, '--exact-version=' . $self->exact_version, $pkg_name ]; } if(defined $self->max_version) { push @probe, [ $pkgconf, '--max-version=' . $self->max_version, $pkg_name ]; } push @probe, [ $pkgconf, '--modversion', $pkg_name, sub { my($build, $args) = @_; my $version = $args->{out}; $version =~ s{^\s+}{}; $version =~ s{\s*$}{}; $build->hook_prop->{version} = $version; }]; unshift @probe, sub { my($build) = @_; $build->runtime_prop->{legacy}->{name} ||= $pkg_name; $build->hook_prop->{probe_class} = __PACKAGE__; $build->hook_prop->{probe_instance_id} = $self->instance_id; }; $meta->register_hook( probe => \@probe ); push @gather, sub { my($build) = @_; die 'pkg-config command line probe does not match gather' if $build->hook_prop->{name} eq 'gather_system' && ($build->install_prop->{system_probe_instance_id} || '') ne $self->instance_id; }; push @gather, map { [ $pkgconf, '--exists', $_] } ($pkg_name, @alt_names); foreach my $prop_name (qw( cflags libs version )) { my $flag = $prop_name eq 'version' ? '--modversion' : "--$prop_name"; push @gather, [ $pkgconf, $flag, $pkg_name, sub { _val @_, $prop_name } ]; if(@alt_names) { foreach my $alt ($pkg_name, @alt_names) { push @gather, [ $pkgconf, $flag, $alt, sub { _val @_, "alt.$alt.$prop_name" } ]; } } } foreach my $prop_name (qw( cflags libs )) { push @gather, [ $pkgconf, '--static', "--$prop_name", $pkg_name, sub { _val @_, "${prop_name}_static" } ]; if(@alt_names) { foreach my $alt ($pkg_name, @alt_names) { push @gather, [ $pkgconf, '--static', "--$prop_name", $alt, sub { _val @_, "alt.$alt.${prop_name}_static" } ]; } } } $meta->register_hook(gather_system => [@gather]); if($meta->prop->{platform}->{system_type} eq 'windows-mingw') { @gather = map { if(ref $_ eq 'ARRAY') { my($pkgconf, @rest) = @$_; [$pkgconf, '--dont-define-prefix', @rest], } else { $_ } } @gather; } $meta->register_hook(gather_share => [@gather]); $meta->after_hook( $_ => sub { my($build) = @_; if(keys %{ $build->runtime_prop->{alt} } < 2) { delete $build->runtime_prop->{alt}; } }, ) for qw( gather_system gather_share ); $self; } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::PkgConfig::CommandLine - Probe system and determine library or tool properties using the pkg-config command line interface =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; plugin 'PkgConfig::CommandLine' => ( pkg_name => 'libfoo', ); =head1 DESCRIPTION Note: in most case you will want to use L instead. It picks the appropriate fetch plugin based on your platform and environment. In some cases you may need to use this plugin directly instead. This plugin provides Probe and Gather steps for pkg-config based packages. It uses the best command line tools to accomplish this task. =head1 PROPERTIES =head2 pkg_name The package name. If this is a list reference then .pc files with all those package names must be present. The first name will be the primary and used by default once installed. For the subsequent C<.pc> files you can use the L to retrieve the alternate configurations once the L is installed. =head2 atleast_version The minimum required version that is acceptable version as provided by the system. =head2 exact_version The exact required version that is acceptable version as provided by the system. =head2 max_version The max required version that is acceptable version as provided by the system. =head2 minimum_version Alias for C for backward compatibility. =head1 METHODS =head2 available my $bool = Alien::Build::Plugin::PkgConfig::CommandLine->available; Returns true if the necessary prereqs for this plugin are I installed. =head1 SEE ALSO L, L, L, L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/PkgConfig/Negotiate.pm000044400000012523152346246310013174 0ustar00package Alien::Build::Plugin::PkgConfig::Negotiate; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; use Alien::Build::Plugin::PkgConfig::PP; use Alien::Build::Plugin::PkgConfig::LibPkgConf; use Alien::Build::Plugin::PkgConfig::CommandLine; use Alien::Build::Util qw( _perl_config ); use Carp (); # ABSTRACT: Package configuration negotiation plugin our $VERSION = '2.74'; # VERSION has '+pkg_name' => sub { Carp::croak "pkg_name is a required property"; }; has atleast_version => undef; has exact_version => undef; has max_version => undef; has minimum_version => undef; sub pick { my($class) = @_; return $ENV{ALIEN_BUILD_PKG_CONFIG} if $ENV{ALIEN_BUILD_PKG_CONFIG}; if(Alien::Build::Plugin::PkgConfig::LibPkgConf->available) { return 'PkgConfig::LibPkgConf'; } if(Alien::Build::Plugin::PkgConfig::CommandLine->available) { # TODO: determine environment or flags necessary for using pkg-config # on solaris 64 bit. # Some advice on pkg-config and 64 bit Solaris # https://docs.oracle.com/cd/E53394_01/html/E61689/gplhi.html my $is_solaris64 = (_perl_config('osname') eq 'solaris' && _perl_config('ptrsize') == 8); # PkgConfig.pm is more reliable on windows my $is_windows = _perl_config('osname') eq 'MSWin32'; if(!$is_solaris64 && !$is_windows) { return 'PkgConfig::CommandLine'; } } if(Alien::Build::Plugin::PkgConfig::PP->available) { return 'PkgConfig::PP'; } else { # this is a fata error. because we check for a pkg-config implementation # at configure time, we expect at least one of these to work. (and we # fallback on installing PkgConfig.pm as a prereq if nothing else is avail). # we therefore expect at least one of these to work, if not, then the configuration # of the system has shifted from underneath us. Carp::croak("Could not find an appropriate pkg-config or pkgconf implementation, please install PkgConfig.pm, PkgConfig::LibPkgConf, pkg-config or pkgconf"); } } sub init { my($self, $meta) = @_; my $plugin = $self->pick; Alien::Build->log("Using PkgConfig plugin: $plugin"); if(ref($self->pkg_name) eq 'ARRAY') { $meta->add_requires('configure', 'Alien::Build::Plugin::PkgConfig::Negotiate' => '0.79'); } if($self->atleast_version || $self->exact_version || $self->max_version) { $meta->add_requires('configure', 'Alien::Build::Plugin::PkgConfig::Negotiate' => '1.53'); } my @args; push @args, pkg_name => $self->pkg_name; push @args, register_prereqs => 0; foreach my $method (map { "${_}_version" } qw( minimum atleast exact max )) { push @args, $method => $self->$method if defined $self->$method; } $meta->apply_plugin($plugin, @args); $self; } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::PkgConfig::Negotiate - Package configuration negotiation plugin =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; plugin 'PkgConfig' => ( pkg_name => 'libfoo', ); =head1 DESCRIPTION This plugin provides Probe and Gather steps for pkg-config based packages. It picks the best C plugin depending your platform and environment. =head1 PROPERTIES =head2 pkg_name The package name. If this is a list reference then .pc files with all those package names must be present. The first name will be the primary and used by default once installed. For the subsequent C<.pc> files you can use the L to retrieve the alternate configurations once the L is installed. =head2 atleast_version The minimum required version that is acceptable version as provided by the system. =head2 exact_version The exact required version that is acceptable version as provided by the system. =head2 max_version The max required version that is acceptable version as provided by the system. =head2 minimum_version Alias for C for backward compatibility. =head1 METHODS =head2 pick my $name = Alien::Build::Plugin::PkgConfig::Negotiate->pick; Returns the name of the negotiated plugin. =head1 ENVIRONMENT =over 4 =item ALIEN_BUILD_PKG_CONFIG If set, this plugin will be used instead of the build in logic which attempts to automatically pick the best plugin. =back =head1 SEE ALSO L, L, L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/PkgConfig/PP.pm000044400000017543152346246310011603 0ustar00package Alien::Build::Plugin::PkgConfig::PP; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; use Carp (); use File::Which (); use Env qw( @PKG_CONFIG_PATH ); # ABSTRACT: Probe system and determine library or tool properties using PkgConfig.pm our $VERSION = '2.74'; # VERSION has '+pkg_name' => sub { Carp::croak "pkg_name is a required property"; }; has atleast_version => undef; has exact_version => undef; has max_version => undef; has minimum_version => undef; use constant _min_version => '0.14026'; # private for now, used by negotiator has register_prereqs => 1; sub available { !!eval { require PkgConfig; PkgConfig->VERSION(_min_version) }; } sub _cleanup { my($value) = @_; $value =~ s{\s*$}{ }; $value; } sub init { my($self, $meta) = @_; unless(defined $meta->prop->{env}->{PKG_CONFIG}) { # TODO: Better would be to to "execute" lib/PkgConfig.pm # as that should always be available, and will match the # exact version of PkgConfig.pm that we are using here. # there are a few corner cases to deal with before we # can do this. What is here should handle most use cases. my $command_line = File::Which::which('ppkg-config') ? 'ppkg-config' : File::Which::which('pkg-config.pl') ? 'pkg-config.pl' : File::Which::which('pkg-config') ? 'pkg-config' : undef; $meta->prop->{env}->{PKG_CONFIG} = $command_line if defined $command_line; } if($self->register_prereqs) { $meta->add_requires('configure' => 'PkgConfig' => _min_version); } my($pkg_name, @alt_names) = (ref $self->pkg_name) ? (@{ $self->pkg_name }) : ($self->pkg_name); $meta->register_hook( probe => sub { my($build) = @_; $build->runtime_prop->{legacy}->{name} ||= $pkg_name; $build->hook_prop->{probe_class} = __PACKAGE__; $build->hook_prop->{probe_instance_id} = $self->instance_id; require PkgConfig; my $pkg = PkgConfig->find($pkg_name); die "package @{[ $pkg_name ]} not found" if $pkg->errmsg; $build->hook_prop->{version} = $pkg->pkg_version; my $version = PkgConfig::Version->new($pkg->pkg_version); my $atleast_version = $self->atleast_version; $atleast_version = $self->minimum_version unless defined $atleast_version; if(defined $atleast_version) { my $need = PkgConfig::Version->new($atleast_version); if($version < $need) { die "package @{[ $pkg_name ]} is @{[ $pkg->pkg_version ]}, but at least $atleast_version is required."; } } if(defined $self->exact_version) { my $need = PkgConfig::Version->new($self->exact_version); if($version != $need) { die "package @{[ $pkg_name ]} is @{[ $pkg->pkg_version ]}, but exactly @{[ $self->exact_version ]} is required."; } } if(defined $self->max_version) { my $need = PkgConfig::Version->new($self->max_version); if($version > $need) { die "package @{[ $pkg_name ]} is @{[ $pkg->pkg_version ]}, but max of @{[ $self->max_version ]} is required."; } } foreach my $alt (@alt_names) { my $pkg = PkgConfig->find($alt); die "package $alt not found" if $pkg->errmsg; } 'system'; }, ); $meta->register_hook( $_ => sub { my($build) = @_; return if $build->hook_prop->{name} eq 'gather_system' && ($build->install_prop->{system_probe_instance_id} || '') ne $self->instance_id; require PkgConfig; foreach my $name ($pkg_name, @alt_names) { require PkgConfig; my $pkg = PkgConfig->find($name, search_path => [@PKG_CONFIG_PATH]); if($pkg->errmsg) { $build->log("Trying to load the pkg-config information from the source code build"); $build->log("of your package failed"); $build->log("You are currently using the pure-perl implementation of pkg-config"); $build->log("(AB Plugin is named PkgConfig::PP, which uses PkgConfig.pm"); $build->log("It may work better with the real pkg-config."); $build->log("Try installing your OS' version of pkg-config or unset ALIEN_BUILD_PKG_CONFIG"); die "second load of PkgConfig.pm @{[ $name ]} failed: @{[ $pkg->errmsg ]}" } my %prop; $prop{cflags} = _cleanup scalar $pkg->get_cflags; $prop{libs} = _cleanup scalar $pkg->get_ldflags; $prop{version} = $pkg->pkg_version; $pkg = PkgConfig->find($name, static => 1, search_path => [@PKG_CONFIG_PATH]); $prop{cflags_static} = _cleanup scalar $pkg->get_cflags; $prop{libs_static} = _cleanup scalar $pkg->get_ldflags; $build->runtime_prop->{alt}->{$name} = \%prop; } foreach my $key (keys %{ $build->runtime_prop->{alt}->{$pkg_name} }) { $build->runtime_prop->{$key} = $build->runtime_prop->{alt}->{$pkg_name}->{$key}; } if(keys %{ $build->runtime_prop->{alt} } == 1) { delete $build->runtime_prop->{alt}; } } ) for qw( gather_system gather_share ); $self; } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::PkgConfig::PP - Probe system and determine library or tool properties using PkgConfig.pm =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; plugin 'PkgConfig::PP' => ( pkg_name => 'libfoo', ); =head1 DESCRIPTION Note: in most case you will want to use L instead. It picks the appropriate fetch plugin based on your platform and environment. In some cases you may need to use this plugin directly instead. This plugin provides Probe and Gather steps for pkg-config based packages. It uses L to accomplish this task. =head1 PROPERTIES =head2 pkg_name The package name. If this is a list reference then .pc files with all those package names must be present. The first name will be the primary and used by default once installed. For the subsequent C<.pc> files you can use the L to retrieve the alternate configurations once the L is installed. =head2 atleast_version The minimum required version that is acceptable version as provided by the system. =head2 exact_version The exact required version that is acceptable version as provided by the system. =head2 max_version The max required version that is acceptable version as provided by the system. =head2 minimum_version Alias for C for backward compatibility. =head1 METHODS =head2 available my $bool = Alien::Build::Plugin::PkgConfig::PP->available; Returns true if the necessary prereqs for this plugin are I installed. =head1 SEE ALSO L, L, L, L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/PkgConfig/LibPkgConf.pm000044400000016747152346246310013247 0ustar00package Alien::Build::Plugin::PkgConfig::LibPkgConf; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; use Carp (); # ABSTRACT: Probe system and determine library or tool properties using PkgConfig::LibPkgConf our $VERSION = '2.74'; # VERSION has '+pkg_name' => sub { Carp::croak "pkg_name is a required property"; }; has atleast_version => undef; has exact_version => undef; has max_version => undef; has minimum_version => undef; # private for now, used by negotiator has register_prereqs => 1; use constant _min_version => '0.04'; sub available { !!eval { require PkgConfig::LibPkgConf; PkgConfig::LibPkgConf->VERSION(_min_version) }; } sub init { my($self, $meta) = @_; unless(defined $meta->prop->{env}->{PKG_CONFIG}) { # TODO: this doesn't yet find pkgconf in the bin dir of a share # install. my $command_line = File::Which::which('pkgconf') ? 'pkgconf' : File::Which::which('pkg-config') ? 'pkg-config' : undef; $meta->prop->{env}->{PKG_CONFIG} = $command_line if defined $command_line; } if($self->register_prereqs) { # Also update in Neotiate.pm $meta->add_requires('configure' => 'PkgConfig::LibPkgConf::Client' => _min_version); if(defined $self->minimum_version || defined $self->atleast_version || defined $self->exact_version || defined $self->max_version) { $meta->add_requires('configure' => 'PkgConfig::LibPkgConf::Util' => _min_version); } } my($pkg_name, @alt_names) = (ref $self->pkg_name) ? (@{ $self->pkg_name }) : ($self->pkg_name); $meta->register_hook( probe => sub { my($build) = @_; $build->runtime_prop->{legacy}->{name} ||= $pkg_name; $build->hook_prop->{probe_class} = __PACKAGE__; $build->hook_prop->{probe_instance_id} = $self->instance_id; require PkgConfig::LibPkgConf::Client; my $client = PkgConfig::LibPkgConf::Client->new; my $pkg = $client->find($pkg_name); die "package $pkg_name not found" unless $pkg; $build->hook_prop->{version} = $pkg->version; my $atleast_version = $self->atleast_version; $atleast_version = $self->minimum_version unless defined $self->atleast_version; if($atleast_version) { require PkgConfig::LibPkgConf::Util; if(PkgConfig::LibPkgConf::Util::compare_version($pkg->version, $atleast_version) < 0) { die "package $pkg_name is version @{[ $pkg->version ]}, but at least $atleast_version is required."; } } if($self->exact_version) { require PkgConfig::LibPkgConf::Util; if(PkgConfig::LibPkgConf::Util::compare_version($pkg->version, $self->exact_version) != 0) { die "package $pkg_name is version @{[ $pkg->version ]}, but exactly @{[ $self->exact_version ]} is required."; } } if($self->max_version) { require PkgConfig::LibPkgConf::Util; if(PkgConfig::LibPkgConf::Util::compare_version($pkg->version, $self->max_version) > 0) { die "package $pkg_name is version @{[ $pkg->version ]}, but max @{[ $self->max_version ]} is required."; } } foreach my $alt (@alt_names) { my $pkg = $client->find($alt); die "package $alt not found" unless $pkg; } 'system'; }, ); $meta->register_hook( $_ => sub { my($build) = @_; return if $build->hook_prop->{name} eq 'gather_system' && ($build->install_prop->{system_probe_instance_id} || '') ne $self->instance_id; require PkgConfig::LibPkgConf::Client; my $client = PkgConfig::LibPkgConf::Client->new; foreach my $name ($pkg_name, @alt_names) { my $pkg = $client->find($name); die "reload of package $name failed" unless defined $pkg; my %prop; $prop{version} = $pkg->version; $prop{cflags} = $pkg->cflags; $prop{libs} = $pkg->libs; $prop{cflags_static} = $pkg->cflags_static; $prop{libs_static} = $pkg->libs_static; $build->runtime_prop->{alt}->{$name} = \%prop; } foreach my $key (keys %{ $build->runtime_prop->{alt}->{$pkg_name} }) { $build->runtime_prop->{$key} = $build->runtime_prop->{alt}->{$pkg_name}->{$key}; } if(keys %{ $build->runtime_prop->{alt} } == 1) { delete $build->runtime_prop->{alt}; } }, ) for qw( gather_system gather_share ); $self; } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::PkgConfig::LibPkgConf - Probe system and determine library or tool properties using PkgConfig::LibPkgConf =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; plugin 'PkgConfig::LibPkgConf' => ( pkg_name => 'libfoo', ); =head1 DESCRIPTION Note: in most case you will want to use L instead. It picks the appropriate fetch plugin based on your platform and environment. In some cases you may need to use this plugin directly instead. This plugin provides Probe and Gather steps for pkg-config based packages. It uses L to accomplish this task. This plugin is part of the Alien::Build core For Now, but may be removed in a future date. While It Seemed Like A Good Idea at the time, it may not be appropriate to keep it in core. If it is spun off it will get its own distribution some time in the future. =head1 PROPERTIES =head2 pkg_name The package name. If this is a list reference then .pc files with all those package names must be present. The first name will be the primary and used by default once installed. For the subsequent C<.pc> files you can use the L to retrieve the alternate configurations once the L is installed. =head2 atleast_version The minimum required version that is acceptable version as provided by the system. =head2 exact_version The exact required version that is acceptable version as provided by the system. =head2 max_version The max required version that is acceptable version as provided by the system. =head2 minimum_version Alias for C for backward compatibility. =head1 METHODS =head2 available my $bool = Alien::Build::Plugin::PkgConfig::LibPkgConf->available; Returns true if the necessary prereqs for this plugin are I installed. =head1 SEE ALSO L, L, L, L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Core/Legacy.pm000044400000004724152346246310011506 0ustar00package Alien::Build::Plugin::Core::Legacy; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; # ABSTRACT: Core Alien::Build plugin to maintain compatibility with legacy Alien::Base our $VERSION = '2.74'; # VERSION sub init { my($self, $meta) = @_; $meta->after_hook( $_ => sub { my($build) = @_; $build->log("adding legacy hash to config"); my $runtime = $build->runtime_prop; if($runtime->{cflags} && ! defined $runtime->{cflags_static}) { $runtime->{cflags_static} = $runtime->{cflags}; } if($runtime->{libs} && ! defined $runtime->{libs_static}) { $runtime->{libs_static} = $runtime->{libs}; } $runtime->{legacy}->{finished_installing} = 1; $runtime->{legacy}->{install_type} = $runtime->{install_type}; $runtime->{legacy}->{version} = $runtime->{version}; $runtime->{legacy}->{original_prefix} = $runtime->{prefix}; } ) for qw( gather_system gather_share ); } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Core::Legacy - Core Alien::Build plugin to maintain compatibility with legacy Alien::Base =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; # already loaded =head1 DESCRIPTION This plugin provides some compatibility with the legacy L interfaces. =head1 SEE ALSO L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Core/Gather.pm000044400000012642152346246310011512 0ustar00package Alien::Build::Plugin::Core::Gather; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; use Env qw( @PATH @PKG_CONFIG_PATH ); use Path::Tiny (); use File::chdir; use Alien::Build::Util qw( _mirror _destdir_prefix ); use JSON::PP (); # ABSTRACT: Core gather plugin our $VERSION = '2.74'; # VERSION sub init { my($self, $meta) = @_; $meta->default_hook( $_ => sub {}, ) for qw( gather_system gather_share ); $meta->around_hook( gather_share => sub { my($orig, $build) = @_; local $ENV{PATH} = $ENV{PATH}; local $ENV{PKG_CONFIG_PATH} = $ENV{PKG_CONFIG_PATH}; unshift @PATH, Path::Tiny->new('bin')->absolute->stringify if -d 'bin'; for my $dir (qw(share lib)) { unshift @PKG_CONFIG_PATH, Path::Tiny->new("$dir/pkgconfig")->absolute->stringify if -d "$dir/pkgconfig"; } $orig->($build) } ); foreach my $type (qw( share ffi )) { $meta->around_hook( "gather_$type" => sub { my($orig, $build) = @_; if($build->meta_prop->{destdir}) { my $destdir = $ENV{DESTDIR}; if(-d $destdir) { my $src = Path::Tiny->new(_destdir_prefix($ENV{DESTDIR}, $build->install_prop->{prefix})); my $dst = Path::Tiny->new($build->install_prop->{stage}); my $res = do { local $CWD = "$src"; $orig->($build); }; $build->log("mirror $src => $dst"); $dst->mkpath; # Please note: _mirror and Alien::Build::Util are ONLY # allowed to be used by core plugins. If you are writing # a non-core plugin it may be removed. That is why it # is private. _mirror("$src", "$dst", { verbose => 1, filter => $build->meta_prop->{$type eq 'share' ? 'destdir_filter' : 'destdir_ffi_filter'}, }); return $res; } else { die "nothing was installed into destdir" if $type eq 'share'; } } else { local $CWD = $build->install_prop->{stage}; my $ret = $orig->($build); # if we are not doing a double staged install we want to substitute the install # prefix with the runtime prefix. my $old = $build->install_prop->{prefix}; my $new = $build->runtime_prop->{prefix}; foreach my $flag (qw( cflags cflags_static libs libs_static )) { next unless defined $build->runtime_prop->{$flag}; $build->runtime_prop->{$flag} =~ s{(-I|-L|-LIBPATH:)\Q$old\E}{$1 . $new}eg; } return $ret; } } ); } $meta->after_hook( $_ => sub { my($build) = @_; die "stage is not defined. be sure to call set_stage on your Alien::Build instance" unless $build->install_prop->{stage}; my $stage = Path::Tiny->new($build->install_prop->{stage}); $build->log("mkdir -p $stage/_alien"); $stage->child('_alien')->mkpath; # drop a alien.json file for the runtime properties $stage->child('_alien/alien.json')->spew( JSON::PP->new->pretty->canonical(1)->ascii->encode($build->runtime_prop) ); # copy the alienfile, if we managed to keep it around. if($build->meta->filename && -r $build->meta->filename && $build->meta->filename !~ /\.(pm|pl)$/ && ! -d $build->meta->filename) { Path::Tiny->new($build->meta->filename) ->copy($stage->child('_alien/alienfile')); } if($build->install_prop->{patch} && -d $build->install_prop->{patch}) { # Please note: _mirror and Alien::Build::Util are ONLY # allowed to be used by core plugins. If you are writing # a non-core plugin it may be removed. That is why it # is private. _mirror($build->install_prop->{patch}, $stage->child('_alien/patch')->stringify); } }, ) for qw( gather_share gather_system ); } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Core::Gather - Core gather plugin =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; # already loaded =head1 DESCRIPTION This plugin helps make the gather stage work. =head1 SEE ALSO L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Core/Tail.pm000044400000003270152346246310011166 0ustar00package Alien::Build::Plugin::Core::Tail; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; # ABSTRACT: Core tail setup plugin our $VERSION = '2.74'; # VERSION sub init { my($self, $meta) = @_; if($meta->prop->{out_of_source}) { $meta->add_requires('configure' => 'Alien::Build' => '1.08'); } } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Core::Tail - Core tail setup plugin =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; # already loaded =head1 DESCRIPTION This plugin does some core tail setup for you. =head1 SEE ALSO L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Core/Setup.pm000044400000016405152346246310011401 0ustar00package Alien::Build::Plugin::Core::Setup; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; use Config; use File::Which qw( which ); # ABSTRACT: Core setup plugin our $VERSION = '2.74'; # VERSION sub init { my($self, $meta) = @_; $meta->prop->{platform} ||= {}; $self->_platform($meta->prop->{platform}); } sub _platform { my(undef, $hash) = @_; if($^O eq 'MSWin32' && $Config{ccname} eq 'cl') { $hash->{compiler_type} = 'microsoft'; } else { $hash->{compiler_type} = 'unix'; } if($^O eq 'MSWin32') { $hash->{system_type} = 'windows-unknown'; if(defined &Win32::BuildNumber) { $hash->{system_type} = 'windows-activestate'; } elsif($Config{myuname} =~ /strawberry-perl/) { $hash->{system_type} = 'windows-strawberry'; } elsif($hash->{compiler_type} eq 'microsoft') { $hash->{system_type} = 'windows-microsoft'; } else { my $uname_exe = which('uname'); if($uname_exe) { my $uname = `$uname_exe`; if($uname =~ /^(MINGW)(32|64)_NT/) { $hash->{system_type} = 'windows-' . lc $1; } } } } elsif($^O =~ /^(VMS)$/) { # others probably belong in here... $hash->{system_type} = lc $^O; } else { $hash->{system_type} = 'unix'; } $hash->{cpu}{count} = exists $ENV{ALIEN_CPU_COUNT} && $ENV{ALIEN_CPU_COUNT} > 0 ? $ENV{ALIEN_CPU_COUNT} : _cpu_count(); $hash->{cpu}{arch} = _cpu_arch(\%Config); } # Retrieve number of available CPU cores. Adopted from # # which is in turn adopted from Test::Smoke::Util with improvements. sub _cpu_count { local $ENV{PATH} = $ENV{PATH}; if( $^O ne 'MSWin32' ) { $ENV{PATH} = "/usr/sbin:/sbin:/usr/bin:/bin:$ENV{PATH}"; } $ENV{PATH} =~ /(.*)/; $ENV{PATH} = $1; ## Remove tainted'ness my $ncpu = 1; OS_CHECK: { local $_ = lc $^O; /linux/ && do { my ( $count, $fh ); if ( open $fh, '<', '/proc/stat' ) { $count = grep { /^cpu\d/ } <$fh>; close $fh; } $ncpu = $count if $count; last OS_CHECK; }; /bsd|darwin|dragonfly/ && do { chomp( my @output = `sysctl -n hw.ncpu 2>/dev/null` ); $ncpu = $output[0] if @output; last OS_CHECK; }; /aix/ && do { my @output = `lparstat -i 2>/dev/null | grep "^Online Virtual CPUs"`; if ( @output ) { $output[0] =~ /(\d+)\n$/; $ncpu = $1 if $1; } if ( !$ncpu ) { @output = `pmcycles -m 2>/dev/null`; if ( @output ) { $ncpu = scalar @output; } else { @output = `lsdev -Cc processor -S Available 2>/dev/null`; $ncpu = scalar @output if @output; } } last OS_CHECK; }; /gnu/ && do { chomp( my @output = `nproc 2>/dev/null` ); $ncpu = $output[0] if @output; last OS_CHECK; }; /haiku/ && do { my @output = `sysinfo -cpu 2>/dev/null | grep "^CPU #"`; $ncpu = scalar @output if @output; last OS_CHECK; }; /hp-?ux/ && do { my $count = grep { /^processor/ } `ioscan -fkC processor 2>/dev/null`; $ncpu = $count if $count; last OS_CHECK; }; /irix/ && do { my @out = grep { /\s+processors?$/i } `hinv -c processor 2>/dev/null`; $ncpu = (split ' ', $out[0])[0] if @out; last OS_CHECK; }; /osf|solaris|sunos|svr5|sco/ && do { if (-x '/usr/sbin/psrinfo') { my $count = grep { /on-?line/ } `psrinfo 2>/dev/null`; $ncpu = $count if $count; } else { my @output = grep { /^NumCPU = \d+/ } `uname -X 2>/dev/null`; $ncpu = (split ' ', $output[0])[2] if @output; } last OS_CHECK; }; /mswin|mingw|msys|cygwin/ && do { if (exists $ENV{NUMBER_OF_PROCESSORS}) { $ncpu = $ENV{NUMBER_OF_PROCESSORS}; } last OS_CHECK; }; warn "CPU count: unknown operating system"; } $ncpu = 1 if (!$ncpu || $ncpu < 1); $ncpu; } sub _cpu_arch { my ($my_config) = @_; my $arch = {}; my %Config = %$my_config; die "Config missing archname" unless exists $Config{archname}; die "Config missing ptrsize" unless exists $Config{ptrsize}; if( $Config{archname} =~ m/ \b x64 \b # MSWin32-x64 | \b x86_64 \b # x86_64-linux | \b amd64 \b # amd64-freebsd /ix) { $arch = { name => 'x86_64' }; } elsif( $Config{archname} =~ m/ \b x86 \b # MSWin32-x86 | \b i386 \b # freebsd-i386 | \b i486 \b # i486-linux | \b i686 \b # i686-cygwin /ix ) { $arch = { name => 'x86' }; } elsif( $Config{archname} =~ m/ \b darwin \b /ix ) { chomp( my $hw_machine = `sysctl -n hw.machine 2>/dev/null` ); HW_MACHINE: for($hw_machine) { $_ eq 'arm64' && do { $arch = { name => 'aarch64' }; last HW_MACHINE; }; $_ eq 'x86_64' && do { $arch = { name => $Config{ptrsize} == 8 ? 'x86_64' : 'x86' }; last HW_MACHINE; }; $_ eq 'i386' && do { $arch = { name => 'x86' }; last HW_MACHINE; }; $_ eq 'Power Macintosh' && do { $arch = { name => $Config{ptrsize} == 8 ? 'ppc64' : 'ppc' }; last HW_MACHINE; }; warn "Architecture detection: unknown macOS arch hw.machine = $_, ptrsize = $Config{ptrsize}"; $arch = { name => 'unknown' }; } } elsif( $Config{archname} =~ / \b aarch64 \b /ix ) { $arch = { name => 'aarch64' }; # ARM64 } elsif( $Config{archname} =~ m/ \b arm-linux-gnueabi \b /ix ) { # 32-bit ARM soft-float $arch = { name => 'armel' }; } elsif( $Config{archname} =~ m/ \b arm-linux-gnueabihf \b /ix ) { # 32-bit ARM hard-float $arch = { name => 'armhf' }; } unless(exists $arch->{name}) { warn "Architecture detection: Unknown archname '$Config{archname}'."; $arch->{name} = 'unknown'; } return $arch; } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Core::Setup - Core setup plugin =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; # already loaded =head1 DESCRIPTION This plugin does some core setup for you. =head1 SEE ALSO L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Core/Override.pm000044400000003344152346246310012056 0ustar00package Alien::Build::Plugin::Core::Override; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; # ABSTRACT: Core override plugin our $VERSION = '2.74'; # VERSION sub init { my($self, $meta) = @_; $meta->default_hook( override => sub { my($build) = @_; return $ENV{ALIEN_INSTALL_TYPE} || ''; }, ); } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Core::Override - Core override plugin =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; # already loaded =head1 DESCRIPTION This plugin implements the C environment variable. =head1 SEE ALSO L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Core/FFI.pm000044400000003353152346246310010703 0ustar00package Alien::Build::Plugin::Core::FFI; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; # ABSTRACT: Core FFI plugin our $VERSION = '2.74'; # VERSION sub init { my($self, $meta) = @_; $meta->default_hook( $_ => sub {}, ) for qw( build_ffi gather_ffi ); $meta->prop->{destdir_ffi_filter} = '^dynamic'; } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Core::FFI - Core FFI plugin =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; # already loaded =head1 DESCRIPTION This plugin helps make the build_ffi work. You should not need to interact with it directly. =head1 SEE ALSO L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Core/CleanInstall.pm000044400000004262152346246310012650 0ustar00package Alien::Build::Plugin::Core::CleanInstall; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; use Path::Tiny (); # ABSTRACT: Implementation for clean_install hook. our $VERSION = '2.74'; # VERSION sub init { my($self, $meta) = @_; $meta->default_hook( clean_install => sub { my($build) = @_; my $root = Path::Tiny->new( $build->runtime_prop->{prefix} ); if(-d $root) { foreach my $child ($root->children) { if($child->basename eq '_alien') { $build->log("keeping $child"); } else { $build->log("removing $child"); $child->remove_tree({ safe => 0}); } } } } ); } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Core::CleanInstall - Implementation for clean_install hook. =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; # already loaded =head1 DESCRIPTION This plugin implements the default C hook. You shouldn't use it directly. =head1 SEE ALSO L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Core/Download.pm000044400000012676152346246310012056 0ustar00package Alien::Build::Plugin::Core::Download; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; use Path::Tiny (); use Alien::Build::Util qw( _mirror ); # ABSTRACT: Core download plugin our $VERSION = '2.74'; # VERSION sub _hook { my($build) = @_; my $res = $build->fetch; if($res->{type} =~ /^(?:html|dir_listing)$/) { my $type = $res->{type}; $type =~ s/_/ /; $build->log("decoding $type"); $res = $build->decode($res); } if($res->{type} eq 'list') { my $orig = $res; $res = $build->prefer($res); my @exclude; if($build->meta->prop->{start_url} =~ /^https:/) { @{ $res->{list} } = grep { $_->{url} =~ /https:/ ? 1 : do { push @exclude, $_->{url}; 0; } } @{ $res->{list} }; } if(@{ $res->{list} } == 0) { my @excluded = map { $_->{url} } @{ $orig->{list} }; if(@excluded) { if(@excluded > 15) { splice @excluded , 14; push @excluded, '...'; } $build->log("These files were excluded by the filter stage:"); $build->log("excluded $_") for @excluded; } else { $build->log("No files found prior to the filter stage"); } die "no matching files in listing"; } my $version = $res->{list}->[0]->{version}; my($pick, @other) = map { $_->{url} } @{ $res->{list} }; if(@other > 8) { splice @other, 7; push @other, '...'; } $build->log("candidate *$pick"); $build->log("candidate $_") for @other; if(@exclude) { if(@exclude > 8) { splice @exclude, 7; push @exclude, '...'; } $build->log("excluded insecure URLs:"); $build->log($_) for @exclude; } $res = $build->fetch($pick); if($version) { $version =~ s/\.+$//; $build->log("setting version based on archive to $version"); $build->runtime_prop->{version} = $version; } } if($res->{type} eq 'file') { my $alienfile = $res->{filename}; $build->log("downloaded $alienfile"); if($res->{content}) { my $tmp = Alien::Build::TempDir->new($build, "download"); my $path = Path::Tiny->new("$tmp/$alienfile"); $path->spew_raw($res->{content}); $build->install_prop->{download} = $path->stringify; $build->install_prop->{complete}->{download} = 1; $build->install_prop->{download_detail}->{"$path"}->{protocol} = $res->{protocol} if defined $res->{protocol}; return $build; } elsif($res->{path}) { if(defined $res->{tmp} && !$res->{tmp}) { if(-e $res->{path}) { $build->install_prop->{download} = $res->{path}; $build->install_prop->{complete}->{download} = 1; $build->install_prop->{download_detail}->{$res->{path}}->{protocol} = $res->{protocol} if defined $res->{protocol}; } else { die "not a file or directory: @{[ $res->{path} ]}"; } } else { my $from = Path::Tiny->new($res->{path}); my $tmp = Alien::Build::TempDir->new($build, "download"); my $to = Path::Tiny->new("$tmp/@{[ $from->basename ]}"); if(-d $res->{path}) { # Please note: _mirror and Alien::Build::Util are ONLY # allowed to be used by core plugins. If you are writing # a non-core plugin it may be removed. That is why it # is private. _mirror $from, $to; } else { require File::Copy; File::Copy::copy( "$from" => "$to", ) || die "copy $from => $to failed: $!"; } $build->install_prop->{download} = $to->stringify; $build->install_prop->{complete}->{download} = 1; $build->install_prop->{download_detail}->{"$to"}->{protocol} = $res->{protocol} if defined $res->{protocol}; } return $build; } die "file without content or path"; } die "unknown fetch response type: @{[ $res->{type} ]}"; } sub init { my($self, $meta) = @_; $meta->default_hook(download => \&_hook); } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Core::Download - Core download plugin =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; # already loaded =head1 DESCRIPTION This plugin does some core download logic. =head1 SEE ALSO L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Prefer.pod000044400000003751152346246310011002 0ustar00# PODNAME: Alien::Build::Plugin::Prefer # ABSTRACT: Prefer Alien::Build plugins # VERSION __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Prefer - Prefer Alien::Build plugins =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; share { start_url 'http://ftp.gnu.org/gnu/make'; plugin 'Download'; }; =head1 DESCRIPTION Prefer plugins sort Decode plugins decode HTML and FTP file listings. Normally you will want to use the L plugin which will automatically load the appropriate Prefer plugins. =over 4 =item L Filter out known bad versions from a candidate list. =item L Require specific known good versions from a candidate list. =item L Sort candidates by version. =back =head1 SEE ALSO L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Build.pod000044400000004664152346246310010622 0ustar00# PODNAME: Alien::Build::Plugin::Build # ABSTRACT: Build Alien::Build plugins # VERSION __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Build - Build Alien::Build plugins =head1 VERSION version 2.74 =head1 SYNOPSIS For autoconf: use alienfile; plugin 'Build::Autoconf'; for unixy (even on windows): use alienfile; plugin 'Build::MSYS'; =head1 DESCRIPTION Build plugins provide tools for building your package once it has been downloaded and extracted. =over 4 =item L For dealing with packages that are configured using autotools, or an autotools-like C script. =item L For dealing with packages that are configured and built using CMake. =item L For dealing with packages that do not require any build, and can just be copied into their final location. =item L For dealing with packages that require MSYS on Windows in order to build. This plugin is typically a no-op on other platforms. =item L For dealing with packages that require Make to build. Several flavors of Make are supported, including GNU Make and BSD Make. =item L Add other Ls as dependencies. =back =head1 SEE ALSO L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Build/Autoconf.pm000044400000022647152346246310012233 0ustar00package Alien::Build::Plugin::Build::Autoconf; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; use constant _win => $^O eq 'MSWin32'; use Path::Tiny (); use File::Temp (); # ABSTRACT: Autoconf plugin for Alien::Build our $VERSION = '2.74'; # VERSION has with_pic => 1; has ffi => 0; has msys_version => undef; has config_site => sub { my $config_site = "# file automatically generated by @{[ __FILE__ ]}\n"; $config_site .= ". $ENV{CONFIG_SITE}\n" if defined $ENV{CONFIG_SITE}; $config_site .= ". $ENV{ALIEN_BUILD_SITE_CONFIG}\n" if defined $ENV{ALIEN_BUILD_SITE_CONFIG}; # on some platforms autofools sorry I mean autotools likes to install into # exec_prefix/lib64 or even worse exec_prefix/lib/64 but that messes everything # else up so we try to nip that in the bud. $config_site .= "libdir='\${prefix}/lib'\n"; $config_site; }; sub init { my($self, $meta) = @_; $meta->apply_plugin('Build::MSYS', (defined $self->msys_version ? (msys_version => $self->msys_version) : ()), ); $meta->prop->{destdir} = 1; $meta->prop->{autoconf} = 1; my $intr = $meta->interpolator; my $set_autoconf_prefix = sub { my($build) = @_; my $prefix = $build->install_prop->{prefix}; die "Prefix is not set. Did you forget to run 'make alien_prefix'?" unless $prefix; if(_win) { $prefix = Path::Tiny->new($prefix)->stringify; $prefix =~ s!^([a-z]):!/$1!i if _win; } $build->install_prop->{autoconf_prefix} = $prefix; }; $meta->before_hook( build_ffi => $set_autoconf_prefix, ); # FFI mode undocumented for now... if($self->ffi) { $meta->add_requires('configure', 'Alien::Build::Plugin::Build::Autoconf' => '0.41'); $meta->default_hook( build_ffi => [ '%{configure} --enable-shared --disable-static --libdir=%{.install.autoconf_prefix}/dynamic', '%{make}', '%{make} install', ] ); if($^O eq 'MSWin32') { # for whatever reason autohell puts the .dll files in bin, even if you # point --bindir somewhere else. $meta->after_hook( build_ffi => sub { my($build) = @_; my $prefix = $build->install_prop->{autoconf_prefix}; my $bin = Path::Tiny->new($ENV{DESTDIR})->child($prefix)->child('bin'); my $lib = Path::Tiny->new($ENV{DESTDIR})->child($prefix)->child('dynamic'); if(-d $bin) { foreach my $from (grep { $_->basename =~ /.dll$/i } $bin->children) { $lib->mkpath; my $to = $lib->child($from->basename); $build->log("copy $from => $to"); $from->copy($to); } } } ); } } $meta->around_hook( build => sub { my $orig = shift; my $build = shift; $set_autoconf_prefix->($build); my $prefix = $build->install_prop->{autoconf_prefix}; die "Prefix is not set. Did you forget to run 'make alien_prefix'?" unless $prefix; local $ENV{CONFIG_SITE} = do { my $site_config = Path::Tiny->new(File::Temp::tempdir( CLEANUP => 1 ))->child('config.site'); $site_config->spew($self->config_site); "$site_config"; }; $intr->replace_helper( configure => sub { my $configure; if($build->meta_prop->{out_of_source}) { my $extract = $build->install_prop->{extract}; $configure = _win ? "sh $extract/configure" : "$extract/configure"; } else { $configure = _win ? 'sh ./configure' : './configure'; } $configure .= ' --prefix=' . $prefix; $configure .= ' --with-pic' if $self->with_pic; $configure; } ); my $ret = $orig->($build, @_); if(_win) { my $real_prefix = Path::Tiny->new($build->install_prop->{prefix}); my @pkgconf_dirs; push @pkgconf_dirs, Path::Tiny->new($ENV{DESTDIR})->child($prefix)->child("$_/pkgconfig") for qw(lib share); # for any pkg-config style .pc files that are dropped, we need # to convert the MSYS /C/Foo style paths to C:/Foo for my $pkgconf_dir (@pkgconf_dirs) { if(-d $pkgconf_dir) { foreach my $pc_file ($pkgconf_dir->children) { $pc_file->edit(sub {s/\Q$prefix\E/$real_prefix->stringify/eg;}); } } } } $ret; }, ); $intr->add_helper( configure => sub { my $configure = _win ? 'sh configure' : './configure'; $configure .= ' --with-pic' if $self->with_pic; $configure; }, ); $meta->default_hook( build => [ '%{configure} --disable-shared', '%{make}', '%{make} install', ] ); $self; } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Build::Autoconf - Autoconf plugin for Alien::Build =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; plugin 'Build::Autoconf'; =head1 DESCRIPTION This plugin provides some tools for building projects that use autoconf. The main thing this provides is a C helper, documented below and the default build stage, which is: '%{configure} --disable-shared', '%{make}', '%{make} install', On Windows, this plugin also pulls in the L which is required for autoconf style projects on windows. The other thing that this plugin does is that it does a double staged C install. The author has found this improves the overall reliability of L modules that are based on autoconf packages. This plugin supports out-of-source builds (known in autoconf terms as "VPATH" builds) via the meta property C. B: by itself, this plugin is only intended for use on packages that include a C script. For packages that expect you to use Autotools to generate a configure script before building, you can use L to generate the C script and use this plugin to run it. For more details see the documentation for L. =head1 PROPERTIES =head2 with_pic Adds C<--with-pic> option when running C. If supported by your package, it will generate position independent code on platforms that support it. This is required to XS modules, and generally what you want. autoconf normally ignores options that it does not understand, so it is usually a safe and reasonable default to include it. A small number of projects look like they use autoconf, but are really an autoconf style interface with a different implementation. They may fail if you try to provide it with options such as C<--with-pic> that they do not recognize. Such packages are the rationale for this property. =head2 msys_version The version of L required if it is deemed necessary. If L isn't needed (if running under Unix, or MSYS2, for example) this will do nothing. =head2 config_site The content for the generated C. =head1 HELPERS =head2 configure %{configure} The correct incantation to start an autoconf style C script on your platform. Some reasonable default flags will be provided. =head1 ENVIRONMENT =over 4 =item C For a share install, this plugin needs to alter the behavior of autotools using C. It does this by generating a C file on the fly, and setting the C environment variable. In the event that you already have your own C set, that file will be sourced from the generated one, so your local defaults should still be honored, unless it is one that needs to be changed for a share install. In particular, the C directory must be overridden, because on some platforms dynamic libraries will otherwise be placed in directories that L doesn't normally look in. Since the alienized package will be installed in a share directory, and not a system directory, that should be fine. =item C If defined, this file will be also be sourced in the generated C. This allows you to have local defaults for alien share installs only. =back =head1 SEE ALSO L, L, L, L, L L L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Build/MSYS.pm000044400000007323152346246310011242 0ustar00package Alien::Build::Plugin::Build::MSYS; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; use File::Which (); use Env qw( @PATH ); # ABSTRACT: MSYS plugin for Alien::Build our $VERSION = '2.74'; # VERSION has msys_version => '0.07'; sub init { my($self, $meta) = @_; if($self->msys_version ne '0.07') { $meta->add_requires('configure' => 'Alien::Build::Plugin::Build::MSYS' => '0.84'); } if(_win_and_needs_msys($meta)) { $meta->add_requires('share' => 'Alien::MSYS' => $self->msys_version); $meta->around_hook( $_ => sub { my $orig = shift; my $build = shift; local $ENV{PATH} = $ENV{PATH}; unshift @PATH, Alien::MSYS::msys_path(); $orig->($build, @_); }, ) for qw( build build_ffi test_share test_ffi ); } if($^O eq 'MSWin32') { # Most likely if we are trying to build something unix-y and # we are using MSYS, then we want to use the make that comes # with MSYS. $meta->interpolator->replace_helper( make => sub { 'make' }, ); } $self; } sub _win_and_needs_msys { my($meta) = @_; # check to see if we are running on windows. # if we are running on windows, check to see if # it is MSYS2, then we can just use that. Otherwise # we are probably on Strawberry, or (less likely) # VC Perl, in which case we will still need Alien::MSYS return 0 unless $^O eq 'MSWin32'; return 0 if $meta->prop->{platform}->{system_type} eq 'windows-mingw'; return 1; } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Build::MSYS - MSYS plugin for Alien::Build =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; plugin 'Build::MSYS'; =head1 DESCRIPTION This plugin sets up the MSYS environment for your build on Windows. It does not do anything on non-windows platforms. MSYS provides the essential tools for building software that is normally expected in a UNIX or POSIX environment. This like C, C and C. To provide MSYS, this plugin uses L. =head1 PROPERTIES =head2 msys_version The version of L required if it is deemed necessary. If L isn't needed (if running under Unix, or MSYS2, for example) this will do nothing. =head1 HELPERS =head2 make %{make} On windows the default C<%{make}> helper is replace with the make that comes with L. This is almost certainly what you want, as most unix style make projects will not build with C or C typically used by Perl on Windows. =head1 SEE ALSO L, L, L, L, L L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Build/CMake.pm000044400000013335152346246310011427 0ustar00package Alien::Build::Plugin::Build::CMake; use strict; use warnings; use 5.008004; use Config; use Alien::Build::Plugin; use Capture::Tiny qw( capture ); # ABSTRACT: CMake plugin for Alien::Build our $VERSION = '2.74'; # VERSION sub cmake_generator { if($^O eq 'MSWin32') { return 'MinGW Makefiles' if is_dmake(); { my($out, $err) = capture { system $Config{make}, '/?' }; return 'NMake Makefiles' if $out =~ /NMAKE/; } { my($out, $err) = capture { system $Config{make}, '--version' }; return 'MinGW Makefiles' if $out =~ /GNU Make/; } die 'make not detected'; } else { return 'Unix Makefiles'; } } sub init { my($self, $meta) = @_; $meta->prop->{destdir} = $^O eq 'MSWin32' ? 0 : 1; $meta->add_requires('configure' => 'Alien::Build::Plugin::Build::CMake' => '0.99'); $meta->add_requires('share' => 'Alien::cmake3' => '0.02'); if(is_dmake()) { # even on at least some older versions of strawberry that do not # use it, come with gmake in the PATH. So to save us the effort # of having to install Alien::gmake lets just use that version # if we can find it! my $found_gnu_make = 0; foreach my $exe (qw( gmake make mingw32-make )) { my($out, $err) = capture { system $exe, '--version' }; if($out =~ /GNU Make/) { $meta->interpolator->replace_helper('make' => sub { $exe }); $found_gnu_make = 1; last; } } if(!$found_gnu_make) { $meta->add_requires('share' => 'Alien::gmake' => '0.20'); $meta->interpolator->replace_helper('make' => sub { require Alien::gmake; Alien::gmake->exe }); } } $meta->interpolator->replace_helper('cmake' => sub { require Alien::cmake3; Alien::cmake3->exe }); $meta->interpolator->add_helper('cmake_generator' => \&cmake_generator); my @args = ( -G => '%{cmake_generator}', '-DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=true', '-DCMAKE_INSTALL_PREFIX:PATH=%{.install.prefix}', '-DCMAKE_INSTALL_LIBDIR:PATH=lib', '-DCMAKE_MAKE_PROGRAM:PATH=%{make}', ); $meta->prop->{plugin_build_cmake}->{args} = \@args; $meta->default_hook( build => [ ['%{cmake}', @args, '%{.install.extract}' ], ['%{make}' ], ['%{make}', 'install' ], ], ); # TODO: handle destdir on windows ?? } my $is_dmake; sub is_dmake { unless(defined $is_dmake) { if($^O eq 'MSWin32') { my($out, $err) = capture { system $Config{make}, '-V' }; $is_dmake = $out =~ /dmake/ ? 1 : 0; } else { $is_dmake = 0; } } $is_dmake; } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Build::CMake - CMake plugin for Alien::Build =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; share { plugin 'Build::CMake'; build [ # this is the default build step, if you do not specify one. [ '%{cmake}', @{ meta->prop->{plugin_build_cmake}->{args} }, # ... put extra cmake args here ... '%{.install.extract}' ], '%{make}', '%{make} install', ]; }; =head1 DESCRIPTION This plugin helps build alienized projects that use C. The intention is to make this a core L plugin if/when it becomes stable enough. This plugin provides a meta property C which may change over time but for the moment includes: -G %{cmake_generator} \ -DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=true \ -DCMAKE_INSTALL_PREFIX:PATH=%{.install.prefix} \ -DCMAKE_INSTALL_LIBDIR:PATH=lib \ -DCMAKE_MAKE_PROGRAM:PATH=%{make} This plugin supports out-of-source builds via the meta property C. =head1 METHODS =head2 cmake_generator Returns the C generator according to your Perl's C. =head2 is_dmake Returns true if your Perls C appears to be C. =head1 HELPERS =head2 cmake This plugin replaces the default C helper with the one that comes from L. =head2 cmake_generator This is the appropriate C generator to use based on the make used by your Perl. This is frequently C. One place where it may be different is if your Windows Perl uses C, which comes with Visual C++. =head2 make This plugin I replace the default C helper if the default C is not supported by C. This is most often an issue with older versions of Strawberry Perl which used C. On Perls that use C, this plugin will search for GNU Make in the PATH, and if it can't be found will fallback on using L. =head1 SEE ALSO =over 4 =item L =item L =item L =back =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Build/SearchDep.pm000044400000012556152346246310012311 0ustar00package Alien::Build::Plugin::Build::SearchDep; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; use Text::ParseWords qw( shellwords ); # ABSTRACT: Add dependencies to library and header search path our $VERSION = '2.74'; # VERSION has aliens => {}; has public_I => 0; has public_l => 0; sub init { my($self, $meta) = @_; $meta->add_requires('configure' => 'Alien::Build::Plugin::Build::SearchDep' => '0.35'); $meta->add_requires('share' => 'Env::ShellWords' => 0.01); if($self->public_I || $self->public_l) { $meta->add_requires('configure' => 'Alien::Build::Plugin::Build::SearchDep' => '0.53'); } my @aliens; if(ref($self->aliens) eq 'HASH') { @aliens = keys %{ $self->aliens }; $meta->add_requires('share' => $_ => $self->aliens->{$_}) for @aliens; } else { @aliens = ref $self->aliens ? @{ $self->aliens } : ($self->aliens); $meta->add_requires('share' => $_ => 0) for @aliens; } $meta->around_hook( build => sub { my($orig, $build) = @_; local $ENV{CFLAGS} = $ENV{CFLAGS}; local $ENV{CXXFLAGS} = $ENV{CXXFLAGS}; local $ENV{LDFLAGS} = $ENV{LDFLAGS}; tie my @CFLAGS, 'Env::ShellWords', 'CFLAGS'; tie my @CXXFLAGS, 'Env::ShellWords', 'CXXFLAGS'; tie my @LDFLAGS, 'Env::ShellWords', 'LDFLAGS'; my $cflags = $build->install_prop->{plugin_build_searchdep_cflags} = []; my $ldflags = $build->install_prop->{plugin_build_searchdep_ldflags} = []; my $libs = $build->install_prop->{plugin_build_searchdep_libs} = []; foreach my $other (@aliens) { my $other_cflags; my $other_libs; if($other->install_type('share')) { $other_cflags = $other->cflags_static; $other_libs = $other->libs_static; } else { $other_cflags = $other->cflags; $other_libs = $other->libs; } unshift @$cflags, grep /^-I/, shellwords($other_cflags); unshift @$ldflags, grep /^-L/, shellwords($other_libs); unshift @$libs, grep /^-l/, shellwords($other_libs); } unshift @CFLAGS, @$cflags; unshift @CXXFLAGS, @$cflags; unshift @LDFLAGS, @$ldflags; $orig->($build); }, ); $meta->after_hook( gather_share => sub { my($build) = @_; $build->runtime_prop->{libs} = '' unless defined $build->runtime_prop->{libs}; $build->runtime_prop->{libs_static} = '' unless defined $build->runtime_prop->{libs_static}; if($self->public_l) { $build->runtime_prop->{$_} = join(' ', _space_escape(@{ $build->install_prop->{plugin_build_searchdep_libs} })) . ' ' . $build->runtime_prop->{$_} for qw( libs libs_static ); } $build->runtime_prop->{$_} = join(' ', _space_escape(@{ $build->install_prop->{plugin_build_searchdep_ldflags} })) . ' ' . $build->runtime_prop->{$_} for qw( libs libs_static ); if($self->public_I) { $build->runtime_prop->{cflags} = '' unless defined $build->runtime_prop->{cflags}; $build->runtime_prop->{cflags_static} = '' unless defined $build->runtime_prop->{cflags_static}; $build->runtime_prop->{$_} = join(' ', _space_escape(@{ $build->install_prop->{plugin_build_searchdep_cflags} })) . ' ' . $build->runtime_prop->{$_} for qw( cflags cflags_static ); } }, ); } sub _space_escape { map { my $str = $_; $str =~ s{(\s)}{\\$1}g; $str; } @_; } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Build::SearchDep - Add dependencies to library and header search path =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; plugin 'Build::SearchDep' => ( aliens => [qw( Alien::Foo Alien::Bar )], ); =head1 DESCRIPTION This plugin adds the other aliens as prerequisites, and adds their header and library search path to C and C environment variable, so that tools that use them (like autoconf) can pick them up. =head1 PROPERTIES =head2 aliens Either a list reference or hash reference of the other aliens. If a hash reference then the keys are the class names and the values are the versions of those classes. =head2 public_I Include the C<-I> flags when setting the runtime cflags property. =head2 public_l Include the C<-l> flags when setting the runtime libs property. =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Build/Make.pm000044400000010233152346246310011316 0ustar00package Alien::Build::Plugin::Build::Make; use strict; use warnings; use 5.008004; use Carp (); use Capture::Tiny qw( capture ); use Alien::Build::Plugin; # ABSTRACT: Make plugin for Alien::Build our $VERSION = '2.74'; # VERSION has '+make_type' => undef; sub init { my($self, $meta) = @_; $meta->add_requires('configure', 'Alien::Build::Plugin::Build::Make', '0.99'); my $type = $self->make_type; return unless defined $type; $type = 'gmake' if $^O eq 'MSWin32' && $type eq 'umake'; if($type eq 'nmake') { $meta->interpolator->replace_helper( make => sub { 'nmake' } ); } elsif($type eq 'dmake') { $meta->interpolator->replace_helper( make => sub { 'dmake' } ); } elsif($type eq 'gmake') { my $found = 0; foreach my $make (qw( gmake make mingw32-make )) { my($out, $err) = capture { system $make, '--version' }; if($out =~ /GNU Make/) { $meta->interpolator->replace_helper( make => sub { $make } ); $found = 1; } } unless($found) { $meta->add_requires('share' => 'Alien::gmake' => '0.20'); $meta->interpolator->replace_helper('make' => sub { require Alien::gmake; Alien::gmake->exe }); } } elsif($type eq 'umake') { # nothing } else { Carp::croak("unknown make type = ", $self->make_type); } } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Build::Make - Make plugin for Alien::Build =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; # For a recipe that requires GNU Make plugin 'Build::Make' => 'gmake'; =head1 DESCRIPTION By default L provides a helper for the C that is used by Perl and L itself. This is handy, because it is the one make that you can mostly guarantee that you will have. Unfortunately it may be a C that isn't supported by the library or tool that you are trying to alienize. This is mostly a problem on Windows, where the supported Cs for years were Microsoft's C and Sun's C, which many open source projects do not use. This plugin will alter the L recipe to use a different C. It may (as in the case of C / L) automatically download and install an alienized version of that C if it is not already installed. This plugin should NOT be used with other plugins that replace the C helper, like L, L, L. This plugin is intended instead for projects that use vanilla makefiles of a specific type. This plugin is for now distributed separately from L, but the intention is for it to soon become a core plugin for L. =head1 PROPERTIES =head2 make_type The make type needed by the L recipe: =over 4 =item dmake Sun's dmake. =item gmake GNU Make. =item nmake Microsoft's nmake. It comes with Visual C++. =item umake Any UNIX C Usually either BSD or GNU Make. =back =head1 HELPERS =head2 make %{make} This plugin may change the make helper used by your L recipe. =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Build/Copy.pm000044400000007517152346246310011366 0ustar00package Alien::Build::Plugin::Build::Copy; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; use Path::Tiny (); # ABSTRACT: Copy plugin for Alien::Build our $VERSION = '2.74'; # VERSION sub init { my($self, $meta) = @_; $meta->add_requires( 'configure', __PACKAGE__, 0); if($^O eq 'MSWin32') { $meta->register_hook(build => sub { my($build) = @_; my $stage = Path::Tiny->new($build->install_prop->{stage})->canonpath; $build->system(qq{xcopy . "$stage" /E}); }); } elsif($^O eq 'darwin') { # On recent macOS -pPR is the same as -aR # on older Mac OS X (10.5 at least) -a is not supported but -pPR is. # Looks like -pPR should also work on coreutils if for some reason # someone is using coreutils on macOS, although there are semantic # differences between -pPR and -aR on coreutils, that may or may not be # important enough to care about. $meta->register_hook(build => [ 'cp -pPR * "%{.install.stage}"', ]); } else { # TODO: some platforms might not support -a # I think most platforms will support -r $meta->register_hook(build => [ 'cp -aR * "%{.install.stage}"', ]); } } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Build::Copy - Copy plugin for Alien::Build =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; plugin 'Build::Copy'; =head1 DESCRIPTION This plugin copies all of the files from the source to the staging prefix. This is mainly useful for software packages that are provided as binary blobs. It works on both Unix and Windows using the appropriate commands for those platforms without having worry about the platform details in your L. If you want to filter add or remove files from what gets installed you can use a C hook. build { ... before 'build' => sub { # remove or modify files }; plugin 'Build::Copy'; ... }; Some packages might have binary blobs on some platforms and require build from source on others. In that situation you can use C statements with the appropriate logic in your L. configure { # normally the Build::Copy plugin will insert itself # as a config requires, but since it is only used # on some platforms, you will want to explicitly # require it in your alienfile in case you build your # alien dist on a platform that doesn't use it. requires 'Alien::Build::Plugin::Build::Copy'; }; build { ... if($^O eq 'linux') { start_url 'http://example.com/binary-blob-linux.tar.gz'; plugin 'Download'; plugin 'Extract' => 'tar.gz'; plugin 'Build::Copy'; } else { start_url 'http://example.com/source.tar.gz'; plugin 'Download'; plugin 'Extract' => 'tar.gz'; plugin 'Build::Autoconf'; } }; =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Digest.pod000044400000004273152346246310010776 0ustar00# PODNAME: Alien::Build::Plugin::Digest # ABSTRACT: Fetch Alien::Digest plugins # VERSION __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Digest - Fetch Alien::Digest plugins =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; share { start_url 'http://ftp.gnu.org/gnu/make/make-3.75.tar.gz'; plugin 'Digest' => [ SHA256 => '2bc876304905aee78abf0f7163ba55a2efcec803034f75c75d1b94650c36aba7'; plugin 'Download'; }; =head1 DESCRIPTION Digest plugins checks the cryptographic signatures of downloaded files. Typically you will probably want to use SHA256 via the L. =over 4 =item L Negotiate the most appropriate plugin to calculate digest. =item L Use the XS based L for computing SHA digests. This is the default since L comes with recent versions of Perl. =item L Use the pure-perl based L for computing SHA digests. =back =head1 SEE ALSO L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Download.pod000044400000003122152346246310011316 0ustar00# PODNAME: Alien::Build::Plugin::Download # ABSTRACT: Download Alien::Build plugins # VERSION __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Download - Download Alien::Build plugins =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile share { start_url 'http://ftp.gnu.org/gnu/make'; plugin 'Download'; }; =head1 DESCRIPTION Download plugins download packages from the internet. =over 4 =item L =back =head1 SEE ALSO L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Gather/IsolateDynamic.pm000044400000006505152346246310013530 0ustar00package Alien::Build::Plugin::Gather::IsolateDynamic; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; use Path::Tiny (); use Alien::Build::Util qw( _destdir_prefix ); use File::Copy (); # ABSTRACT: Plugin to gather dynamic libraries into a separate directory our $VERSION = '2.74'; # VERSION sub init { my($self, $meta) = @_; # plugin was introduced in 0.42, but had a bug which was fixed in 0.48 $meta->add_requires('share' => 'Alien::Build::Plugin::Gather::IsolateDynamic' => '0.48' ); $meta->after_hook( gather_share => sub { my($build) = @_; $build->log("Isolating dynamic libraries ..."); my $install_root; if($build->meta_prop->{destdir}) { my $destdir = $ENV{DESTDIR}; $install_root = Path::Tiny->new(_destdir_prefix($ENV{DESTDIR}, $build->install_prop->{prefix})); } else { $install_root = Path::Tiny->new($build->install_prop->{stage}); } foreach my $dir (map { $install_root->child($_) } qw( bin lib )) { next unless -d $dir; foreach my $from ($dir->children) { next unless $from->basename =~ /\.so/ || $from->basename =~ /\.(dylib|bundle|la|dll|dll\.a)$/; my $to = $install_root->child('dynamic', $from->basename); $to->parent->mkpath; unlink "$to" if -e $to; $build->log("move @{[ $from->parent->basename ]}/@{[ $from->basename ]} => dynamic/@{[ $to->basename ]}"); File::Copy::move("$from", "$to") || die "unable to move $from => $to $!"; } } $build->log(" Done!"); }, ); } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Gather::IsolateDynamic - Plugin to gather dynamic libraries into a separate directory =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; plugin 'Gather::IsolateDynamic'; =head1 DESCRIPTION This plugin moves dynamic libraries from the C and C directories and puts them in their own C directory. This allows them to be used by FFI modules, but to be ignored by XS modules. This plugin provides the equivalent functionality of the C attribute from L. =head1 SEE ALSO L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Prefer/GoodVersion.pm000044400000010320152346246310013060 0ustar00package Alien::Build::Plugin::Prefer::GoodVersion; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; use Carp (); # ABSTRACT: Plugin to filter known good versions our $VERSION = '2.74'; # VERSION has '+filter' => sub { Carp::croak("The filter property is required for the Prefer::GoodVersion plugin") }; sub init { my($self, $meta) = @_; $meta->add_requires('configure', __PACKAGE__, '1.44'); my $filter; if(ref($self->filter) eq '') { my $string = $self->filter; $filter = sub { my($file) = @_; $file->{version} eq $string; }; } elsif(ref($self->filter) eq 'ARRAY') { my %filter = map { $_ => 1 } @{ $self->filter }; $filter = sub { my($file) = @_; !! $filter{$file->{version}}; }; } elsif(ref($self->filter) eq 'CODE') { my $code = $self->filter; $filter = sub { !! $code->($_[0]) }; } else { Carp::croak("unknown filter type for Prefer::GoodVersion"); } $meta->around_hook( prefer => sub { my($orig, $build, @therest) = @_; my $res1 = $orig->($build, @therest); return $res1 unless $res1->{type} eq 'list'; return { type => 'list', list => [ grep { $filter->($_) } @{ $res1->{list} } ], }; }, ); } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Prefer::GoodVersion - Plugin to filter known good versions =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; plugin 'Prefer::GoodVersion' => '1.2.3'; =head1 DESCRIPTION This plugin allows you to specify one or more good versions of a library. This doesn't affect a system install at all. This plugin does the opposite of the C plugin. You need need a Prefer plugin that filters and sorts files first. You may specify the filter in one of three ways: =over =item as a string Filter any files that match the given version. use alienfile; plugin 'Prefer::GoodVersion' => '1.2.3'; =item as an array Filter all files that match any of the given versions. use alienfile; plugin 'Prefer::GoodVersion' => [ '1.2.3', '1.2.4' ]; =item as a code reference Filter any files return a true value. use alienfile; plugin 'Prefer::GoodVersion' => sub { my($file) = @_; $file->{version} eq '1.2.3'; # same as the string version above }; =back This plugin can also be used to filter known good versions of a library on just one platform. For example, if you know that version 1.2.3 if good on windows, but the default logic is fine on other platforms: use alienfile; plugin 'Prefer::GoodVersion' => '1.2.3' if $^O eq 'MSWin32'; =head1 PROPERTIES =head2 filter Filter entries that match the filter. =head1 CAVEATS If you are using the string or array mode, then you need an existing Prefer plugin that sets the version number for each file candidate, such as L. Unless you want to exclude the latest version from a share install, this plugin isn't really that useful. It has no effect on system installs, which may not be obvious at first. =head1 SEE ALSO =over 4 =item L =item L =item L =back =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Prefer/BadVersion.pm000044400000010223152346246310012660 0ustar00package Alien::Build::Plugin::Prefer::BadVersion; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; use Carp (); # ABSTRACT: Plugin to filter out known bad versions our $VERSION = '2.74'; # VERSION has '+filter' => sub { Carp::croak("The filter property is required for the Prefer::BadVersion plugin") }; sub init { my($self, $meta) = @_; $meta->add_requires('configure', __PACKAGE__, '1.05'); my $filter; if(ref($self->filter) eq '') { my $string = $self->filter; $filter = sub { my($file) = @_; $file->{version} ne $string; }; } elsif(ref($self->filter) eq 'ARRAY') { my %filter = map { $_ => 1 } @{ $self->filter }; $filter = sub { my($file) = @_; ! $filter{$file->{version}}; }; } elsif(ref($self->filter) eq 'CODE') { my $code = $self->filter; $filter = sub { ! $code->($_[0]) }; } else { Carp::croak("unknown filter type for Prefer::BadVersion"); } $meta->around_hook( prefer => sub { my($orig, $build, @therest) = @_; my $res1 = $orig->($build, @therest); return $res1 unless $res1->{type} eq 'list'; return { type => 'list', list => [ grep { $filter->($_) } @{ $res1->{list} } ], }; }, ); } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Prefer::BadVersion - Plugin to filter out known bad versions =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; plugin 'Prefer::BadVersion' => '1.2.3'; =head1 DESCRIPTION This plugin allows you to easily filter out known bad versions of libraries in a share install. It doesn't affect a system install at all. You need a Prefer plugin that filters and sorts files first. You may specify the filter in one of three ways: =over =item as a string Filter out any files that match the given version. use alienfile; plugin 'Prefer::BadVersion' => '1.2.3'; =item as an array Filter out all files that match any of the given versions. use alienfile; plugin 'Prefer::BadVersion' => [ '1.2.3', '1.2.4' ]; =item as a code reference Filter out any files return a true value. use alienfile; plugin 'Prefer::BadVersion' => sub { my($file) = @_; $file->{version} eq '1.2.3'; # same as the string version above }; =back This plugin can also be used to filter out known bad versions of a library on just one platform. For example, if you know that version 1.2.3 if bad on windows, but okay on other platforms: use alienfile; plugin 'Prefer::BadVersion' => '1.2.3' if $^O eq 'MSWin32'; =head1 PROPERTIES =head2 filter Filter out entries that match the filter. =head1 CAVEATS If you are using the string or array mode, then you need an existing Prefer plugin that sets the version number for each file candidate, such as L. Unless you want to exclude the latest version from a share install, this plugin isn't really that useful. It has no effect on system installs, which may not be obvious at first. =head1 SEE ALSO =over 4 =item L =item L =item L =back =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Prefer/SortVersions.pm000044400000007147152346246310013317 0ustar00package Alien::Build::Plugin::Prefer::SortVersions; use strict; use warnings; use 5.008004; use Alien::Build::Plugin; # ABSTRACT: Plugin to sort candidates by most recent first our $VERSION = '2.74'; # VERSION has 'filter' => undef; has '+version' => qr/([0-9](?:[0-9\.]*[0-9])?)/; sub init { my($self, $meta) = @_; $meta->add_requires('share' => 'Sort::Versions' => 0); $meta->register_hook( prefer => sub { my(undef, $res) = @_; my $cmp = sub { my($A,$B) = map { ($_ =~ $self->version)[0] } @_; Sort::Versions::versioncmp($B,$A); }; my @list = sort { $cmp->($a->{filename}, $b->{filename}) } map { ($_->{version}) = $_->{filename} =~ $self->version; $_ } grep { $_->{filename} =~ $self->version } grep { defined $self->filter ? $_->{filename} =~ $self->filter : 1 } @{ $res->{list} }; return { type => 'list', list => \@list, }; }); } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Prefer::SortVersions - Plugin to sort candidates by most recent first =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; plugin 'Prefer::SortVersions'; =head1 DESCRIPTION Note: in most case you will want to use L instead. It picks the appropriate fetch plugin based on your platform and environment. In some cases you may need to use this plugin directly instead. This Prefer plugin sorts the packages that were retrieved from a dir listing, either directly from a Fetch plugin, or from a Decode plugin. It Returns a listing with the items sorted from post preferable to least, and filters out any undesirable candidates. This plugin updates the file list to include the versions that are extracted, so they can be used by other plugins, such as L. =head1 PROPERTIES =head2 filter This is a regular expression that lets you filter out files that you do not want to consider downloading. For example, if the directory listing contained tarballs and readme files like this: foo-1.0.0.tar.gz foo-1.0.0.readme You could specify a filter of C to make sure only tarballs are considered for download. =head2 version Regular expression to parse out the version from a filename. The regular expression should store the result in C<$1>. The default C is frequently reasonable. =head1 SEE ALSO L, L, L, L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Gather.pod000044400000003311152346246310010761 0ustar00# PODNAME: Alien::Build::Plugin::Gather # ABSTRACT: Gather Alien::Build plugins # VERSION __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Gather - Gather Alien::Build plugins =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; plugin 'Gather::IsolateDynamic'; # just as an example =head1 DESCRIPTION Gather plugins enhance L recipes at the gather stage, either during a C or C install. =over 4 =item L Isolate dynamic libraries (C<.so>, <.DLL> or <.dylib>) so that they aren't used by XS. =back =head1 SEE ALSO L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/PkgConfig.pod000044400000004311152346246310011417 0ustar00# PODNAME: Alien::Build::Plugin::PkgConfig # ABSTRACT: PkgConfig Alien::Build plugins # VERSION __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::PkgConfig - PkgConfig Alien::Build plugins =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; plugin 'PkgConfig' => ( pkg_name => 'foo', ); =head1 DESCRIPTION PkgConfig plugins use C or a compatible library to retrieve flags at probe and gather stages. =over 4 =item L Use the command-line C or C to get compiler and linker flags. =item L Use the XS L to get compiler and linker flags. =item L Convert .pc file to use static linkage by default. =item L Choose the best plugin to do C work. The best choice is typically platform and configuration dependent. =item L Use the pure-perl L to get compiler and linker flags. =back =head1 SEE ALSO L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Plugin/Fetch.pod000044400000005152152346246310010605 0ustar00# PODNAME: Alien::Build::Plugin::Fetch # ABSTRACT: Fetch Alien::Build plugins # VERSION __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Plugin::Fetch - Fetch Alien::Build plugins =head1 VERSION version 2.74 =head1 SYNOPSIS use alienfile; share { start_url 'http://ftp.gnu.org/gnu/make'; plugin 'Download'; }; =head1 DESCRIPTION Fetch plugins retrieve single resources from the internet. The difference between a Fetch plugin and a Download plugin is that Download plugin may fetch several resources from the internet (usually using a Fetch plugin), before finding the final archive. Normally you will not need to use Fetch plugins directly but should instead use the L plugin, which will pick the best plugins for your given URL. =over 4 =item L Fetch using the C command. =item L Fetch using L. =item L Fetch using L. =item L Fetch from a local file. This is typically used to bundle packages with your L. =item L Fetch from a local directory. This is typically used to bundle packages with your L. =item L Fetch using L. Use of FTP should be discouraged as of this writing (August 2022). =item L Fetch using C. =back =head1 SEE ALSO L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Util.pm000044400000011504152346246310007063 0ustar00package Alien::Build::Util; use strict; use warnings; use 5.008004; use Exporter qw( import ); use Path::Tiny qw( path ); use Config; # ABSTRACT: Private utility functions for Alien::Build our $VERSION = '2.74'; # VERSION our @EXPORT_OK = qw( _mirror _dump _destdir_prefix _perl_config _ssl_reqs _has_ssl ); # usage: _mirror $source_directory, $dest_direction, \%options # # options: # - filter -> regex for files that should match # - empty_directory -> if true, create all directories, including empty ones. # - verbose -> turn on verbosity sub _mirror { my($src_root, $dst_root, $opt) = @_; ($src_root, $dst_root) = map { path($_) } ($src_root, $dst_root); $opt ||= {}; require Alien::Build; require File::Find; require File::Copy; File::Find::find({ wanted => sub { next unless -e $File::Find::name; my $src = path($File::Find::name)->relative($src_root); return if $opt->{filter} && "$src" !~ $opt->{filter}; return if "$src" eq '.'; my $dst = $dst_root->child("$src"); $src = $src->absolute($src_root); if(-l "$src") { unless(-d $dst->parent) { Alien::Build->log("mkdir -p @{[ $dst->parent ]}") if $opt->{verbose}; $dst->parent->mkpath; } # TODO: rmtree if a directory? if(-e "$dst") { unlink "$dst" } my $target = readlink "$src"; Alien::Build->log("ln -s $target $dst") if $opt->{verbose}; symlink($target, $dst) || die "unable to symlink $target => $dst"; } elsif(-d "$src") { if($opt->{empty_directory}) { unless(-d $dst) { Alien::Build->log("mkdir $dst") if $opt->{verbose}; mkdir($dst) || die "unable to create directory $dst: $!"; } } } elsif(-f "$src") { unless(-d $dst->parent) { Alien::Build->log("mkdir -p @{[ $dst->parent ]}") if $opt->{verbose}; $dst->parent->mkpath; } # TODO: rmtree if a directory? if(-e "$dst") { unlink "$dst" } Alien::Build->log("cp $src $dst") if $opt->{verbose}; File::Copy::cp("$src", "$dst") || die "copy error $src => $dst: $!"; if($] < 5.012 && -x "$src" && $^O ne 'MSWin32') { # apparently Perl 5.8 and 5.10 do not preserver perms my $mode = [stat "$src"]->[2] & oct(777); eval { chmod $mode, "$dst" }; } } }, no_chdir => 1, }, "$src_root"); (); } sub _dump { if(eval { require YAML }) { return YAML::Dump(@_); } else { require Data::Dumper; return Data::Dumper::Dumper(@_); } } sub _destdir_prefix { my($destdir, $prefix) = @_; $prefix =~ s{^/?([a-z]):}{$1}i if $^O eq 'MSWin32'; path($destdir)->child($prefix)->stringify; } sub _perl_config { my($key) = @_; $Config{$key}; } sub _ssl_reqs { return { 'Net::SSLeay' => '1.49', 'IO::Socket::SSL' => '1.56', }; } sub _has_ssl { my %reqs = %{ _ssl_reqs() }; eval { require Net::SSLeay; die "need Net::SSLeay $reqs{'Net::SSLeay'}" unless Net::SSLeay->VERSION($reqs{'Net::SSLeay'}); require IO::Socket::SSL; die "need IO::Socket::SSL $reqs{'IO::Socket::SSL'}" unless IO::Socket::SSL->VERSION($reqs{'IO::Socket::SSL'}); }; $@ eq ''; } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Util - Private utility functions for Alien::Build =head1 VERSION version 2.74 =head1 DESCRIPTION This module contains some private utility functions used internally by L. It shouldn't be used by any distribution other than C. That includes L plugins that are not part of the L core. You have been warned. The functionality within may be removed at any time! =head1 SEE ALSO L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Interpolate.pm000044400000014607152346246310010443 0ustar00package Alien::Build::Interpolate; use strict; use warnings; use 5.008004; # ABSTRACT: Advanced interpolation engine for Alien builds our $VERSION = '2.74'; # VERSION sub new { my($class) = @_; my $self = bless { helper => {}, classes => {}, }, $class; $self; } sub add_helper { my $self = shift; my $name = shift; my $code = shift; if(defined $self->{helper}->{$name}) { require Carp; Carp::croak("duplicate implementation for interpolated key $name"); } my $require; if(ref $_[0] eq 'CODE') { $require = shift; } else { $require = []; while(@_) { my $module = shift; my $version = shift; $version ||= 0; push @$require, $module => $version; } } $self->{helper}->{$name} = Alien::Build::Helper->new( $name, $code, $require, ); } sub replace_helper { my $self = shift; my($name) = @_; delete $self->{helper}->{$name}; $self->add_helper(@_); } sub has_helper { my($self, $name) = @_; return unless defined $self->{helper}->{$name}; my @require = $self->{helper}->{$name}->require; while(@require) { my $module = shift @require; my $version = shift @require; { my $pm = "$module.pm"; $pm =~ s/::/\//g; require $pm; $module->VERSION($version) if $version; } unless($self->{classes}->{$module}) { if($module->can('alien_helper')) { my $helpers = $module->alien_helper; foreach my $k (keys %$helpers) { $self->{helper}->{$k}->code($helpers->{$k}); } } $self->{classes}->{$module} = 1; } } my $code = $self->{helper}->{$name}->code; return unless defined $code; if(ref($code) ne 'CODE') { my $perl = $code; package Alien::Build::Interpolate::Helper; $code = sub { ## no critic my $value = eval $perl; ## use critic die $@ if $@; $value; }; } $code; } sub execute_helper { my($self, $name) = @_; my $code = $self->has_helper($name); die "no helper defined for $name" unless defined $code; $code->(); } sub _get_prop { my($name, $prop, $orig) = @_; $name =~ s/^\./alien./; if($name =~ /^(.*?)\.(.*)$/) { my($key,$rest) = ($1,$2); return _get_prop($rest, $prop->{$key}, $orig); } elsif(exists $prop->{$name}) { return $prop->{$name}; } else { require Carp; Carp::croak("No property $orig is defined"); } } sub interpolate { my($self, $string, $build) = @_; my $prop = defined $build && eval { $build->isa('Alien::Build') } ? $build->_command_prop : {}; $string =~ s{(?execute_helper($1)}eg; $string =~ s{(?{helper}->{$_}; $helper ? $helper->require : (); } $string =~ m{(?{helper} }) { $helper{$name} = $self->{helper}->{$name}->clone; } my $new = bless { helper => \%helper, classes => Storable::dclone($self->{classes}), }, ref $self; } package Alien::Build::Helper; sub new { my($class, $name, $code, $require) = @_; bless { name => $name, code => $code, require => $require, }, $class; } sub name { shift->{name} } sub code { my($self, $code) = @_; $self->{code} = $code if $code; $self->{code}; } sub require { my($self) = @_; if(ref $self->{require} eq 'CODE') { $self->{require} = [ $self->{require}->($self) ]; } @{ $self->{require} }; } sub clone { my($self) = @_; my $class = ref $self; $class->new( $self->name, $self->code, [ $self->require ], ); } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Interpolate - Advanced interpolation engine for Alien builds =head1 VERSION version 2.74 =head1 CONSTRUCTOR =head2 new my $intr = Alien::Build::Interpolate->new; =head2 add_helper $intr->add_helper($name => $code); $intr->add_helper($name => $code, %requirements); =head2 replace_helper $intr->replace_helper($name => $code); $intr->replace_helper($name => $code, %requirements); =head2 has_helper my $coderef = $intr->has_helper($name); Used to discover if a helper exists with the given name. Returns the code reference. =head2 execute_helper my $value = $intr->execute_helper($name); This evaluates the given helper and returns the result. =head2 interpolate my $string = $intr->interpolate($template, $build); my $string = $intr->interpolate($template); This takes a template and fills in the appropriate values of any helpers used in the template. [version 2.58] If you pass in an L instance as the second argument, you can use properties as well as helpers in the template. Example: my $patch = $intr->template("%{.install.patch}/foo-%{.runtime.version}.patch", $build); =head2 requires my %requires = $intr->requires($template); This returns a hash of modules required in order to execute the given template. The keys are the module names and the values are the versions. Version will be set to C<0> if any version is sufficient. =head2 clone my $intr2 = $intr->clone; This creates a clone of the interpolator. =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Version/Basic.pm000044400000011373152346246310010620 0ustar00package Alien::Build::Version::Basic; use strict; use warnings; use 5.008004; use Carp (); use Exporter qw( import ); use overload '<=>' => sub { shift->cmp(@_) }, 'cmp' => sub { shift->cmp(@_) }, '""' => sub { shift->as_string }, bool => sub { 1 }, fallback => 1; our @EXPORT_OK = qw( version ); # ABSTRACT: Very basic version object for Alien::Build our $VERSION = '2.74'; # VERSION sub new { my($class, $value) = @_; $value =~ s/\.$//; # trim trailing dot Carp::croak("invalud version: $value") unless $value =~ /^[0-9]+(\.[0-9]+)*$/; bless \$value, $class; } sub version ($) { my($value) = @_; __PACKAGE__->new($value); } sub as_string { my($self) = @_; "@{[ $$self ]}"; } sub cmp { my @x = split /\./, ${$_[0]}; my @y = split /\./, ${ref($_[1]) ? $_[1] : version($_[1])}; while(@x or @y) { my $x = (shift @x) || 0; my $y = (shift @y) || 0; return $x <=> $y if $x <=> $y; } 0; } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Version::Basic - Very basic version object for Alien::Build =head1 VERSION version 2.74 =head1 SYNOPSIS OO interface: use Alien::Build::Version::Basic; my $version = Alien::Build::Version::Basic->new('1.2.3'); if($version > '1.2.2') # true { ... } Function interface: use Alien::Build::Version::Basic qw( version ); if(version('1.2.3') > version('1.2.2')) # true { ... } my @sorted = sort map { version($_) } qw( 2.1 1.2.3 1.2.2 ); # will come out in the order 1.2.2, 1.2.3, 2.1 =head1 DESCRIPTION This module provides a very basic class for comparing versions. This is already a crowded space on CPAN. Parts of L already use L, which is fine for sorting versions. Sometimes you need to compare to see if versions match exact I, and the best candidates (such as L on CPAN compare C<1.2.3.0> and C<1.2.3> as being different. This class compares those two as the same. This class is also quite limited, in that it only works with version schemes using a doted version numbers or real numbers with a fixed number of digits. Versions with: dashes, letters, hex digits, or anything else are not supported. This class overloads both C=E> and C to compare the version in the way that you would expect for version numbers. This way you can compare versions like numbers, or sort them using sort. if(version($v1) > version($v2)) { ... } my @sorted = sort map { version($_) } @unsorted; it also overloads C<""> to stringify as whatever string value you passed to the constructor. =head1 CONSTRUCTOR =head2 new my $version = Alien::Build::Version::Basic->new($value); This is the long form of the constructor, if you don't want to import anything into your namespace. =head2 version my $version = version($value); This is the short form of the constructor, if you are sane. It is NOT exported by default so you will have to explicitly import it. =head1 METHODS =head2 as_string my $string = $version->as_string; my $string = "$version"; Returns the string representation of the version object. =head2 cmp my $bool = $version->cmp($other); my $bool = $version <=> $other; my $bool = $version cmp $other; Returns C<-1>, C<0> or C<1> just like the regular C=E> and C operators. Although C<$version> must be a version object, C<$other> may be either a version object, or a string that could be used to create a valid version object. =head1 SEE ALSO =over 4 =item L Good, especially if you have to support rpm style versions (like C<1.2.3-2-b>) or don't care if trailing zeros (C<1.2.3> vs C<1.2.3.0>) are treated as different values. =item L Problematic for historical reasons. =back =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Build/Temp.pm000044400000005564152346246310007064 0ustar00package Alien::Build::Temp; use strict; use warnings; use 5.008004; use Carp (); use Path::Tiny (); use File::Temp (); use File::Spec (); # ABSTRACT: Temp Dir support for Alien::Build our $VERSION = '2.74'; # VERSION # problem with vanilla File::Temp is that is often uses # as /tmp that has noexec turned on. Workaround is to # create a temp directory in the build directory, but # we have to be careful about cleanup. This puts all that # (attempted) carefulness in one place so that when we # later discover it isn't so careful we can fix it in # one place rather thabn alllll the places that we need # temp directories. # we also have a speical case for Windows, which often # has problems with long paths if we try to use the # current directory for temp files, so for those we # use the system tmp directory. my %root; sub _root { return File::Spec->tmpdir if $^O eq 'MSWin32'; my $root = Path::Tiny->new(-d "_alien" ? "_alien/tmp" : ".tmp")->absolute; unless(-d $root) { mkdir $root or die "unable to create temp root $!"; } # TODO: doesn't account for fork... my $lock = $root->child("l$$"); unless(-f $lock) { open my $fh, '>', $lock; close $fh; } $root{"$root"} = 1; $root; } END { foreach my $root (keys %root) { my $lock = Path::Tiny->new($root)->child("l$$"); unlink $lock; # try to delete if possible. # if not possible then punt rmdir $root if -d $root; } } sub newdir { my $class = shift; Carp::croak "uneven" if @_ % 2; File::Temp->newdir(DIR => _root, @_); } sub new { my $class = shift; Carp::croak "uneven" if @_ % 2; File::Temp->new(DIR => _root, @_); } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Build::Temp - Temp Dir support for Alien::Build =head1 VERSION version 2.74 =head1 DESCRIPTION This class is private to L. =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Util.pm000044400000005651152346246310006032 0ustar00package Alien::Util; use strict; use warnings; use Exporter qw( import ); # ABSTRACT: Alien Utilities used at build and runtime our $VERSION = '2.74'; # VERSION our @EXPORT_OK = qw( version_cmp ); # Sort::Versions isn't quite the same algorithm because it differs in # behaviour with leading zeroes. # See also https://dev.gentoo.org/~mgorny/pkg-config-spec.html#version-comparison sub version_cmp { my @x = (shift =~ m/([0-9]+|[a-z]+)/ig); my @y = (shift =~ m/([0-9]+|[a-z]+)/ig); while(@x and @y) { my $x = shift @x; my $x_isnum = $x =~ m/[0-9]/; my $y = shift @y; my $y_isnum = $y =~ m/[0-9]/; if($x_isnum and $y_isnum) { # Numerical comparison return $x <=> $y if $x != $y; } elsif(!$x_isnum && !$y_isnum) { # Alphabetic comparison return $x cmp $y if $x ne $y; } else { # Of differing types, the numeric one is newer return $x_isnum - $y_isnum; } } # Equal so far; the longer is newer return @x <=> @y; } 1; __END__ =pod =encoding UTF-8 =head1 NAME Alien::Util - Alien Utilities used at build and runtime =head1 VERSION version 2.74 =head1 SYNOPSIS use Alien::Util qw( version_cmp ); =head1 DESCRIPTION This module contains some functions used by both the L build-time and run-time for Alien. =head2 version_cmp $cmp = version_cmp($x, $y) Comparison method used by L, L and L. May be useful to implement custom comparisons, or for subclasses to overload to get different version comparison semantics than the default rules, for packages that have some other rules than the F behaviour. Should return a number less than, equal to, or greater than zero; similar in behaviour to the C<< <=> >> and C operators. =head1 SEE ALSO L, L, L =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Base.pm000044400000070333152346246310005766 0ustar00package Alien::Base; use strict; use warnings; use 5.008004; use Carp; use Path::Tiny (); use Scalar::Util qw/blessed/; use Capture::Tiny 0.17 qw/capture_stdout/; use Text::ParseWords qw/shellwords/; use Alien::Util; # ABSTRACT: Base classes for Alien:: modules our $VERSION = '2.74'; # VERSION sub import { my $class = shift; return if $class eq __PACKAGE__; return if $class->runtime_prop; return if $class->install_type('system'); require DynaLoader; # Sanity check in order to ensure that dist_dir can be found. # This will throw an exception otherwise. $class->dist_dir; # get a reference to %Alien::MyLibrary::AlienLoaded # which contains names of already loaded libraries # this logic may be replaced by investigating the DynaLoader arrays my $loaded = do { no strict 'refs'; no warnings 'once'; \%{ $class . "::AlienLoaded" }; }; my @libs = $class->split_flags( $class->libs ); my @L = grep { s/^-L// } map { "$_" } @libs; ## no critic (ControlStructures::ProhibitMutatingListFunctions) my @l = grep { /^-l/ } @libs; unshift @DynaLoader::dl_library_path, @L; my @libpaths; foreach my $l (@l) { next if $loaded->{$l}; my $path = DynaLoader::dl_findfile( $l ); unless ($path) { carp "Could not resolve $l"; next; } push @libpaths, $path; $loaded->{$l} = $path; } push @DynaLoader::dl_resolve_using, @libpaths; my @librefs = map { DynaLoader::dl_load_file( $_, 0x01 ) } grep !/\.(a|lib)$/, @libpaths; push @DynaLoader::dl_librefs, @librefs; } sub _dist_dir ($) { my($dist_name) = @_; my @pm = split /-/, $dist_name; $pm[-1] .= ".pm"; foreach my $inc (@INC) { my $pm = Path::Tiny->new($inc, @pm); if(-f $pm) { my $share = Path::Tiny->new($inc, qw( auto share dist ), $dist_name ); if(-d $share) { return $share->absolute->stringify; } last; } } Carp::croak("unable to find dist share directory for $dist_name"); } sub dist_dir { my $class = shift; my $dist = blessed $class || $class; $dist =~ s/::/-/g; my $dist_dir = $class->config('finished_installing') ? _dist_dir $dist : $class->config('working_directory'); croak "Failed to find share dir for dist '$dist'" unless defined $dist_dir && -d $dist_dir; return $dist_dir; } sub new { return bless {}, $_[0] } sub _flags { my($class, $key) = @_; my $config = $class->runtime_prop; my $flags = $config->{$key}; my $prefix = $config->{prefix}; $prefix =~ s{\\}{/}g if $^O =~ /^(MSWin32|msys)$/; my $distdir = $config->{distdir}; $distdir =~ s{\\}{/}g if $^O =~ /^(MSWin32|msys)$/; if(defined $flags && $prefix ne $distdir) { $flags = join ' ', map { my $flag = $_; $flag =~ s/^(-I|-L|-LIBPATH:)?\Q$prefix\E/$1$distdir/; $flag =~ s/(\s)/\\$1/g; $flag; } $class->split_flags($flags); } $flags; } sub cflags { my $class = shift; return $class->runtime_prop ? $class->_flags('cflags') : $class->_pkgconfig_keyword('Cflags'); } sub cflags_static { my $class = shift; return $class->runtime_prop ? $class->_flags('cflags_static') : $class->_pkgconfig_keyword('Cflags', 'static'); } sub libs { my $class = shift; return $class->runtime_prop ? $class->_flags('libs') : $class->_pkgconfig_keyword('Libs'); } sub libs_static { my $class = shift; return $class->runtime_prop ? $class->_flags('libs_static') : $class->_pkgconfig_keyword('Libs', 'static'); } sub version { my $self = shift; return $self->runtime_prop ? $self->runtime_prop->{version} : do { my $version = $self->config('version'); chomp $version; $version; }; } sub atleast_version { my $self = shift; my ($wantver) = @_; defined(my $version = $self->version) or croak "$self has no defined ->version"; return $self->version_cmp($version, $wantver) >= 0; } sub exact_version { my $self = shift; my ($wantver) = @_; defined(my $version = $self->version) or croak "$self has no defined ->version"; return $self->version_cmp($version, $wantver) == 0; } sub max_version { my $self = shift; my ($wantver) = @_; defined(my $version = $self->version) or croak "$self has no defined ->version"; return $self->version_cmp($version, $wantver) <= 0; } sub version_cmp { shift; goto &Alien::Util::version_cmp; } sub install_type { my $self = shift; my $type = $self->config('install_type'); return @_ ? $type eq $_[0] : $type; } sub _pkgconfig_keyword { my $self = shift; my $keyword = shift; my $static = shift; # use pkg-config if installed system-wide if ($self->install_type('system')) { my $name = $self->config('name'); require Alien::Base::PkgConfig; my $command = Alien::Base::PkgConfig->pkg_config_command . " @{[ $static ? '--static' : '' ]} --\L$keyword\E $name"; $! = 0; chomp ( my $pcdata = capture_stdout { system( $command ) } ); # if pkg-config fails for whatever reason, then we try to # fallback on alien_provides_* $pcdata = '' if $! || $?; $pcdata =~ s/\s*$//; if($self->config('system_provides')) { if(my $system_provides = $self->config('system_provides')->{$keyword}) { $pcdata = length $pcdata ? "$pcdata $system_provides" : $system_provides; } } return $pcdata; } # use parsed info from build .pc file my $dist_dir = $self->dist_dir; my @pc = $self->_pkgconfig(@_); my @strings = grep defined, map { $_->keyword($keyword, #{ pcfiledir => $dist_dir } ) } @pc; if(defined $self->config('original_prefix') && $self->config('original_prefix') ne $self->dist_dir) { my $dist_dir = $self->dist_dir; $dist_dir =~ s{\\}{/}g if $^O eq 'MSWin32'; my $old = quotemeta $self->config('original_prefix'); @strings = map { my $flag = $_; $flag =~ s{^(-I|-L|-LIBPATH:)?($old)}{$1.$dist_dir}e; $flag =~ s/(\s)/\\$1/g; $flag; } map { $self->split_flags($_) } @strings; } return join( ' ', @strings ); } sub _pkgconfig { my $self = shift; my %all = %{ $self->config('pkgconfig') }; # merge in found pc files require File::Find; my $wanted = sub { return if ( -d or not /\.pc$/ ); require Alien::Base::PkgConfig; my $pkg = Alien::Base::PkgConfig->new($_); $all{$pkg->{package}} = $pkg; }; File::Find::find( $wanted, $self->dist_dir ); croak "No Alien::Base::PkgConfig objects are stored!" unless keys %all; # Run through all pkgconfig objects and ensure that their modules are loaded: for my $pkg_obj (values %all) { my $perl_module_name = blessed $pkg_obj; my $pm = "$perl_module_name.pm"; $pm =~ s/::/\//g; eval { require $pm }; } return @all{@_} if @_; my $manual = delete $all{_manual}; if (keys %all) { return values %all; } else { return $manual; } } # helper method to call Alien::MyLib::ConfigData->config(@_) sub config { my $class = shift; $class = blessed $class || $class; if(my $ab_config = $class->runtime_prop) { my $key = shift; return $ab_config->{legacy}->{$key}; } my $config = $class . '::ConfigData'; my $pm = "$class/ConfigData.pm"; $pm =~ s{::}{/}g; eval { require $pm }; if($@) { warn "Cannot find either a share directory or a ConfigData module for $class.\n"; my $pm = "$class.pm"; $pm =~ s{::}{/}g; warn "($class loaded from $INC{$pm})\n" if $INC{$pm}; warn "Please see https://metacpan.org/pod/distribution/Alien-Build/lib/Alien/Build/Manual/FAQ.pod#Cannot-find-either-a-share-directory-or-a-ConfigData-module\n"; die $@; } return $config->config(@_); } # helper method to split flags based on the OS sub split_flags { my ($class, $line) = @_; if( $^O eq 'MSWin32' ) { $class->split_flags_windows($line); } else { # $os eq 'Unix' $class->split_flags_unix($line); } } sub split_flags_unix { my ($class, $line) = @_; shellwords($line); } sub split_flags_windows { # NOTE a better approach would be to write a function that understands cmd.exe metacharacters. my ($class, $line) = @_; # Double the backslashes so that when they are unescaped by shellwords(), # they become a single backslash. This should be fine on Windows since # backslashes are not used to escape metacharacters in cmd.exe. $line =~ s,\\,\\\\,g; shellwords($line); } sub dynamic_libs { my ($class) = @_; require FFI::CheckLib; my @find_lib_flags; if($class->install_type('system')) { if(my $prop = $class->runtime_prop) { if($prop->{ffi_checklib}->{system}) { push @find_lib_flags, @{ $prop->{ffi_checklib}->{system} }; } return FFI::CheckLib::find_lib( lib => $prop->{ffi_name}, @find_lib_flags ) if defined $prop->{ffi_name}; } my $name = $class->config('ffi_name'); unless(defined $name) { $name = $class->config('name'); $name = '' unless defined $name; # strip leading lib from things like libarchive or libffi $name =~ s/^lib//; # strip trailing version numbers $name =~ s/-[0-9\.]+$//; } my @libpath; if(defined $class->libs) { foreach my $flag ($class->split_flags($class->libs)) { if($flag =~ /^-L(.*)$/) { push @libpath, $1; } } } return FFI::CheckLib::find_lib(lib => $name, libpath => \@libpath, @find_lib_flags ); } else { my $dir = $class->dist_dir; my $dynamic = Path::Tiny->new($class->dist_dir, 'dynamic'); if(my $prop = $class->runtime_prop) { if($prop->{ffi_checklib}->{share}) { push @find_lib_flags, @{ $prop->{ffi_checklib}->{share_flags} }; } } if(-d $dynamic) { return FFI::CheckLib::find_lib( lib => '*', libpath => "$dynamic", systempath => [], ); } return FFI::CheckLib::find_lib( lib => '*', libpath => $dir, systempath => [], recursive => 1, ); } } sub bin_dir { my ($class) = @_; if($class->install_type('system')) { my $prop = $class->runtime_prop; return () unless defined $prop; return () unless defined $prop->{system_bin_dir}; return ref $prop->{system_bin_dir} ? @{ $prop->{system_bin_dir} } : ($prop->{system_bin_dir}); } else { my $dir = Path::Tiny->new($class->dist_dir, 'bin'); return -d $dir ? ("$dir") : (); } } sub dynamic_dir { my ($class) = @_; if($class->install_type('system')) { return (); } else { my $dir = Path::Tiny->new($class->dist_dir, 'dynamic'); return -d $dir ? ("$dir") : (); } } sub alien_helper { {}; } sub inline_auto_include { my ($class) = @_; return [] unless $class->config('inline_auto_include'); $class->runtime_prop->{inline_auto_include} || $class->config('inline_auto_include') } sub Inline { my ($class, $language) = @_; return unless defined $language; return if $language !~ /^(C|CPP)$/; my $config = { # INC should arguably be for -I flags only, but # this improves compat with ExtUtils::Depends. # see gh#107, gh#108 INC => $class->cflags, LIBS => $class->libs, }; if (@{ $class->inline_auto_include } > 0) { $config->{AUTO_INCLUDE} = join "\n", map { "#include \"$_\"" } @{ $class->inline_auto_include }; } $config; } { my %alien_build_config_cache; sub runtime_prop { my($class) = @_; if(ref($class)) { # called as an instance method. my $self = $class; $class = ref $self; return $self->{_alt}->{runtime_prop} if defined $self->{_alt}; } return $alien_build_config_cache{$class} if exists $alien_build_config_cache{$class}; $alien_build_config_cache{$class} ||= do { my $dist = ref $class ? ref $class : $class; $dist =~ s/::/-/g; my $dist_dir = eval { _dist_dir $dist }; return if $@; my $alien_json = Path::Tiny->new($dist_dir, '_alien', 'alien.json'); return unless -r $alien_json; my $json = $alien_json->slurp; require JSON::PP; my $config = JSON::PP::decode_json($json); $config->{distdir} = $dist_dir; $config; }; } } sub alt { my($old, $name) = @_; my $new = ref $old ? (ref $old)->new : $old->new; my $orig; if(ref($old) && defined $old->{_alt}) { $orig = $old->{_alt}->{orig} } else { $orig = $old->runtime_prop } require Storable; my $runtime_prop = Storable::dclone($orig); if($runtime_prop->{alt}->{$name}) { foreach my $key (keys %{ $runtime_prop->{alt}->{$name} }) { $runtime_prop->{$key} = $runtime_prop->{alt}->{$name}->{$key}; } } else { Carp::croak("no such alt: $name"); } $new->{_alt} = { runtime_prop => $runtime_prop, orig => $orig, }; $new; } sub alt_names { my($class) = @_; my $alts = $class->runtime_prop->{alt}; defined $alts ? sort keys %$alts : (); } sub alt_exists { my($class, $alt_name) = @_; my $alts = $class->runtime_prop->{alt}; defined $alts ? exists $alts->{$alt_name} && defined $alts->{$alt_name} : 0; } 1; =pod =encoding UTF-8 =head1 NAME Alien::Base - Base classes for Alien:: modules =head1 VERSION version 2.74 =head1 SYNOPSIS package Alien::MyLibrary; use strict; use warnings; use parent 'Alien::Base'; 1; (for details on the C or C and L that should be bundled with your L subclass, please see L). Then a C can use C in its C: use Alien::MyLibrary use ExtUtils::MakeMaker; use Alien::Base::Wrapper qw( Alien::MyLibrary !export ); use Config; WriteMakefile( ... Alien::Base::Wrapper->mm_args, ... ); Or if you prefer L, in its C: use Alien::MyLibrary; use Module::Build 0.28; # need at least 0.28 use Alien::Base::Wrapper qw( Alien::MyLibrary !export ); my $builder = Module::Build->new( ... Alien::Base::Wrapper->mb_args, ... ); $builder->create_build_script; Or if you are using L: use ExtUtils::MakeMaker; use ExtUtils::Depends; my $eud = ExtUtils::Depends->new(qw( MyLibrary::XS Alien::MyLibrary )); WriteMakefile( ... $eud->get_makefile_vars ); If you are using L instead of the recommended L and L, then in your C module, you may need something like this in your main C<.pm> file IF your library uses dynamic libraries: package MyLibrary::XS; use Alien::MyLibrary; # may only be needed if you are using Alien::Base::ModuleBuild ... Or you can use it from an FFI module: package MyLibrary::FFI; use Alien::MyLibrary; use FFI::Platypus; use FFI::CheckLib 0.28 qw( find_lib_or_die ); my $ffi = FFI::Platypus->new; $ffi->lib(find_lib_or_die lib => 'mylib', alien => ['Alien::MyLibrary']); $ffi->attach( 'my_library_function' => [] => 'void' ); You can even use it with L (C and C++ languages are supported): package MyLibrary::Inline; use Alien::MyLibrary; # Inline 0.56 or better is required use Inline 0.56 with => 'Alien::MyLibrary'; ... =head1 DESCRIPTION B: L is no longer bundled with L and has been spun off into a separate distribution. L will be a prerequisite for L until October 1, 2017. If you are using L you need to make sure it is declared as a C in your C. You may want to also consider using L and L as a more modern alternative. L comprises base classes to help in the construction of C modules. Modules in the L namespace are used to locate and install (if necessary) external libraries needed by other Perl modules. This is the documentation for the L module itself. If you are starting out you probably want to do so from one of these documents: =over 4 =item L For users of an C that is implemented using L. (The developer of C I provide the documentation necessary, but if not, this is the place to start). =item L If you are writing your own L based on L and L. =item L If you have a common question that has already been answered, like "How do I use L with some build system". =item L This is for the brave souls who want to write plugins that will work with L + L. =back Before using an L based L directly, please consider the following advice: If you are wanting to use an L based L with an XS module using L or L, it is highly recommended that you use L, rather than using the L directly, because it handles a number of sharp edges and avoids pitfalls common when trying to use an L directly with L. In the same vein, if you are wanting to use an L based L with an XS module using L it is highly recommended that you use L for the same reasons. As of version 0.28, L has a good interface for working with L based Ls in fallback mode, which is recommended. You should typically only be using an L based L directly, if you need to integrate it with some other system, or if it is a tool based L that you don't need to link. The above synopsis and linked manual documents will lead you down the right path, but it is worth knowing before you read further in this document. =head1 METHODS In the example snippets here, C represents any subclass of L. =head2 dist_dir my $dir = Alien::MyLibrary->dist_dir; Returns the directory that contains the install root for the packaged software, if it was built from install (i.e., if C is C). =head2 new my $alien = Alien::MyLibrary->new; Creates an instance of an L object. This is typically unnecessary. =head2 cflags my $cflags = Alien::MyLibrary->cflags; use Text::ParseWords qw( shellwords ); my @cflags = shellwords( Alien::MyLibrary->cflags ); Returns the C compiler flags necessary to compile an XS module using the alien software. If you need this in list form (for example if you are calling system with a list argument) you can pass this value into C from the Perl core L module. =head2 cflags_static my $cflags = Alien::MyLibrary->cflags_static; Same as C above, but gets the static compiler flags, if they are different. =head2 libs my $libs = Alien::MyLibrary->libs; use Text::ParseWords qw( shellwords ); my @cflags = shellwords( Alien::MyLibrary->libs ); Returns the library linker flags necessary to link an XS module against the alien software. If you need this in list form (for example if you are calling system with a list argument) you can pass this value into C from the Perl core L module. =head2 libs_static my $libs = Alien::MyLibrary->libs_static; Same as C above, but gets the static linker flags, if they are different. =head2 version my $version = Alien::MyLibrary->version; Returns the version of the alienized library or tool that was determined at install time. =head2 atleast_version =head2 exact_version =head2 max_version my $ok = Alien::MyLibrary->atleast_version($wanted_version); my $ok = Alien::MyLibrary->exact_version($wanted_version); my $ok = Alien::MyLibrary->max_version($wanted_version); Returns true if the version of the alienized library or tool is at least, exactly, or at most the version specified, respectively. =head2 version_cmp $cmp = Alien::MyLibrary->version_cmp($x, $y) Comparison method used by L, L and L. May be useful to implement custom comparisons, or for subclasses to overload to get different version comparison semantics than the default rules, for packages that have some other rules than the F behaviour. Should return a number less than, equal to, or greater than zero; similar in behaviour to the C<< <=> >> and C operators. =head2 install_type my $install_type = Alien::MyLibrary->install_type; my $bool = Alien::MyLibrary->install_type($install_type); Returns the install type that was used when C was installed. If a type is provided (the second form in the synopsis) returns true if the actual install type matches. Types include: =over 4 =item system The library was provided by the operating system =item share The library was not available when C was installed, so it was built from source code, either downloaded from the Internet or bundled with C. =back =head2 config my $value = Alien::MyLibrary->config($key); Returns the configuration data as determined during the install of C. For the appropriate config keys, see L. This is not typically used by L and L, but a compatible interface will be provided. =head2 dynamic_libs my @dlls = Alien::MyLibrary->dynamic_libs; my($dll) = Alien::MyLibrary->dynamic_libs; Returns a list of the dynamic library or shared object files for the alien software. =head2 bin_dir my(@dir) = Alien::MyLibrary->bin_dir Returns a list of directories with executables in them. For a C install this will be an empty list. For a C install this will be a directory under C named C if it exists. You may wish to override the default behavior if you have executables or scripts that get installed into non-standard locations. Example usage: use Env qw( @PATH ); unshift @PATH, Alien::MyLibrary->bin_dir; =head2 dynamic_dir my(@dir) = Alien::MyLibrary->dynamic_dir Returns the dynamic dir for a dynamic build (if the main build is static). For a C install this will be a directory under C named C if it exists. System builds return an empty list. Example usage: use Env qw( @PATH ); unshift @PATH, Alien::MyLibrary->dynamic_dir; =head2 alien_helper my $helpers = Alien::MyLibrary->alien_helper; Returns a hash reference of helpers provided by the Alien module. The keys are helper names and the values are code references. The code references will be executed at command time and the return value will be interpolated into the command before execution. The default implementation returns an empty hash reference, and you are expected to override the method to create your own helpers. For use with commands specified in and L or in your C when used with L. Helpers allow users of your Alien module to use platform or environment determined logic to compute command names or arguments in your installer logic. Helpers allow you to do this without making your Alien module a requirement when a build from source code is not necessary. As a concrete example, consider L, which provides the helper C: package Alien::gmake; ... sub alien_helper { my($class) = @_; return { gmake => sub { # return the executable name for GNU make, # usually either make or gmake depending on # the platform and environment $class->exe; } }, } Now consider L. C requires GNU Make to build from source code, but if the system C package is installed we don't need it. From the L of C: use alienfile; plugin 'Probe::CommandLine' => ( command => 'nasm', args => ['-v'], match => qr/NASM version/, ); share { ... plugin 'Extract' => 'tar.gz'; plugin 'Build::MSYS'; build [ 'sh configure --prefix=%{alien.install.prefix}', '%{gmake}', '%{gmake} install', ]; }; ... =head2 inline_auto_include my(@headers) = Alien::MyLibrary->inline_auto_include; List of header files to automatically include in inline C and C++ code when using L or L. This is provided as a public interface primarily so that it can be overridden at run time. This can also be specified in your C with L using the C property. =head2 runtime_prop my $hashref = Alien::MyLibrary->runtime_prop; Returns a hash reference of the runtime properties computed by L during its install process. If the L based L was not built using L, then this will return undef. =head2 alt my $new_alien = Alien::MyLibrary->alt($alt_name); my $new_alien = $old_alien->alt($alt_name); Returns an L instance with the alternate configuration. Some packages come with multiple libraries, and multiple C<.pc> files to use with them. This method can be used with C plugins to access different configurations. (It could also be used with non-pkg-config based packages too, though there are not as of this writing any build time plugins that take advantage of this feature). From your L use alienfile; plugin 'PkgConfig' => ( pkg_name => [ 'libfoo', 'libbar', ], ); Then in your base class works like normal: package Alien::MyLibrary; use parent qw( Alien::Base ); 1; Then you can use it: use Alien::MyLibrary; my $cflags = Alien::MyLibrary->alt('foo1')->cflags; my $libs = Alien::MyLibrary->alt('foo1')->libs; =head2 alt_names my @alt_names = Alien::MyLibrary->alt_names Returns the list of all available alternative configuration names. =head2 alt_exists my $bool = Alien::MyLibrary->alt_exists($alt_name) Returns true if the given alternative configuration exists. =head1 SUPPORT AND CONTRIBUTING First check the L for questions that have already been answered. IRC: #native on irc.perl.org L<(click for instant chatroom login)|http://chat.mibbit.com/#native@irc.perl.org> If you find a bug, please report it on the projects issue tracker on GitHub: =over 4 =item L =back Development is discussed on the projects google groups. This is also a reasonable place to post a question if you don't want to open an issue in GitHub. =over 4 =item L =back If you have implemented a new feature or fixed a bug, please open a pull request. =over 4 =item L =back =head1 SEE ALSO =over =item * L =item * L =item * L =item * L =back =head1 THANKS C was originally written by Joel Berger, and that code is still Copyright (C) 2012-2017 Joel Berger. It has the same license as the rest of the L. Special thanks for the early development of C go to: =over =item Christian Walde (Mithaldu) For productive conversations about component interoperability. =item kmx For writing Alien::Tidyp from which I drew many of my initial ideas. =item David Mertens (run4flat) For productive conversations about implementation. =item Mark Nunberg (mordy, mnunberg) For graciously teaching me about rpath and dynamic loading, =back =head1 AUTHOR Author: Graham Ollis Eplicease@cpan.orgE Contributors: Diab Jerius (DJERIUS) Roy Storey (KIWIROY) Ilya Pavlov David Mertens (run4flat) Mark Nunberg (mordy, mnunberg) Christian Walde (Mithaldu) Brian Wightman (MidLifeXis) Zaki Mughal (zmughal) mohawk (mohawk2, ETJ) Vikas N Kumar (vikasnkumar) Flavio Poletti (polettix) Salvador Fandiño (salva) Gianni Ceccarelli (dakkar) Pavel Shaydo (zwon, trinitum) Kang-min Liu (劉康民, gugod) Nicholas Shipp (nshp) Juan Julián Merelo Guervós (JJ) Joel Berger (JBERGER) Petr Písař (ppisar) Lance Wicks (LANCEW) Ahmad Fatoum (a3f, ATHREEF) José Joaquín Atria (JJATRIA) Duke Leto (LETO) Shoichi Kaji (SKAJI) Shawn Laffan (SLAFFAN) Paul Evans (leonerd, PEVANS) Håkon Hægland (hakonhagland, HAKONH) nick nauwelaerts (INPHOBIA) Florian Weimer =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2011-2022 by Graham Ollis. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut __END__ __POD__