You've installed a native library with Alien::Xrepo. Now what? The whole point is to call a C function from Perl but there are three very different ways to do it. This article walks through the same task (calling zlibVersion() from Perl) using three different binding tools, shows the trade-offs, and helps you pick the right one.

All three examples assume:

my $repo = Alien::Xrepo->new;
my $zlib = $repo->install('zlib');

After this, $zlib->libpath points to zlib.dll / libz.so, $zlib->includedirs has zlib.h, and $zlib->links has the -lz flag.

Affix: one-liner FFI

Best for: Single functions, quick prototypes, CPAN-distributed bindings.

use v5.40;
use Alien::Xrepo;
use Affix;

my $zlib = Alien::Xrepo->new->install('zlib');
affix $zlib->libpath, 'zlibVersion', [], String;

say 'zlib ' . zlibVersion();

affix is a declarative one-liner: tell it the shared library, function name, argument types, and return type. No XS compilation, no compiler needed at runtime.

Pros

Cons

FFI::Platypus: the classic

Best for: Old code you wrote before Affix existed?

use v5.40;
use Alien::Xrepo;
use FFI::Platypus;

my $zlib = Alien::Xrepo->new->install('zlib');

my $ffi = FFI::Platypus->new;
$ffi->lib( $zlib->libpath );
$ffi->attach( 'zlibVersion', [] => 'string' );

say 'zlib ' . zlibVersion();

FFI::Platypus is an established workhorse. It reads the same libpath and also accepts an explicit lib call, which is handy when you need to load several libraries.

Pros

Cons

Inline::C: full C extensions

Best for: Performance-critical paths, code that needs headers and multiple libraries linked together, XS authorship.

use v5.40;
use Alien::Xrepo;
use Config;

my $repo  = Alien::Xrepo->new;
my $zlib  = $repo->install('zlib');
my $libpng = $repo->install('libpng');

# Runtime include/link flags
my $incs = join ' ', map { "-I$_" } (@{ $zlib->includedirs }, @{ $libpng->includedirs });
my $libs = join ' ',
    map { "-L$_" } (@{ $zlib->linkdirs }, @{ $libpng->linkdirs }),
    map { "-l$_" } (@{ $zlib->links },    @{ $libpng->links });

# PATH for DLLs
local $ENV{PATH} = join $Config{path_sep},
    @{[$zlib->bin_dir]}, @{[$libpng->bin_dir]}, $ENV{PATH};

use Inline ();
Inline->bind(
    'C',
    <<'C',
#include <zlib.h>
#include <png.h>
const char* versions() {
    static char buf[128];
    snprintf(buf, sizeof buf, "zlib %s / libpng %s", zlibVersion(), PNG_LIBPNG_VER_STRING);
    return buf;
}
C
    INC  => $incs,
    LIBS => $libs
);

say versions();

Inline::C compiles a real C extension at build time. You get full access to the C preprocessor (macros, headers) and can call any function, define any struct, and chain any number of libraries in a single XS.

Pros

Cons


Comparison

Affix FFI::Platypus Inline::C
Compiler needed No No Yes
Boilerplate 1 line per function 3-4 lines per function Full C code block
Multi-library Manual (one affix per lib) Manual (lib calls) Merged into one INC/LIBS
Header macros Not available Not available Full C preprocessor
Performance FFI FFI Native XS
Best for Quick one-offs ??? Performance-critical XS

Which should you choose?

In every case, Alien::Xrepo hands you libpath, includedirs, linkdirs, and links; the same four things each binding tool needs to find the library. Swap one binding for another without changing the install step.