We love and know Zig. But Python? Me personally not so much. While Python isn't the hardest language to learn, I am far more productive in Zig.
Fortunately, I can escape Python and mainly work in Zig as both support the C ABI.
Python's standard library directly supports the C ABI via ctypes, but it is a bit clunky to use. A far more user friendly library is cffi.
Calling Zig via cffi
Let's say we have a simple sqrt function written in Zig.
// simple.zig
export fn sqrt(x: f64) f64 {
return @sqrt(x);
}
We can build this as a library:
zig build-lib -dynamic simple.zig
In Python land, we use cffi to declare the sqrt
function, import the library and call it. Note the following assumes the code is being run on Windows.
from cffi import FFI
cffi = FFI()
cffi.cdef(
"""
double sqrt(double x);
"""
)
import os
simple = cffi.dlopen(os.path.abspath("simple.dll"))
print(simple.sqrt(2))
Note that cdef
uses C declarations, which is annoying but mostly a mechanical translation from Zig.
And there's more! We can build anything into the library and access the full power of Zig. Allocation, io, debug symbols all work.
For more examples including string/struct/dict translation, I created a repository that demonstrates all of that.
Top comments (1)
Nice post! I just confirmed this works on macos-arm64 as well. Couple of additional notes:
If you want to use zig's build system (e.g. project created with
zig init-lib
), then just change line 18 of build.zig to be a shared lib:Then on the python side the file extension would be in a subfolder (again this is on macos).