Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Auto-FFI (Peta::FFI)

PetaPerl includes a built-in Foreign Function Interface that allows calling C library functions directly from Perl — without writing XS, without a C compiler, without any build step. This is a PetaPerl-exclusive feature with no perl5 equivalent.

Architecture

The FFI system has three layers:

LayerModulePurpose
0Peta::FFIRaw FFI: dlopen + call with type signatures
1Peta::FFI::Libc, ::UUID, ::GMPPre-baked bindings for specific libraries
2Peta::FFI::scan()Discovery: enumerate available system libraries

Layer 0 uses libffi for dispatch — any C function signature works, no code generation required.

Layer 0: Raw FFI

dlopen / call / dlclose

use Peta::FFI qw(dlopen call dlclose);

my $lib = dlopen("libm.so.6");
my $result = call($lib, "sqrt", "(d)d", 2.0);   # √2 = 1.4142...
print "sqrt(2) = $result\n";
dlclose($lib);

Type Signature Format

The signature string "(arg_types)return_type" uses single-character type codes:

CodeC TypePerl Mapping
vvoid(no value)
iintIV
llongIV
Lunsigned long / size_tUV
ddoubleNV
ffloatNV
pconst char*String (input)
Pvoid* (mutable buffer)String (output)

Examples:

  • "(d)d" — one double argument, returns double (e.g. sqrt)
  • "(p)L" — one string argument, returns unsigned long (e.g. strlen)
  • "(ppi)i" — two strings + int, returns int
  • "()i" — no arguments, returns int (e.g. getpid)

Library Discovery

use Peta::FFI qw(scan);

my $libs = scan();
# Returns hashref: { "libz.so.1" => "/usr/lib/libz.so.1", ... }

for my $soname (sort keys %$libs) {
    print "$soname => $libs->{$soname}\n";
}

scan() calls ldconfig -p to enumerate all shared libraries available on the system.

Layer 1: Pre-baked Bindings

Layer 1 modules provide Perl-native APIs for specific C libraries, with proper argument validation, return value conversion, and error handling. No type signatures needed — just call functions.

Peta::FFI::Libc

Direct bindings to libc functions, grouped by category:

Process: getpid, getppid, getuid, getgid, geteuid, getegid

Strings: strlen, strerror

Environment: getenv, setenv, unsetenv

Math: abs, labs

System: sleep, usleep, gethostname, uname

File operations: access, unlink, rmdir, mkdir, chmod, chown

use Peta::FFI::Libc qw(getpid gethostname uname);

print "PID: ", getpid(), "\n";
print "Host: ", gethostname(), "\n";

my @info = uname();
print "OS: $info[0] $info[2] ($info[4])\n";

Peta::FFI::UUID

Bindings to libuuid (must be installed on the system):

use Peta::FFI::UUID qw(uuid_generate uuid_generate_random);

my $uuid = uuid_generate();           # e.g. "550e8400-e29b-41d4-a716-446655440000"
my $rand = uuid_generate_random();    # random-based UUID

Functions: uuid_generate, uuid_generate_random, uuid_generate_time, uuid_parse, uuid_is_null, uuid_unparse.

If libuuid is not installed, use Peta::FFI::UUID dies with a diagnostic message.

Peta::FFI::GMP (Math::GMP)

Arbitrary-precision integer arithmetic via libgmp. Integrates with the Math::GMP class name for compatibility with CPAN’s Math::GMP:

use Math::GMP;

my $big = Math::GMP->new("123456789012345678901234567890");
my $sum = $big + 42;
print "$sum\n";

GMP integers are heap-allocated mpz_t values stored as blessed references. Operator overloading (+, -, *, /, %, **, <=>, "") works identically to the XS module.

If libgmp is not installed, use Math::GMP dies with a diagnostic message.

When to Use FFI vs Native Modules

ScenarioRecommendation
Common CPAN module (List::Util, etc.)Native module (already built in)
System library not yet wrappedLayer 0 raw FFI
Frequent calls to same libraryRequest Layer 1 pre-baked binding
One-off experimentLayer 0 raw FFI

Layer 0 FFI has per-call overhead from argument marshalling and libffi dispatch. Layer 1 pre-baked bindings call Rust/C directly and are faster. Native modules are fastest — same speed as built-in operators.