For a personal project I am working on I wanted to create Python bindings to a Rust library I am creating. The first port of call was Milksnake and I wrote a Python wrapper to make it nicer to consume. However, a few weeks later I wanted wrappers for a few more languages and rather than create each one individually I decided to see if I could use a tried and trusted tool like Swig. What follows is a short tutorial on how to use Swig to create bindings for a Rust library.
The rmath library
We will write a simple library with one function that takes two integers and adds them, returning the sum. First we create a new Rust crate.
We add the following function to
src/lib.rs and edit the test:
And now run cargo test to make sure it all works.
The rmath C library
Now we need to expose this as a C API. We could edit our sum function so it is C compatible but it would make usage from Rust awkward. We could also just add another function to this crate that exposes a C compatible version but if you are creating a real library a nicer way to do it is to create a new crate that contains the C api.
to create the crate for our C API. We need to update our Cargo.toml file with our dependencies and we need to tell cargo we want to build a C shared library.
Now, we will create a C “friendly” function in
src/lib.rs that we use to expose our sum function.
Next build the crate and make sure it compiles. You should now have a shared library in
target/debug/ (called librmath_c.dylib on OS X).
Now we need to use cbindgen to create a C header file. Create a new file called
build.rs in the same folder as your Cargo.toml file.
build = "build.rs" to the package section of your Cargo.toml file.
Running cargo build again should create
Finally, we will use Swig to create a Python and r bindings. First install Swig using the instructions on its website.
Then create a swig file called
rmath.i and add the following:
This tells Swig our module is called rmath, we want to include rmath.h and we want to wrap the functions defined in rmath.h.
First we will build the Python package, these commands can be added to a Makefile if desired.
Now we cd into the python folder and fire up Python:
Oh! If you get an error like this it means the version of Python you linked against is different to the one you are running. By specifying ‘-lpython’ it is likely you linked against your default system Python rather than another install that may be in your path, so we you may need to try again using your system Python.
Excellent. You can now package up
_rmath.so and use your Rust library from Python.
Finally, we will use the same swig file to create r bindings.
Now if we cd into the r folder and fire up the r interperator:
we can use the same Rust function.
Rust is a very promising language and as we have seen, using mature tools such as Swig it is very easy to tip your toe in the water and start including Rust libraries in your existing Python and r projects where you may need a perfromance boast or wish to take advantage of Rusts type safety and fearless concurrency. The full project can be downloaded from github.