'How do I invoke a C++ Arduino library from rust?
It has been possible to build apps for Arduino and Teensy written in Rust for a while.
You can find lists of peripheral libraries ( https://github.com/rust-embedded/awesome-embedded-rust ) , but there are so many peripherals that it can take a while for native Rust implementations to be written for the less common ones.
In my case, I have AdaFruit Neopixels. There are a couple of C++ libraries for this ( https://github.com/Makuna/NeoPixelBus/wiki/Library-Comparisons ) , but the only Rust library I could find is https://github.com/trezm/neopixel_rs which depends on a crate with a path of ../photon-hal
, and even when I remove that, I get compile errors deep in a macro which might be related to the build.rs
for compiling the C++ elements. I'm not even sure it is targeting the Arduino.
Is there a document that outlines the proper procedure for cross-compiling a C++ module from the Arduino, and then wrapping it in a Rust API?
Solution 1:[1]
So far I have developed a crate to help me write Rust wrappers for C++ libraries. rust-arduino-helpers is a library of helper functions and as of 2022-May is almost entirely undocumented.
rust-arduino-helpers
is mostly driven by the development of the rust-arduino-wrappers crate, which contains wrappers for the Ethernet, NeoPixel, and PubSubClient(MQTT) libraries.
The first step is build.rs
. Use bindgen
to translate the C++ header file into a Rust bindings.rs
.
Then you compile the C++ library source so you can include the library in the rust app. Sometimes you create a file like src-cpp/multi.cpp
which #include
s the various .cpp
files of the library. Alternatively, you can list the library source files as individual arguments to the file() method of the cc:Build
object.
The rust-arduino-helpers
crate has helper methods that help configure bindgen
and the cc:Build
. Then create a src/raw.rs
containing something like
#![allow(non_snake_case, non_upper_case_globals, non_camel_case_types)]
#![allow(dead_code)]
#![allow(clippy::all)]
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
In the raw.rs
file you can add a little bit of helper code (sometimes a use
clause), but the majority of your wrappers will go in lib.rs
. This is where you'll create Rust wrapper structs that own pins or other devices, and ensure correct initialization and deallocation.
It may be helpful to examine some of the examples like ethernet/build.rs until there is proper documentation
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Mutant Bob |