Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integration with C codebases #48

Closed
japaric opened this issue Feb 22, 2018 · 13 comments
Closed

Integration with C codebases #48

japaric opened this issue Feb 22, 2018 · 13 comments
Assignees
Milestone

Comments

@japaric
Copy link
Member

japaric commented Feb 22, 2018

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:

  • Integrate Rust / Cargo into a C project build system.

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?

  • Binding C code (FFI)

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.

  • Calling Rust from C applications.

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?

@jamesmunns
Copy link
Member

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?

@jamesmunns
Copy link
Member

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.

@nastevens
Copy link
Member

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 japaric added the docs label Mar 16, 2018
@japaric japaric added this to the Epoch 2018 milestone Mar 16, 2018
@jamesmunns
Copy link
Member

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

@jdub
Copy link

jdub commented Apr 4, 2018

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
Copy link
Member Author

japaric commented Apr 5, 2018

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.

@ryankurte
Copy link
Contributor

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
Copy link
Member Author

japaric commented Jul 17, 2018

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

  • "A little Rust with your C code". Integrating a Rust component into an existing C project.
  • "A little C with your Rust code". Creating bindings to some C library / SDK and using that from a Rust project.

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

@japaric japaric modified the milestones: 2018 edition, RC Jul 17, 2018
@jamesmunns
Copy link
Member

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.

@adamgreig
Copy link
Member

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.

@jamesmunns
Copy link
Member

@jdub tagging rust-lang/rust#49879 as the former issue has been closed in favor of this (ThinLTO across languages)

@Ekleog
Copy link

Ekleog commented Aug 2, 2018

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! 💯

@japaric
Copy link
Member Author

japaric commented Aug 10, 2018

This issue was moved to rust-embedded/book#1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants