# 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: | Layer | Module | Purpose | |-------|--------|---------| | 0 | Peta::FFI | Raw FFI: dlopen + call with type signatures | | 1 | Peta::FFI::Libc, ::UUID, ::GMP | Pre-baked bindings for specific libraries | | 2 | Peta::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 ```perl 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: | Code | C Type | Perl Mapping | |------|--------|--------------| | `v` | void | (no value) | | `i` | int | IV | | `l` | long | IV | | `L` | unsigned long / size_t | UV | | `d` | double | NV | | `f` | float | NV | | `p` | const char* | String (input) | | `P` | void* (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 ```perl 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` ```perl 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): ```perl 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: ```perl 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 | Scenario | Recommendation | |----------|---------------| | Common CPAN module (List::Util, etc.) | Native module (already built in) | | System library not yet wrapped | Layer 0 raw FFI | | Frequent calls to same library | Request Layer 1 pre-baked binding | | One-off experiment | Layer 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.