Alien-Build
view release on metacpan or search on metacpan
lib/Alien/Build/Manual/AlienAuthor.pod view on Meta::CPAN
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<sys> and not C<system> is so that it
does not conflict with the built in C<system> 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
L<Alien>s that use autoconf and C<pkg-config> (which are quite common.
L<alienfile> allows you to use plugins. See L<Alien::Build::Plugin> for
a list of some of the plugin categories.
For now, I will just show you how to write the L<alienfile> for libfoo
above using L<Alien::Build::Plugin::Build::Autoconf>,
L<Alien::Build::Plugin::PkgConfig::Negotiate>,
L<Alien::Build::Plugin::Download::Negotiate>, and
L<Alien::Build::Plugin::Extract::Negotiate>
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<pkg-config> 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<Alien::Build::Plugin::PkgConfig::Negotiate>, it may choose to use
command line tools, a pure Perl implementation (L<PkgConfig>), 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<wget> 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<Alien::Build::Plugin::Build::Autoconf>). 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<Alien::Build::Plugin::PkgConfig::Negotiate> with an array reference
of package names.
plugin 'PkgConfig' => (
pkg_name => [ 'foo', 'bar', 'baz' ],
);
All packages must be found in order for the C<system> install to succeed.
Once installed the first C<pkg_name> will be used by default (in this
example C<foo>), and you can retrieve any other C<pkg_name> using
the L<Alien::Base alt method|Alien::Base/alt>.
=head2 A note about dynamic vs. static libraries
If you are using your L<Alien> 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<Alien::Role::Dino>.
Actually let me back up a minute. For a C<share> install it is best
to use static libraries to build your XS extension. This is because
if your L<Alien> is ever upgraded to a new version it can break your
existing XS modules. For a C<system> 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<want> both static and dynamic libraries to work with XS and FFI.
For that case, there is the L<Alien::Build::Plugin::Gather::IsolateDynamic>
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<clean_install> property on L<Alien::Build::MM>, 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<Alien::Build>, or
L<Alien::Build::MM>, but it is sometimes useful to test your alienfile
using the C<af> command (it does not come with L<Alien::Build>, you need
to install L<App::af>). By default C<af> will use the C<alienfile> in
the current directory (just as C<make> uses the C<Makefile> in the
current directory; just like C<make> you can use the C<-f> option to
specify a different L<alienfile>).
You can test your L<alienfile> 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 '
( run in 1.369 second using v1.01-cache-2.11-cpan-9581c071862 )