rust-embedded / book

Documentation on how to use the Rust Programming Language to develop firmware for bare metal (microcontroller) devices
https://docs.rust-embedded.org/book/
Apache License 2.0
1.12k stars 177 forks source link

Integration with C codebases #1

Closed japaric closed 6 years ago

japaric commented 6 years ago

Triage(2018-08-21)

We need help writing the initial content for this section.


From @japaric on February 22, 2018 13:29

An approach that has worked well for the adoption of Rust in std land is to replace existing components of a C codebase with Rust components (rather than the more radical rewrite everything in Rust from scratch).

I think we are lacking guides for this important use case in embedded Rust land and we should fix that. There are different aspects to integrating Rust into a existing C codebase:

The Rust team has been working on making this easier since last year but I don't know what's the current status.

What build systems can we expect to encounter in practice? Makefiles, cmake? Do we have examples of integrating Cargo with those?

Some examples will probably come out of the work of binding RTOSes in #45. We should write a guide (e.g. "how to use bindgen to bind C code that will be used in no_std context") once we have gained experience.

Example use case: write your parser in Rust and call it from C.

Do we have any examples of this? Anyone tried rusty-cheddar in no_std context?

Copied from original issue: rust-embedded/wg#48

japaric commented 6 years ago

From @jamesmunns on February 27, 2018 18:50

I made a talk last year based on my learnings when integrating C/C++ code for the teensy3 and nrf52dk-sys crates.

The slides are here and the video is here.

I think there are two main scenarios to consider:

  1. Rust is the main component, and is calling C code because of existing code/driver support.
  2. C is the main component, with Rust covering one or a few specific parts.

I believe the content of my talk above covers 1, and I would be willing to refine that out into a more verbose guide, blog post, or something. Tools like gcc-rs and bindgen cover most of the work here, and this path is relatively well travelled.

I have not seen too many examples of 2, though I think we could probably take a lot of learnings from Mozilla and the Firefox team, as they are using these techniques heavily for post-Quantum builds of Firefox, where their existing build tools are driving Cargo to generate libraries used by C++ code. Perhaps @japaric, @hannobraun, and I could discuss this during the Mozilla all-hands later this month?

japaric commented 6 years ago

From @jamesmunns on February 27, 2018 19:7

Another issue with integrating with C codebases is matching the configuration of the C project in Rust. For most C libraries (including driver and bsp support), this machinery is configured using compile time #define flags set by the dependent code, or by -D settings at the command line/Makefile.

Rust's equivalent is broken up into two components: build.rs scripts, and #[cfg()] items, which are not a 1:1 equivalent.

japaric commented 6 years ago

From @nastevens on March 2, 2018 17:14

The friction when integrating C and Rust gets cranked way up when you add cross-compiling to the mix, and 99.9% or more of embedded code is going to be cross-compiled. In addition to documentation of how to deal with different cross-compiling scenarios when integrating Rust with C, it may also be valuable to look at the current state of the art for Rust interaction with things like CMake and see if there aren't programmatic improvements that can also be made. @posborne may also have more thoughts on this, since he wrote a majority of the current CMake + Rust build system we use at work.

japaric commented 6 years ago

From @jamesmunns on April 3, 2018 19:55

@japaric This topic is going to be covered in #56 - We may want to close this issue as a duplicate

japaric commented 6 years ago

From @jdub on April 4, 2018 16:3

rust-lang/rust#45865 might be interesting/relevant here… it'd be great to have LTO working across Rust and C components of an embedded project.

japaric commented 6 years ago

Someone asked yesterday on IRC about using C allocator as Rust's allocator so I set out to investigate how to do that and wrote down my findings in the following gist:

https://gist.github.com/japaric/b5e0a7450d968f6ca29c4d238d34a2d0

This uses newlib's malloc / free interface to implement a Rust allocator, and it looks pretty similar to alloc_system, which is part of the std facade. It may be good to include a more polished version of that in the book as I expect some SDKs use standard malloc / free for memory allocation and in that case you may want to have a single allocator and not a C one and Rust one.

japaric commented 6 years ago

From @ryankurte on May 11, 2018 1:50

I've thrown together some helpers for including a rust library in a CMake based C/C++ project using rusty-binder and rusty-cheddar. It's definitely working natively, and set up and linking but untested for arm cortex-m3 and cortex-m4s.

One issue with this approach is the requirement that even with a header generator, the rust functions need to be written to be C compatible. So, this is fine for writing new rust code to replace C code, but doesn't support using existing rust libraries directly.

This is pretty much inline with my experience of writing rust wrappers for C libraries, it seems like the binding generators in both direction could/should be producing an intermediary to either wrap c-types in rust or rust-types in c (for example, flattening methods on objects into functions and adding extern, #[repr(C)] etc), so I guess that's something to consider going forward.

japaric commented 6 years ago

I'm repurposing this issue to track a book section about integrating Rust and C code. We discussed two scenarios:

The Rust book probably covers this so we should focus on the aspects specific to #[no_std] applications.

japaric commented 6 years ago

From @jamesmunns on July 29, 2018 11:49

For the interoperability docs (little C with your rust), I'd like to use an existing C library with permissive licensing as the C example. Perhaps micro-ecc, though I am open to other examples. The focus will be primarily on build.rs scripts and bindgen.

For the other way (a little Rust with your C), I'd like to find a Rust library that has an appropriate interface for binding against with C. The focus will be primarily on cbindgen, creating a staticlib with cargo, and integrating that into a build system, such as make.

japaric commented 6 years ago

From @adamgreig on July 29, 2018 17:58

As an example of a small Rust library that exposes a C API, I wrote labrador-ldpc a while back. It's an LDPC (error-correcting code) encoding/decoding library designed for embedded use. I didn't use cbindgen though, I just wrote my own interface.

japaric commented 6 years ago

From @jamesmunns on July 29, 2018 18:20

@jdub tagging https://github.com/rust-lang/rust/issues/49879 as the former issue has been closed in favor of this (ThinLTO across languages)

japaric commented 6 years ago

From @Ekleog on August 2, 2018 14:4

As there is a request for use cases and I've been pointed here, here is what I remember from when I integrated a consequent part of Rust with a C “root” for an embedded system.

I've written a Makefile that just compiled the Rust crate as staticlib, and then the C code called into it (with manually-written FFI, didn't know about cbindgen, I don't know what I would do now). Given (IIRC) xargo was not mature yet, I had just bundled the dependencies and the libc as submodules at first, before switching to xargo. I also had to make a fake std crate for rust-bindgen, so that it would have its c_* types.

Since then, C++ has been added into the mix, and I think it's currently using cmake, still compiling Rust as staticlib called from C.

Just my 2¢ from relatively old memory :) Thank you for your work making Rust more suitable for embedded targets! :100:

japaric commented 6 years ago

Triage: we need help writing the initial content for this section.

jamesmunns commented 6 years ago

Repinging @spacekookie, who mentioned having written something up for this.

spacekookie commented 6 years ago

I just opened #23 as a WIP PR. I'd want to add a few more things before merging. And feedback always welcome.

jamesmunns commented 6 years ago

Related issues we need to review before calling this done:

ryankurte commented 6 years ago

I updated my rust cmake stuff into a real project w/ cmake functions: ryankurte/rust-cmake (cc. @posborne).

I think it'd be neat to have canonical approaches (or at least examples) for using cmake and make, but I'm not sure how we'd like to go about it?

japaric commented 6 years ago

closing in favor of #61 and #62