FFI: Calling C with UFFI
Pharo's UFFI calls C libraries with a declaration written in C-like syntax inside a literal array:
39.1 Unified FFI
Pharo's UFFI calls C libraries with a declaration written in C-like syntax inside a literal array:
Arguments in the signature are bound by name to the method's arguments (n, aName), or can be self or literals.
Object << #LibCDemo slots: {}; package: 'FFI-Demo'.
LibCDemo class >> abs: n
^ self ffiCall: #( int abs ( int n ) ) library: LibC
LibCDemo class >> getenv: aName
^ self ffiCall: #( char * getenv ( const char * aName ) ) library: LibC
LibCDemo class >> clock
^ self ffiCall: #( long clock ( ) ) library: LibCLibCDemo abs: -42. "→ 42"
LibCDemo getenv: 'HOME'. "→ '/home/ada' (a String; nil if unset)"39.2 Library classes
FFILibrary << #LibM slots: {}; package: 'FFI-Demo'.
LibM >> unixLibraryName ^ 'libm.so.6'
LibM >> macLibraryName ^ 'libm.dylib'
LibM >> win32LibraryName ^ 'msvcrt.dll'
Object << #MathFFI slots: {}; package: 'FFI-Demo'.
MathFFI class >> ffiLibrary
^ LibM
MathFFI class >> cos: x
^ self ffiCall: #( double cos ( double x ) )39.3 Types, structures, memory
int, long, double, float, char, bool same names; also int32, uint8, size_t, int64 String (copied) or ExternalAddress ExternalAddress / void * subclass of FFIExternalStructure subclass of FFIExternalEnumeration subclass of FFIOpaqueObject / FFIExternalObject
FFICallback signature:... block: [...] Memory you allocate (allocate:, externalNew) must be freed — or registered for finalization (autoRelease).
FFIExternalStructure << #Point2D slots: {}; package: 'FFI-Demo'.
Point2D class >> fieldsDesc
^ #( double x; double y; )
Point2D rebuildFieldAccessors. "generates x, x:, y, y:"
| p mem |
p := Point2D new. p x: 3.0; y: 4.0.
mem := ExternalAddress allocate: 64.
[ "use mem" ] ensure: [ mem free ].39.4 Notes
Pharo 9+ has threaded FFI (TFFI) so long C calls need not block the VM.
Squeak/Cuis FFI uses pragmas: <cdecl: long 'abs' (long) module: 'libc.so.6'>.
GNU Smalltalk: <cCall: 'abs' returning: #int args: #(#int)>.
VisualWorks uses DLL&C Connect; VA Smalltalk uses PlatformFunctions.
Popular bindings built on UFFI: libgit2 (Iceberg), SDL2, Cairo/Athens, SQLite3, OpenGL, TensorFlow/ONNX experiments.