NAME
Alien::Base::FAQ - Frequently Asked Questions about Alien::Base
SYNOPSIS
perldoc Alien::Base::FAQ
DESCRIPTION
This document serves to answer the most frequently asked questions made by Alien::Base authors.
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 Alien. 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.
How do I specify a minimum or exact version requirement for packages that use pkg-config?
The alien_version_check
attribute to Alien::Base::ModuleBuild will be executed to determine if the library is provided by the operating system. The default for this is %{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 --atleast-version
, --exact-version
options to require a specific range of versions, but these flags do not work with the --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' => '0.022' }, # required for %{pkg_config}
alien_version_check => '%{pkg_config} --atleast-version 1.2.3 && %{pkg_config} --modversion %n',
...
)->create_build_script;
It is better to use the built in %{pkg_config}
helper as it will use the system provided pkg-config if it is available and fallback on the pure perl PkgConfig if not.
You can also use --exact-version
to specify an exact version.
How to create an Alien module for packages that do not support pkg-config?
Although Alien::Base and Alien::Base::ModuleBuild assume packages come with a pkg-config
.pc
file to determine compiler and linker flags by default, you can implement an Alien module for packages that do use pkg-config
by following these tasks:
- subclass Alien::Base::ModuleBuild and implement
alien_check_installed_version
-
Create a subclass of Alien::Base::ModuleBuild and put it in the
inc
directory of your distribution so that it can be used during install but won't 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 Devel::CheckLib, ExtUtils::CBuilder, ExtUtls::CChecker, Config::AutoConf, FFI::CheckLib among others. It is also frequently possible to determine if a library is installed using a
-config
suffixed program. For examplelibxml2
comes with xml2-config which provides the existence, compiler and linker flags it needs. In my experience, however, most packages that provide a-config
suffixed program also provide apkg-config
interface as well. - implement
alien_check_built_version
in your Alien::Base::ModuleBuild subclass -
You should also implement
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; }
- set
alien_provides_cflags
andalien_provides_libs
inBuild.PL
. -
Add something like this to your
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
alien_provides_libs
and the appropriate-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 inalien_check_installed_version
above.
For a fully implemented example, see Alien::Libbz2.
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 Test::Alien which is light on dependencies and will test your module very closely to the way that it will actaully 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 Alien::gmake and Alien::patch). Here is a short example, there are many others included with the Test::Alien documentation:
use Test::Stream -V1;
use Test::Alien;
use Alien::Editline;
alien_ok 'Alien::Editline';
my $xs = do { local $/; <DATA> };
xs_ok $xs, with_subtest {
my($module) = @_;
ok $module->version;
};
__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;
How do I patch packages that need minor (or major) alterations?
One approach is to create a unified diff for patches that you want to apply and simply run patch on them. The Alien::patch and the %{patch}
helper can be used like this:
# Build.PL
use Alien::Base::ModuleBuild;
Alien::Base::ModuleBuild->new(
...
alien_bin_requires => {
'Alien::patch' => 0.06, # needed for %{patch} helper
},
alien_build_commands => [
'%{patch} -p1 < ../../patch/mypackage.patch',
...
],
...
)->create_build_script;
Create a folder in your distribution root called patch
and place the mypackage.patch
file in there. Since the patch
command will be executed in the package root instead of the distribution root, you need to use a relative path prefixed by ../..
. Here we use Alien::patch to provide patch even in environments where it is not provided.
A more powerful approach to patching is to write a perl subroutine to modify the source after it has been extracted. One way to do this is to create a module in your distribution's inc directory that does the patching (modules in inc can be used during build/test but won't be installed):
# inc/My/AlienPatch.pm
package My::AlienPatch;
# add this sub to the main namespace
# so we don't need to quote or escape
# anything below
sub main::alien_patch {
# is executed in the package root,
# make what ever changes you need to
# to the source here.
}
1;
# Build.PL
use Alien::Base::ModuleBuild;
Alien::Base::ModuleBuild->new(
...
alien_build_commands => [
# %x will be replaced by path for calling Perl
# from the command line
"%x -I../../inc -MMy::AlienPatch -e alien_patch",
...
],
...
)->create_build_script;
How do I build a package that uses build system?
autoconf
By default Alien::Base::ModuleBuild assumes a package with an autoconf style configure
script. The default is
# Build.PL
use Alien::Base::ModuleBuild;
Alien::Base::ModuleBuild->new(
...
alien_build_commands => [
'%c --prefix=%s',
'make',
],
alien_install_commands => [
'make install',
],
...
)->create_build_script;
There are a couple of short cuts here, %c
indicates the platform independent method for executing the configure
script, plus any normal autoconf flags that are appropriate for Perl Alien libraries. The %c
also tells Alien::Base::ModuleBuild to use Alien::MSYS on Windows platforms and to add that as a dependency. The %s
is a placeholder for the location to which the package will be installed. This is normally in a share directory specific to your distribution.
autoconf-like
If you see an error like this:
Unknown option "--with-pic".
It may be because your package provides a configure
script that provides an autoconf-style interface, but is not actually autoconf. Alien::Base::ModuleBuild is aggressive in using the --with-pic
option because when supported by autoconf it produces position independent code (important for reliably building XS extensions), and when not supported autoconf simply ignores the option. Unfortunately some autoconf-style configure
scripts consider it an error when they see options that they do not recognize. You can tell Alien::Base::ModuleBuild to not use the --with-pic
option via the alien_autoconf_with_pic
property:
# Build.PL
use Alien::Base::ModuleBuild;
Alien::Base::ModuleBuild->new(
...
alien_autoconf_with_pic => 0,
...
)->create_build_script;
CMAKE
You probably cannot count on CMake being available on most platforms. Fortunately, there is an alien distribution Alien::CMake which will either use the CMake provided by the operating system, or download and install it for you. You can use this from your Build.PL
with the alien_bin_requires
property:
# Build.PL
use Alien::Base::ModuleBuild;
use Config;
Alien::Base::ModuleBuild->new(
...
alien_bin_requires => {
'Alien::CMake' => 0.07,
},
alien_build_commands => [
# acutal required arguments may vary
"cmake -G 'Unix Makefiles' -DCMAKE_MAKE_PROGRAM=$Config{make} -DCMAKE_INSTALL_PREFIX:PATH=%s",
"$Config{make}",
],
alien_install_commands => [
"$Config{make} install",
],
...
)->create_build_script;
vanilla Makefiles?
If you want to use the same make
as Perl, you can use Config:
# Build.PL
use Alien::Base::ModuleBuild;
use Config;
Alien::Base::ModuleBuild->new(
...
alien_build_commands => [
"$Config{make}",
],
alien_install_commands => [
"$Config{make} install",
],
...
)->create_build_script;
Gnu Makefiles?
Some packages require GNU Make's unique syntax. Perl's Config provides an entry for gmake
, but it is frequently wrong. Do not depend on it. Instead you can ues 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;
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 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 Alien::CMake or Alien::gmake to build with specific tools that are provided by your operating system, Alien::Build::ModuleBuild will adjust the path before executing build and install commands.
In the alien build directory (usually _alien
) you will find environment files that you can source into your shell (env.csh
for tcsh and 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
How do I use Alien::Base
from Dist::Zilla
For creating Alien::Base based dists from Dist::Zilla you can use the plugin Dist::Zilla::Plugin::Alien.
I have question not listed here!
There are a number of forums available to people working on Alien and Alien::Base modules:
#native
on irc.perl.org-
This is intended for native interfaces in general and so is a good place for questions about Alien generally or Alien::Base specifically.
- mailing list
-
The
perl5-alien
google group is intended for Alien issues generally, including Alien::Base. - Open a support ticket
-
If you have an issue with Alie::Base itself, then please open a support ticket on the project's GitHub issue tracker.
SEE ALSO
AUTHOR
Original author: Joel Berger, <joel.a.berger@gmail.com>
Current maintainer: Graham Ollis <plicease@cpan.org> and the Alien::Base team
COPYRIGHT AND LICENSE
Copyright (C) 2012-2015 by Joel Berger
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.