Auto-FFI (Peta::FFI)
PetaPerl enthält eine eingebaute Foreign Function Interface, die es ermöglicht, C-Bibliotheksfunktionen direkt aus Perl aufzurufen — ohne XS zu schreiben, ohne C-Compiler, ohne jeglichen Build-Schritt. Dies ist eine PetaPerl-exklusive Funktion ohne perl5-Entsprechung.
Architektur
Das FFI-System besteht aus drei Schichten:
| Schicht | Modul | Zweck |
|---|---|---|
| 0 | Peta::FFI | Rohes FFI: dlopen + Aufruf mit Typsignaturen |
| 1 | Peta::FFI::Libc, ::UUID, ::GMP | Fertige Bindings für bestimmte Bibliotheken |
| 2 | Peta::FFI::scan() | Erkennung: verfügbare Systembibliotheken auflisten |
Schicht 0 verwendet libffi für den Dispatch — jede C-Funktionssignatur funktioniert, keine Code-Generierung erforderlich.
Schicht 0: Rohes 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);
Typsignatur-Format
Die Signaturzeichenkette "(arg_types)return_type" verwendet einstellige Typcodes:
| Code | C-Typ | Perl-Zuordnung |
|---|---|---|
v | void | (kein Wert) |
i | int | IV |
l | long | IV |
L | unsigned long / size_t | UV |
d | double | NV |
f | float | NV |
p | const char* | String (Eingabe) |
P | void* (veränderbarer Puffer) | String (Ausgabe) |
Beispiele:
"(d)d"— ein double-Argument, gibt double zurück (z. B.sqrt)"(p)L"— ein String-Argument, gibt unsigned long zurück (z. B.strlen)"(ppi)i"— zwei Strings + int, gibt int zurück"()i"— keine Argumente, gibt int zurück (z. B.getpid)
Bibliothekserkennung
use Peta::FFI qw(scan);
my $libs = scan();
# Gibt Hashref zurück: { "libz.so.1" => "/usr/lib/libz.so.1", ... }
for my $soname (sort keys %$libs) {
print "$soname => $libs->{$soname}\n";
}
scan() ruft ldconfig -p auf, um alle auf dem System verfügbaren Shared Libraries aufzulisten.
Schicht 1: Fertige Bindings
Schicht-1-Module bieten Perl-native APIs für bestimmte C-Bibliotheken mit korrekter Argumentvalidierung, Rückgabewertkonvertierung und Fehlerbehandlung. Keine Typsignaturen nötig — einfach Funktionen aufrufen.
Peta::FFI::Libc
Direkte Bindings zu libc-Funktionen, nach Kategorie gruppiert:
Prozess:
getpid, getppid, getuid, getgid, geteuid, getegid
Strings:
strlen, strerror
Umgebung:
getenv, setenv, unsetenv
Mathematik:
abs, labs
System:
sleep, usleep, gethostname, uname
Dateioperationen:
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 zu libuuid (muss auf dem System installiert sein):
use Peta::FFI::UUID qw(uuid_generate uuid_generate_random);
my $uuid = uuid_generate(); # z. B. "550e8400-e29b-41d4-a716-446655440000"
my $rand = uuid_generate_random(); # zufallsbasierte UUID
Funktionen: uuid_generate, uuid_generate_random, uuid_generate_time,
uuid_parse, uuid_is_null, uuid_unparse.
Falls libuuid nicht installiert ist, bricht use Peta::FFI::UUID mit einer Diagnosemeldung ab.
Peta::FFI::GMP (Math::GMP)
Ganzzahlarithmetik mit beliebiger Genauigkeit über libgmp. Integriert sich unter dem Klassennamen Math::GMP für Kompatibilität mit CPANs Math::GMP:
use Math::GMP;
my $big = Math::GMP->new("123456789012345678901234567890");
my $sum = $big + 42;
print "$sum\n";
GMP-Ganzzahlen sind heap-allozierte mpz_t-Werte, die als gesegnete Referenzen gespeichert werden. Operatorüberladung (+, -, *, /, %, **, <=>, "") funktioniert identisch zum XS-Modul.
Falls libgmp nicht installiert ist, bricht use Math::GMP mit einer Diagnosemeldung ab.
Wann FFI statt nativer Module verwenden
| Szenario | Empfehlung |
|---|---|
| Gängiges CPAN-Modul (List::Util usw.) | Natives Modul (bereits eingebaut) |
| Systembibliothek noch ohne Wrapper | Schicht-0-Rohes-FFI |
| Häufige Aufrufe derselben Bibliothek | Schicht-1-Bindings anfordern |
| Einmaliges Experiment | Schicht-0-Rohes-FFI |
Schicht-0-FFI hat pro Aufruf Overhead durch Argument-Marshalling und libffi-Dispatch. Schicht-1-Bindings rufen Rust/C direkt auf und sind schneller. Native Module sind am schnellsten — gleiche Geschwindigkeit wie eingebaute Operatoren.