As you hopefully know, we publish different series in our blog. For example, The Basics covers essential Remote Desktop Manager functions, while Case Studies highlight examples of IT pros using our products to solve their problems. And for fun, there’s always our Monthly Poll and various quizzes (like this recent one that measures your Geek Level).
Today, I’m happy to introduce you to a new series called the Insider Series. As you might guess from the title, this series features articles by Devolutions’ Software Developers and explores the tools we use to develop our products. We hope that you find this new series interesting and that you find something for your own projects.
To get started, here's my article called “Using Rust Code in a C/C++ Project with CMake”.
I am currently working on Wayk Now written in C for the most part. We recently started writing new code for it in Rust which I’m super excited about.
As we needed a way to integrate this code in our CMake build1, we wrote a set of modules for CMake which can found on the following repository:
CMakeRust makes it possible to generate a static library with cargo and use it as a dependency. We currently handle the following:
- automatically find rustc and cargo
- build for Windows, Linux, macOS, Android and iOS
- build for 32 or 64 bit
- build in release or debug depending on the project configuration
A use-case we do not currently cover is adding a library as a dependency directly from crates.io, but rust libraries in the project can use dependencies as usual.
How to use it
Let’s go over a small example where we will generate a rust library and call its functions from C++. You can find the completed example here.
We will start with a basic C++ project containing two files, CMakeLists.txt and main.cpp.
First we copy the folder CMakeRust/cmake/ to our project and add the following lines to CMakeLists.txt to use the modules.
Next we add a rust library, here I used the name test-lib. An important detail is that we need to set the crate type to staticlib in the Cargo.toml.
To make functions accessible from C/C++ we annotate them with #[no_mangle] and declare them pub extern “C”. Note that we only need to do this for the exported functions, it is not required for the code that is only used inside the library.
In our library folder we create a CMakeLists.txt file with the following content. This tells CMake to generate the library and make it available as a dependency.
We create a header file to declare the library functions and include it in main.cpp.
The last step is to add test-lib as a dependency to the executable. On Windows, we also need to add ws2_32 and userenv as the Rust runtime depends on them. Here is the final CMakeLists.txt.
We’re all set to call our function from our C++ program.
We can now generate the project and build our program.