-
Notifications
You must be signed in to change notification settings - Fork 6.6k
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
Beginning of Rust support in Zephyr #75904
Conversation
91f46b8
to
e1d0982
Compare
Thank you for making this PR. It's great to get the ball rolling! Let's make Rust in Zephyr great! But, I think this PR tries to do a bit too much too quickly. I think the most important first step is to ensure building and linking is done correctly. I think would be best to focus on this and de-scope other parts of this PR for later. Please read on below where I try to explain. LLVM tripletsThis PR is using LLVM for compiling Rust, which I think is a good idea. But it does mean we need to think about ABI compatibility with the Zephyr toolchain. Linking with LLVM objects is not a Rust-specific problem, and we should solve this first, possibly in a language-agnostic way. We should start with a solid foundation on how to correctly build LLVM objects for linking with the Zephyr ABIs. I think the as first thing on the roadmap to Rust, Zephyr should have an utility that selects a foolproof LLVM target specification. And we must have tests that can verify that it works at runtime, e.g. by calling various types of functions and checking for data corruption. The reason this may be a concern is that Zephyr defines its own ABI, which may or may not be equivalent to any of the well-known LLVM triplets. For example, in Zephyr The PR uses the well-known For prior art, see tylerwhall/zephyr-rust target specifications, which defines new LLVM triplets for Zephyr OS. This project also Apache-licensed. Kconfig in RustI feel a framework for exposing Kconfig values in Rust should be done at a later stage, since there are many ways to do this and it has attracted comments on how to map the Kconfig values onto Rust types. I think it's better to defer this work, so that the initial Rust support is not delayed by this. Rust already has I also worry there are good reasons for why Safety in samplesThe sample declares Safety is integral to Rust culture. I think that all Rust samples code should be |
So, I think we have different philosophies about what we need to do to get rust support into Zephyr. Yes, there is stuff that we need to do "right", but if we are too careful, we'll never get anything at all. My goal here is just to go through the build stuff, and I have a lot of other stuff in process that needs to builds to be able to happen. I guess I'd rather have it work well in a limited situation than solve everything before anything can go in.
So, getting this right is important, but this is also difficult to come up with tests for. One possibility is to just be more restrictive about it, and pick configurations that we know work. But, I don't think the calling is as difficult of an issue as you are imagining. Generally, getting the triple wrong is more likely to result in either code that doesn't run at all (using the wrong CPU), or fails at link time (usually from hard float mismatch). Matching the Zephyr types is important, but I wouldn't think of that as a compiler or toolchain, but a matching the ABI. It is also not addresed at all yet, as we aren't really calling anything.
I disagree about delaying it. I'm open for other ideas on how to do it, but getting access to them is foundational for most later work. Do you have specific concerns about how I'm doing it? I'm not quite sure I understand how
As far as the samples, it isn't intended to stay that way, and in fact, my other PR has already removed it. Basically, I'm concerned about spinning, while bike shedding things that really aren't that important. One of my goals is to make using Rust inside of Zephyr as nice (well, hopefully nicer) as writing C code. Coming next is making the DT available to Rust code. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
some documentation related feedback. I might have more when CI has a preview site up again
Thanks <3
doc/develop/languages/rust/index.rst
Outdated
|
||
.. _rustup: https://rustup.rs/ | ||
|
||
.. code-block:: shell |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.. code-block:: shell | |
.. code-block:: console |
Add the `CONFIG_RUST` Kconfig. This can be set to indicate that an application wishes to use Rust support. Adds `CONFIG_RUST_SUPPORTED` to indicate what platforms Rust is known to work on. This is set to the targets that are supported by subsequent commits. Signed-off-by: David Brown <david.brown@linaro.org>
Until further variants are needed, this provides a `main()` function that simply calls into the `rust_main()` function. This is adequate for applications where main can be directly written in Rust. The reason that this is written here, rather than just writing `main` directly in Rust is that `kernel/main_weak.c` provides a weak default implementation that will be brought in before the Rust application's `main` is linked in. Signed-off-by: David Brown <david.brown@linaro.org>
This is the initial Zephyr-specific crates that provide support for Rust on Zephyr. Currently, what they do is fairly minimal, but important. `zephyr-build` is a build time crate (linked against the `zephyr` crate's build.rs) that processes the current build's Kconfig settings, and does three things with them: - Boolean Kconfig values given given to the Rust toolchain so that conditional compilation can be based off of them. - Numeric Kconfig settings end up as constants in `zephyr::kconfig`. - String valued Kconfig settings end up as constants in `zephyr::kconfig`. None of these cause code or data to be generated or allocated (but note that if there is a reference to a string, that string will be placed in read-only memory). The `zephyr` crate is built for the target, and intended to be referenced by the application. It provides minimal support needed for a "bare" Rust build, notably a panic handler. At this point, the panic handler is not implemented as we need better support for calling into Zephyr's C code, so it just stops in an infinite loop. It also ensures that `CONFIG_RUST` is set as a sanity check, and includes the generated kconfig.rs file with the kconfig definitions for the current build. Signed-off-by: David Brown <david.brown@linaro.org>
This provides the function `rust_cargo_application()` within Cmake to give applications written in Rust a simple way to start. This implements the basic functionality needed to build a rust application on Arm, including target mapping, and invoking cargo during the build. Most of the functionality is about passing the appropriate flags to `cargo`, which is used to perform the actual build of the rust code. Cargo generates `librustapp.a` which is added to the link dependencies for the application. The cargo rule is written such that cargo will always be built (provided `app` is being built), as there will be complex dependencies on the cargo side. Cargo will not modify the `librustapp.a` file if nothing needs to be build, so this will generally be fast if there are no changes to files that affect the Rust build. Signed-off-by: David Brown <david.brown@linaro.org>
When `CONFIG_PRINTK` is enabled, provide macros `printk` and `printkln` within the `zephyr` crate that applications can use to print. This currently sends messages, with a small amount of buffering, using `k_str_out`. Until C functions are made generally available from the Rust side, we use a small wrapper function to call `k_str_out`, as it is implemented as an inline syscall. Signed-off-by: David Brown <david.brown@linaro.org>
Create the Rust equivalent of the hello_world application. This shows the use of printk from Rust as well as accessing a string value from Kconfig. Signed-off-by: David Brown <david.brown@linaro.org>
Indicate the new code is maintained. Signed-off-by: David Brown <david.brown@linaro.org>
Add initial docs for Rust language support. Explains the support currently present, how to install the toolchain needed, and explains what is in the current sample. Signed-off-by: David Brown <david.brown@linaro.org>
We use the `#[cfg(...)]` directive in rust to pass Kconfig values through. Because it is possible for the code to depend on a Kconfig value that isn't present in a given build, there isn't a way for us to tell the Rust toolchain about all possible config values. For now, just disable this warning entirely. This functionality could be supported by the patch validation scripts, which seems like a better place than trying to gather a list of all possible configs at build time. Signed-off-by: David Brown <david.brown@linaro.org>
The Cortex-M7 is build the same as M4. Catch it in the same rules. Signed-off-by: David Brown <david.brown@linaro.org>
The rust tag associates rust tests and samples with code that adds rust support to Zephyr. Signed-off-by: David Brown <david.brown@linaro.org>
Add the 'rust' tag so that CI will invoke this test when rust support files have changed. Signed-off-by: David Brown <david.brown@linaro.org>
5c062d2
to
a56d8e4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
.github/workflows/rust.yaml
Outdated
- name: Install Rust Toolchain | ||
run: | | ||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y | ||
# Add to the local environment to be able to use. | ||
source "$HOME/.cargo/env" | ||
# Install support for the targets that are supported. | ||
for target in $`cat lib/rust/targets.txt`; do rustup target install $$target; done |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this necessary if we use the Rust toolchain integrated in the CI Docker image?
.github/workflows/rust.yaml
Outdated
@@ -0,0 +1,178 @@ | |||
name: Build Rust tests |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need a separate workflow for building and running Rust applications? It would be better to integrate this into the existing twister workflow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a mistake, I will remove this file entirely.
Apply the rules to ignore some cargo generated or used files to the whole tree, not just the samples. Signed-off-by: David Brown <david.brown@linaro.org>
Create a Readme for this sample, explaining how to build and what it does. Signed-off-by: David Brown <david.brown@linaro.org>
Rename the sample to just hello world. As long as the actual sample name is different, there won't be index conflicts in the documentation. Signed-off-by: David Brown <david.brown@linaro.org>
Refill the text to 100 columns instead of 72 to match the rest of the project. Signed-off-by: David Brown <david.brown@linaro.org>
Fix various minor typos in the Rust documentation. Signed-off-by: David Brown <david.brown@linaro.org>
Include the Sample Rust applications in the doc generation. Signed-off-by: David Brown <david.brown@linaro.org>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 for docs/samples - thanks for this @d3zd3z!
This package implements the bare minimum support needed to build a simple Zephyr application written in Rust. There are no bindings or Zephyr API's provided, just the build infrastructure. The is described in #75900.