Rowan Marshall


Calling Nim from Python

In this post I’ll show you how to write a function in Nim and call it in Python.

Nim

To start with we’ll need a Nim function. Here’s a one that takes 2 integers, adds them and returns the result:

called.nim

proc nim_add(num1: int, num2: int): int {.exportc.} =
    return num1 + num2

Most of this is pretty ordinary, except for the {.exportc.} in the function signature. This is a pragma, which provides metadata about a function to the Nim compiler. Here, {.exportc.} mainly tells the compiler to keep the function name as it is in the .nim file instead of mangling it, so we know our function will still be called nim_add.

Now we need to compile this into a shared object to let Python call into it:

nim compile --app:lib called.nim

This will create a shared object file called libcalled.so in your current directory.

Python

If you’ve used cffi before this will be very familiar.

calling.py


from cffi import FFI

ffi = FFI()

ffi.cdef("""
    int nim_add(int num1, int num2);
""")

lib = ffi.dlopen("./libcalled.so")
res = lib.nim_add(5, 10)
print(res)

Here we create an FFI object and load in the function definition of nim_add using the C function declaration syntax. There is an explanation on converting Nim types to C types in the Nim manual here. We then open our shared library from the current directory, and can call methods on the library object like any Python namespace.

Running it

Now we can just run the Python file like normal, and if the shared object file is in the expected place, cffi will call into it and we can add two numbers together, but in Nim!

➜ python3 calling.py
15