Perl developers have almost always faced a dependency problem: how do you ensure a CPAN module can find, download, and build a non-Perl library? Whether it’s openssl, libpng, or nuklear, the traditional solution has been a complex dance of shell commands, pkg-config probes, and precarious make invocations.

Today, we have two primary philosophies for solving this. On one side stands Alien::Build, the mature, flexible Swiss Army knife of the Perl ecosystem. On the other stands Alien::Xrepo::Base, a new contender that leverages the cross-platform power of the Xmake/Xrepo ecosystem and Perl 5.40's native class features.

In this article, we’ll compare these two approaches and see why moving from "Recipes" to "Registries" might be the biggest productivity boost for Alien authors in years.


1. Alien::Build: The Recipe-Based Approach

Alien::Build (and its companion alienfile) is built on the idea of a recipe. As an author, you write a DSL that describes exactly how to fetch, build, and probe a library.

Example: A typical alienfile for nuklear

Nuklear is a single-header library, which sounds easy, but to use it with FFI, you must create a C wrapper to compile it into a shared library. (Worth noting: because nuklear is header-only — Xrepo declares it set_kind("library", { headeronly = true }) — there is no prebuilt nuklear.so/nuklear.dll anywhere; you always have to synthesize one for FFI, in Alien::Build or in a registry.)

use alienfile;

share {
  start_url => 'https://github.com/vurtun/nuklear/archive/refs/tags/v4.13.2.tar.gz';
  
  # We have to manually write a C file to 'inject' the implementation
  # so it can be compiled into a .so / .dll
  patch [
    'echo "#define NK_IMPLEMENTATION\n#include \"nuklear.h\"" > nuklear_wrapper.c'
  ];

  build [
    [ '%{cc}', '-shared', '-fPIC', '-o', 'libnuklear.%{so}', 'nuklear_wrapper.c' ],
    [ 'mkdir', '-p', '%{.install.prefix}/lib', '%{.install.prefix}/include' ],
    [ 'cp', 'libnuklear.%{so}', '%{.install.prefix}/lib/' ],
    [ 'cp', 'nuklear.h', '%{.install.prefix}/include/' ]
  ];
};

gather sub {
  my($build) = @_;
  my $prefix = $build->install_prop->{prefix};
  $build->runtime_prop->{cflags} = "-I$prefix/include";
  $build->runtime_prop->{libs}   = "-L$prefix/lib -lnuklear";
};

2. Alien::Xrepo::Base: The Registry-Based Approach

Alien::Xrepo::Base takes a different path. Instead of teaching Perl how to build a specific library, it delegates that responsibility to Xrepo, which already knows how to turn a package like zlib into a usable shared library.

Why alienfile steps are redundant with Xrepo

When you use Alien::Xrepo::Base, the three pillars of alienfile effectively disappear:

Example: The "Quick & Easy" Alien::Xrepo::Base subclass

Here is the equivalent Alien::Zlib using the new Perl 5.40 syntax:

use v5.40;
use experimental 'class';
use Alien::Xrepo::Base;

class Alien::Zlib : isa(Alien::Xrepo::Base) {
    method package_name { 'zlib' }

    # Ask Xrepo for a shared library so we can FFI into it with Affix.
    method install_opts {
        return ( kind => 'shared' );
    }
}

That's it. You don't need to know where the source code lives, how to run make, or how to find zlib1.dll / libz.so. You simply ask for the package by name, and the registry hands you a shared library ready for FFI.


3. Comparing the Developer Experience

Feature Alien::Build / alienfile Alien::Xrepo::Base
Logic Location Inside your Perl distribution. Inside the global Xrepo registry.
Maintenance You must update URLs and patches. Community maintainers update Xrepo.
Cross-Platform Requires manual logic for Win32/Unix. Handled by Xmake's abstraction layer.
Dependencies Hard to chain multiple Aliens. Xrepo handles the full dependency tree.
Perl Version Works on older Perls. Requires Perl 5.40+ (for class).

4. Integration with Distribution Builders

Whether you use Module::Build or ExtUtils::MakeMaker (EUMM), an Alien module needs to hook into the install process to trigger the native build.

Using Module::Build (with Alien::Xrepo::Base)

Alien::Xrepo::Base provides a helper that makes Build.PL trivial. It essentially generates a tiny Module::Build::Tiny clone that understands the Xrepo lifecycle.

Build.PL:

use v5.40;
use lib 'lib';
use Alien::Xrepo::Base;

# This triggers the "Registry-to-Dist" bridge
Build_PL('Alien::Zlib');

When a user runs ./Build, Alien::Xrepo::Base will:

  1. Call xrepo install zlib into the blib share directory.
  2. Generate a ConfigData.pm containing the resolved metadata from Xrepo.

Note: Build_PL reads the distribution's META.json to name the generated Build script, so that file must exist before you run Build_PL('Alien::Zlib').

Using ExtUtils::MakeMaker

If you prefer the classic Makefile.PL approach, you can still drive the Xmake/Xrepo engine directly. The cflags/libs accessors (and the root-isolated install) are provided by Alien::Xrepo::Base; instantiate that instead of the lower-level Alien::Xrepo, whose install returns a raw PackageInfo with no such methods.

Makefile.PL:

use ExtUtils::MakeMaker;
use Alien::Xrepo::Base;

my $package = Alien::Xrepo::Base->new(
    package_name => 'zlib',             # or subclass it and let it provide install_opts
    root         => 'blib/lib/share',   # isolated, project-local install
);
$package->install( kind => 'shared' );  # also available via $package->package_info

WriteMakefile(
    NAME         => 'My::Module',
    VERSION_FROM => 'lib/My/Module.pm',
    CONFIGURE_REQUIRES => {
        'Alien::Xrepo' => '0.09'
    },
    INC          => $package->cflags,   # "-I/path/to/zlib/include"
    LIBS         => [ $package->libs ]  # "-L/path/to/zlib/lib -lzlib"
);

5. The "Zero-Recipe" Advantage

The true strength of Alien::Xrepo::Base is revealed when a library has complex dependencies of its own.

Imagine building libwebp. It might require libjpeg, libpng, and zlib. In the Alien::Build world, you would need to create four separate Alien distributions and coordinate their alienfiles so they find each other.

In the Alien::Xrepo::Base world, you just ask for libwebp. Xrepo resolves the tree, builds all four libraries in the correct order, links them together, and hands you a single PackageInfo object.

By basing your work on Alien::Xrepo::Base, you aren't just writing a wrapper; you are tapping into a global effort to make C/C++ libraries as easy to install as CPAN modules.


Summary

Alien::Build remains the right choice if:

Alien::Xrepo::Base is the superior choice if:

By moving the "Recipe" out of your Perl code and into a managed registry like Xrepo, you reduce the surface area for bugs and ensure your Alien module stays working long after you've stopped updating the download URLs.