'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 #includes 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