Alien-Base-ModuleBuild

 view release on metacpan or  search on metacpan

lib/Alien/Base/ModuleBuild/FAQ.pod  view on Meta::CPAN

 perldoc Alien::Base::FAQ

=head1 DESCRIPTION

B<NOTE>: Please consider for new development of L<Alien>s that you use
L<Alien::Build> and L<alienfile> instead.  Like L<Alien::Base::ModuleBuild> they work
with L<Alien::Base>.  Unlike L<Alien::Base::ModuleBuild> they are more easily customized
and handle a number of corner cases better.  For a good place to start,
please see L<Alien::Base::ModuleBuild::API>.  Although the
Alien-Base / Alien-Build team will continue to maintain this module,
(we will continue to fix bugs where appropriate), we aren't adding any
new features to this module.

This document serves to answer the most frequently asked questions made by L<Alien::Base> authors.

=head2 What is Alien and Alien::Base?

Alien is 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<Alien>.  L<Alien::Base> is a base
class and framework for creating Alien distributions.  The idea is to address as many of the common challenges
to developing Alien modules in the base class to simplify the process.

=head2 How do I specify a minimum or exact version requirement for packages that use pkg-config?

The C<alien_version_check> attribute to L<Alien::Base::ModuleBuild> will be executed to determine if
the library is provided by the operating system.  The default for this is C<%{pkg_config} --modversion %n>
which simply checks to see if any version of that package is available, and prints the version
number.  You can use the C<--atleast-version>, C<--exact-version> options to require a specific range of versions,
but these flags do not work with the C<--modversion> flag, so be sure to invoke separately.

 use Alien::Base::ModuleBuild;
 Alien::Base::ModuleBuild->new(
   dist_name           => 'Alien::Foo',
   alien_name          => 'foo',
   configure_requires  => { 'Alien::Base::ModuleBuild' => '0.022' }, # required for %{pkg_config}
   alien_version_check => '%{pkg_config} --atleast-version 1.2.3 %n && %{pkg_config} --modversion %n',
   ...
 )->create_build_script;

It is better to use the built in C<%{pkg_config}> helper as it will use the system provided pkg-config
if it is available and fallback on the pure perl L<PkgConfig> if not.

You can also use C<--exact-version> to specify an exact version.

=head2 How to create an Alien module for packages that do not support pkg-config?

Although L<Alien::Base> and L<Alien::Base::ModuleBuild> assume packages come with a C<pkg-config>
C<.pc> file to determine compiler and linker flags by default, you can implement an Alien module
for packages that do use C<pkg-config> by following these tasks:

=over 4

=item subclass L<Alien::Base::ModuleBuild> and implement C<alien_check_installed_version>

Create a subclass of L<Alien::Base::ModuleBuild> and put it in the C<inc> directory of your distribution so
that it can be used during install but won't I<be installed>.

 # inc/My/ModuleBuild.pm
 package My::ModuleBuild;
 
 use parent 'Alien::Base::ModuleBuild';
 
 sub alien_check_installed_version {
   my($class) = @_;
 
   # determine if your library is already provided by the system
   my $version = ...;
 
   # return false if the library is NOT provided by the system
   return unless defined $version;
 
   # otherwise return the version detected
   # (if you cannot determine the version it
   #  is usually sufficient to return a true value)
   return $version;
 }

There are number of methods you can use to determine if the system provides your library.  From Perl
methods include L<Devel::CheckLib>, L<ExtUtils::CBuilder>, L<ExtUtils::CChecker>, L<Config::AutoConf>,
L<FFI::CheckLib> among others.  It is also frequently possible to determine if a library is installed
using a C<-config> suffixed program.  For example C<libxml2> comes with xml2-config which provides the
existence, compiler and linker flags it needs.  In my experience, however, most packages that provide a
C<-config> suffixed program also provide a C<pkg-config> interface as well.

=item implement C<alien_check_built_version> in your L<Alien::Base::ModuleBuild> subclass

You should also implement C<alien_check_build_version> which will be executed from the package build
root once the package is successfully built.

 # inc/My/ModuleBuild.pm
 package My::ModuleBuild;
 
 ...
 
 sub alien_check_built_version {
   my($self) = @_;
 
   my $version = ...
 
   # (Again, if you cannot determine the version,
   #  it is usually sufficent to return a true value)
   return $version;
 }

=item set C<alien_provides_cflags> and C<alien_provides_libs> in C<Build.PL>.

Add something like this to your C<Build.PL>:

 # Build.PL
 use lib 'inc';
 use My::ModuleBuild;
 
 My::ModuleBuild->new(
   ...
   alien_provides_cflags => '-I/usr/include/foo',
   alien_provides_libs   => '-L/usr/lib/foo -lfoo',
   ...
 );

Note that it is frequently sufficient to provide C<alien_provides_libs> and the appropriate C<-l> flag.
These flags will be used in the event that the system package can be found.  It is a good idea to verify

lib/Alien/Base/ModuleBuild/FAQ.pod  view on Meta::CPAN

=head3 GNU Makefiles?

Some packages require GNU Make's unique syntax.  Perl's L<Config> provides an entry for C<gmake>, but it is
frequently wrong.  Do not depend on it.  Instead you can use L<Alien::gmake> to provide a real GNU Make (either
from the operating system, or built from source):

 # Build.PL
 use Alien::Base::ModuleBuild;
 
 Alien::Base::ModuleBuild->new(
   ...
   alien_bin_requires => {
     'Alien::gmake' => 0.11, # needed for %{gmake} helper
   },
   alien_build_commands => [
     "%{gmake}",
   ],
   alien_install_commands => [
     "%{gmake} install",
   ],
   ...
 )->create_build_script;

