Alien:...ld::FAQ(3pm)

πŸ“¦
version 1.17 Β· 3 versions
, in fedora 43

okay so bestie, you've got Alien:...ld::FAQ(3pm) open β€” User Contributed Perl Documentation, no cap β€” and honestly? iconic of you. πŸ’– Heads up: this is part 1, there's more coming, so hydrate πŸ“ and let's go. ✨


🌸 NAME 🌸

Alien::Base::ModuleBuild::FAQ β€” Frequently Asked Questions about Alien::Base::ModuleBuild. short, sweet, exactly what it says on the tin. πŸ’…

⭐ VERSION ⭐

version 1.17 🫢

πŸ¦‹ SYNOPSIS πŸ¦‹

perldoc Alien::Base::FAQ

that's it. that's the whole synopsis. just go read the FAQ, bestie. 😌

πŸŽ€ DESCRIPTION πŸŽ€

NOTE: if you're doing new development of Aliens, please consider using Alien::Build and alienfile instead. fr fr.

Like Alien::Base::ModuleBuild, they work with Alien::Base. But unlike Alien::Base::ModuleBuild, they're more easily customized and they handle a number of corner cases better. For a good place to start, please see Alien::Base::ModuleBuild::API.

And like β€” the Alien-Base / Alien-Build team will keep maintaining this module (we will continue to fix bugs where appropriate), but we aren't adding any new features to this module. so there's that. πŸ’€

This document exists to answer the most frequently asked questions made by Alien::Base authors. basically it's the group chat archive. 🫢


πŸ›Έ 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. If you want the manifesto-style description of the Why and the How, go see Alien. 🌈

Alien::Base is a base class and framework for creating Alien distributions. The whole idea is to address as many of the common challenges to developing Alien modules as possible β€” right there in the base class β€” to simplify the process. slay the process, honestly. πŸ‘‘


πŸ” 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 and --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 them 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;

And honestly? It's better to use the built-in %{pkg_config} helper, because it will use the system-provided pkg-config if it's available, and fall back on the pure perl PkgConfig if it isn't. πŸ’–

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? 🧩

Alien::Base and Alien::Base::ModuleBuild assume by default that packages come with a pkg-config .pc file to determine compiler and linker flags. But 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 drop it in the inc directory of your distribution, so it can be used during install but won't actually get 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 a number of methods you can use to determine if the system provides your library. From Perl, that includes Devel::CheckLib, ExtUtils::CBuilder, ExtUtils::CChecker, Config::AutoConf, and FFI::CheckLib, among others. It's also frequently possible to determine whether a library is installed using a -config suffixed program β€” for example libxml2 comes with xml2-config, which provides the existence, compiler and linker flags it needs. ngl though, the author's experience is that most packages which provide a -config suffixed program also provide a pkg-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 and alien_provides_libs in Build.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's a good idea to verify that these flags do indeed work inside alien_check_installed_version above. πŸ”

For a fully implemented example, go peek at 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're installed, but instead of rolling your own, consider using Test::Alien β€” it's light on dependencies and it will test your module very closely to the way it will actually be used. Which 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's a short example β€” there are many others included with the 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;

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

One approach is to create a unified diff for the patches you want to apply, and simply run patch on them. The Alien::patch module 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 ../... And here we're using Alien::patch to provide patch even in environments where it isn't provided. 🫢

A more powerful approach to patching is to write a perl subroutine that modifies 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 happening 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. And %s is a placeholder for the location where the package will be installed β€” normally 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 has an autoconf-style interface, but is not actually autoconf. Alien::Base::ModuleBuild is aggressive about using the --with-pic option, because when it's supported by autoconf it produces position independent code (which is important for reliably building XS extensions), and when it's not supported, autoconf simply ignores the option. Unfortunately, some autoconf-style configure scripts consider it an error when they see options they don't 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 πŸ—οΈ

okay bestie, so β€” CMake. You probably cannot count on CMake being available on most platforms. πŸ’€ But guess what, there's an alien distribution for that: Alien::CMake, and it 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 use 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. Like, for example, if you use Alien::CMake or Alien::gmake to build with specific tools that are provided by your operating system, Alien::Base::ModuleBuild will adjust the path before executing build and install commands. sneaky but helpful ✨

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

πŸ› οΈ Can/Should I write a tool oriented Alien module using 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 Alien::Base tool set. A simple minded example of this which is fairly easy to replicate is Alien::m4. πŸ‘‘

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

Build.PL:

...
use lib 'inc';
use My::ModuleBuild;

My::ModuleBuild->new(
  ...
)->create_build_script;

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 Alien::MyTool class will simply be a subclass of Alien::Base. If you tool is installed in a bin directory, you are done, the default 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 bin_dir method to update the PATH as necessary:

use Alien::MyTool;
use Env qw( @PATH );

unshift @PATH, Alien::MyTool->bin_dir;
system 'mytool';

πŸ’Œ 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. that's it, that's the whole answer, slay πŸŽ€


πŸ” How do I check the built version if my library doesn't provide a .pc file.

The default implementation of alien_check_built_version uses several heuristics, but leans heavily on pkg-config style .pc files, so if your library or tool does not provide a .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 alien_check_built_version is called is the build root, so you can use 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 File::chdir and @CWD is a common idiom in Alien::Base, because File::chdir is already a dependency of Alien::Base. For packages that do not provide a version number in the extracted directory, you may require some creativity. 🧚 get inventive bestie


❓ 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.

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

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

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


🌈 SEE ALSO ✨

  • Alien::Base
  • Alien::Base::ModuleBuild
  • Alien::Base::ModuleBuild::API

πŸ‘‘ AUTHOR πŸ’…

Original author: Joel A Berger <joel.a.berger@gmail.com>

Current maintainer: Graham Ollis <plicease@cpan.org>

Contributors:

  • David Mertens (run4flat)
  • Mark Nunberg (mordy, mnunberg)
  • Christian Walde (Mithaldu)
  • Brian Wightman (MidLifeXis)
  • Graham Ollis (plicease)
  • Zaki Mughal (zmughal)
  • mohawk2
  • 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)
  • Petr PΓ­saΕ™ (ppisar)
  • Alberto SimΓ΅es (ambs)

This software is copyright (c) 2012-2022 by Joel A Berger.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.


and that's the whole page, bestie!! πŸ’– This version was generated by perl v5.42.0 and dated 2025-07-25 β€” go forth and build ur alien modules, you absolute icon πŸ¦‹πŸŒΈ

πŸ“¦ where this page comes from