Foreign Function Interface
WARNING
FFI support is still relatively immature and limited
When you want to call a foreign function from a buzz program you can use buzz's API to build the function call by:
- Taking its arguments from the stack
- Converting them to the expected types
- Making the call to the foreign function
- Converting its result to a buzz value
- Pushing it on the stack
This is called a binding and writing those can be time-consuming for very little added value to your program. Another option is using the FFI feature of buzz, which will generate a JIT-compiled function that will do this work for you.
zdef statements
zdef statements can only occur in the global scope. They have two functions: declare the type of the foreign functions and specify which library they are bound to.
zdef("/path/to/libforeign", "fn hello(name: [*:0]const u8) void;");
zdef("/path/to/libforeign", `
pub const AStruct = extern struct {
id: u32,
name: [*:0]const u8,
};
`);
zdef("/path/to/libforeign", "fn get_id(data: *Data) u32;")
The definitions are written in C ABI-compatible Zig code. Once you've declared your interface with zdefs, you can use it just like any other buzz function, assuming you use the appropriate buzz values.
import "ffi";
// ...
hello(ffi\cstr("world"));
final data = AStruct{
name = ffi\cstr("hello"),
id = 42.0,
};
get_id(data) == 42;
TIP
When a [*:0]const u8 pointer is expected, you can provide a buzz string. Note, however, that we use the ffi\cstr helper which will add \0 to the end of the string. Avoid using buzz strings that have multiple \0 embedded in them.
struct instances are always passed by reference right now (passing a struct by value can be complex depending on your system ABI). This is why you can pass them directly to functions expecting a pointer to a struct.
Pointers
For any other type of pointer, you can use the Buffer object provided by the buffer standard library.
zdef("/path/to/libforeign", "fn sum(values: [*]i32, len: i32) u32;");
// ...
final buffer = Buffer.init();
buffer.writeZ::<int>("i32", values: [ 1, 2, 3 ]);
sum(buffer.ptr(), len: 3) == 6;
To write a list of structs, you must use writeStruct.
buffer.writeStruct(<Data>, Data, values: [data1, data2, data3]);
Supported Zig types and statements
Here's the list of supported types and their buzz counterparts:
| Zig type | buzz type |
|---|---|
c_int | int |
u8 | int |
i8 | int |
u16 | int |
i16 | int |
i32 | int |
c_uint | double |
u32 | double |
i64 | double |
f32 | double |
f64 | double |
u64 | ud |
usize | ud |
bool | bool |
void | void |
| pointers | ud |
extern struct | foreign struct |
opaque struct | foreign struct |
extern union | foreign struct |
