Writing bindings in Rust: Part 1
15 Jan 2017  |  rust, libevdevI started learning rust early December, and the best way to learn a language is to use it. So I started looking for a project in rust and hopefully I was able to find a project which was writing bindings for libevdev in rust. There are a few blogs which talk about bindings but there were certain aspects that this blogs didn’t cover and I had to do some digging myself to get the answers. This aim of this post is to help anyone who wants to write bindings for a C library in rust.
To write bindings we need to call the C functions from rust code. To accomplish this rust provides us with foreign function interface(FFI) to talk with C. Before we call any C function from rust, we first need to declare that function in rust. We use the extern block provided by FFI for this. We will also use libc crate which provides us with C data types.
Functions
Let’s look at some examples to understand how various C functions are translated to their rust counterparts:
linking with the C lib
The easiest way to link to a C lib is to use #[link(name = "libname")]
i.e.
But as usual this is not the recommended way, the recommended way is to use a build script to check if the C lib is available and build it ourselves if not present. A simple build script would check for installed library using pkg-config crate i.e.
I won’t dwell into building of packages as of now as that would deviate us from the topic at hand, however the crates.io has a good documentation regarding build script.
Structs
Structs in C and Rust are pretty similar, the difference being the types used.
translates to
For opaque structs the rust documentation suggests use of enums, which is explained really nicely here.
Enums
There is no nice way to import enums from C, therefore we need to use c_int in place of enums for functions. Though we can declare the enum as constants i.e.
will be used as
Putting things together
Now we are ready to use the C functions in rust, but since C is “unsafe” as it lacks memory safety we need to call C functions in an unsafe
block.
We can now declare all the C functions and structs from our library in a crate. This crate would allow us to access raw C functions of the library. According to the conventions suggested by crates.io the name of this crate should be libname-sys. But our work is not over yet as using raw C functions in rust directly is not a good practice, it is also tedious for the end user of the crate as he needs to take care of memory safety and type conversion. Therefore we need to write a wrapper around this functions which will allow us to make them easier to use and rust-y too. It will be easier to explain writing wrappers using an example, so we will write a wrapper for a part of the libevdev library in the next post.
Until then Stay Tuned!!