=head2 When debugging my package build, I get different results!

If you get results from running the commands in your shell different to what happens when your C<Alien::>
distribution attempts to build, it may be because your environment is different than the one that your
distribution is using.  For example, if you use L<Alien::CMake> or L<Alien::gmake> to build with specific tools
that are provided by your operating system, L<Alien::Base::ModuleBuild> will adjust the path before executing
build and install commands.

In the alien build directory (usually C<_alien>) you will find environment files that you can source
into your shell (C<env.csh> for tcsh and C<env.sh> for bourne based shells), which should provide the
identical environment used by the build process in order to troubleshoot the build manually.

 % source _alien/env.sh

=head2 Can/Should I write a tool oriented Alien module using C<Alien::Base> that provides executables instead of a library?

Certainly.  The original intent was to provide libraries, but tools are also quite doable using the
C<Alien::Base> tool set.  A simple minded example of this which is fairly easy to replicate is L<Alien::m4>.

In general, this means specifying a subclass in your C<Build.PL> and bundling it in your distribution C<inc> directory.

C<Build.PL>:

 ...
 use lib 'inc';
 use My::ModuleBuild;
 
 My::ModuleBuild->new(
   ...
 )->create_build_script;

C<inc/My/ModuleBuild.pm>:

 package My::ModuleBuild;
 
 use strict;
 use warnings;
 use parent 'Alien::Base::ModuleBuild';
 use Capture::Tiny qw( capture );
 
 sub alien_check_installed_version
 {
   # see Alien::Base::ModuleBuild#alien_check_installed_version for details
 
   my($self) = @_;
   my($stdout, $stderr) = capture { system 'mytool', '--version' };
 
   # return empty list if the tool is unavailable on the system,
   # or unacceptable.
   return if $! || ...;
 
   # parse from stdout or stderr
   my $version = ...;
   return $version;
 }
 
 sub alien_check_built_version
 {
   # see Alien::Base::ModuleBuild#alien_check_built_version for details
 
   # return empty list if the tool version cannot be found, or if it
   # is unacceptable.  Note that this will cause a failure, so "unknown"
   # may be reasonable if the tool version cannot be determined.
   return if ...;
 
   # determine from the tool itself, or the current directory.
   my $version = ...;
   return $version;
 }
 
 1;

As usual your C<Alien::MyTool> class will simply be a subclass of L<Alien::Base>.
If you tool is installed in a C<bin> directory, you are done, the default C<bin_dir>
implementation should work for you.  Otherwise you may need to provide an alternate
implementation:

 package Alien::MyTool;
 
 use strict;
 use warnings;
 use parent 'Alien::Base';
 
 sub bin_dir
 {
   # see Alien::Base#bin_dir for details
   # You only need to override the default implementation if your tool
   # does not install into the standard "bin" directory.
 
   my($class) = @_;
 
   # normally for system installs the tool should already be in your
   # PATH, so return an empty list.
   return if $class->install_type eq 'system';
 
   # install_type = share
   my $dist_dir = $class->dist_dir;
   return ("$dist_dir/some/bin", "$dist_dir/some/other/bin");
 }
 
 1;

Now once your tool based Alien is installed you can use the C<bin_dir> method to
update the C<PATH> as necessary:

 use Alien::MyTool;
 use Env qw( @PATH );
 
 unshift @PATH, Alien::MyTool->bin_dir;
 system 'mytool';

=head2 How do I use C<Alien::Base> from C<Dist::Zilla>

For creating L<Alien::Base> based dists from L<Dist::Zilla> you can use the plugin
L<Dist::Zilla::Plugin::Alien>.

=head2 How do I check the built version if my library doesn't provide a C<.pc> file.

The default implementation of C<alien_check_built_version> uses several heuristics,
but leans heavily on C<pkg-config> style C<.pc> files, so if your library or tool
does not provide a C<.pc>, the version may not be detected and your build may fail.

A lot of libraries are bundled as tarballs with the version in the directory name
that they are extracted into, and the current directory when C<alien_check_built_version>
is called is the build root, so you can use C<File::chdir> as an easy way to determine
the version number:

 package My::ModuleBuild;
 
 use strict;
 use warnings;
 use parent 'Alien::Base::ModuleBuild';
 use File::chdir; # provides @CWD
 
 sub alien_check_built_version
 {
   my $dir_name = $CWD[-1];
 
   if($dir_name =~ /^libfoo-([0-9\.]+)$/) {
     return $1;
   } else {
     # Note that this will trigger a build failure
     return;
   }
 }
 
 1;

Using L<File::chdir> and C<@CWD> is a common idiom in L<Alien::Base>, because L<File::chdir>
is already a dependency of L<Alien::Base>.  For packages that do not provide a version number
in the extracted directory, you may require some creativity.

=head2 I have question not listed here!

There are a number of forums available to people working on L<Alien> and L<Alien::Base> modules:

=over 4

=item C<#native> on irc.perl.org

This is intended for native interfaces in general and so is a good place for questions about L<Alien>
generally or L<Alien::Base> specifically.

=item mailing list

The C<perl5-alien> google group is intended for L<Alien> issues generally, including L<Alien::Base>.

L<https://groups.google.com/forum/#!forum/perl5-alien>

=item Open a support ticket

If you have an issue with L<Alien::Base> itself, then please open a support ticket on the
project's GitHub issue tracker.

L<https://github.com/PerlAlien/Alien-Base-ModuleBuild/issues>

=back

=head1 SEE ALSO

=over

=item *

L<Alien::Base>

=item *

L<Alien::Base::ModuleBuild>

=item *



( run in 1.127 second using v1.01-cache-2.11-cpan-80ec619307d )