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 APIopen in new window to build the function call by:

  1. Taking its arguments from the stack
  2. Converting them to the expected types
  3. Making the call to the foreign function
  4. Converting its result to a buzz value
  5. 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 libraryopen in new window.

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 typebuzz type
c_intint
u8int
i8int
u16int
i16int
i32int
c_uintdouble
u32double
i64double
f32double
f64double
u64ud
usizeud
boolbool
voidvoid
pointersud
extern structforeign struct
opaque structforeign struct
extern unionforeign struct
Last Updated:
Contributors: Benoit Giannangeli