Alien-Base-ModuleBuild

 view release on metacpan or  search on metacpan

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


=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
that these flags do indeed work in C<alien_check_installed_version> above.

=back

For a fully implemented example, see L<Alien::Libbz2>.

=head2 How do I test my package once it is built (before it is installed)?

There are many ways to test Alien modules before (or after) they are installed, but instead
of rolling your own, consider using L<Test::Alien> which is light on dependencies and will
test your module very closely to the way that it will actually be used.  That is to say by
building a mini XS or FFI extension and using it.  It even has tests for tool oriented Alien
distributions (like L<Alien::gmake> and L<Alien::patch>).  Here is a short example, there
are many others included with the L<Test::Alien> documentation:

 use Test2::V0;
 use Test::Alien 0.05;
 use Alien::Editline;
 
 alien_ok 'Alien::Editline';
 my $xs = do { local $/; <DATA> };
 xs_ok $xs, with_subtest {
   my($module) = @_;
   ok $module->version;
 };
 
 done_testing;
 
 __DATA__
 
 #include "EXTERN.h"
 #include "perl.h"
 #include "XSUB.h"
 #include <editline/readline.h>
 
 /* having a string parameter that we ignore
    allows us to call this as a class method */
 const char *
 version(const char *class)
 {
   return rl_library_version;
 }
 
 MODULE = TA_MODULE PACKAGE = TA_MODULE
 
 const char *version(class);
     const char *class;

=head2 How do I patch packages that need minor (or major) alterations?

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

 use Alien::Base::ModuleBuild;
 use Config;
 Alien::Base::ModuleBuild->new(
   ...
   alien_build_commands => [
     "$Config{make}",
   ],
   alien_install_commands => [
     "$Config{make} install",
   ],
   ...
 )->create_build_script;

=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
 {



( run in 1.571 second using v1.01-cache-2.11-cpan-0bb4e1dffa6 )