-
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
Merged
Merged
Changes from all commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
3440c95
rust: Initial config option
d3zd3z e0ab017
rust: Simple main wrapper
d3zd3z f18b0f0
rust: Basic `zephyr` crates
d3zd3z bccb7cf
rust: Add cmake support for building rust apps
d3zd3z 5c61adc
lib: rust: Add simple printk support to Rust
d3zd3z e771937
rust: Simple rust hello_world application
d3zd3z cc33b3f
MAINTAINERS: Add Rust to maintainers file
d3zd3z 972e0ee
doc: languages: Add Rust documentation
d3zd3z ee23080
rust: Ignore unknown cfgs in the zephyr crate
d3zd3z c94417c
cmake: rust: Add Cortex M7 support
d3zd3z c36845d
ci: tags: Add rust tag
d3zd3z 2cc2ba6
samples: rust: Tag the rust sample as rust
d3zd3z ff0e16c
rust: Move ignores to top .gitignore
d3zd3z df6b7b0
samples: rust: Add README for rust hello world
d3zd3z 424ca21
samples: rust: Rename hello world
d3zd3z efd8475
doc: languagues: rust: Reformat
d3zd3z 786a962
doc: languages: rust: typo fixes
d3zd3z b48c5f9
samples: rust: Include rust samples in docs
d3zd3z File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
# Rust make support | ||
|
||
# Zephyr targets are defined through Kconfig. We need to map these to | ||
# an appropriate llvm target triple. This sets `RUST_TARGET` in the | ||
# parent scope, or an error if the target is not yet supported by | ||
# Rust. | ||
function(_rust_map_target) | ||
# Map Zephyr targets to LLVM targets. | ||
if(CONFIG_CPU_CORTEX_M) | ||
if(CONFIG_CPU_CORTEX_M0 OR CONFIG_CPU_CORTEX_M0PLUS OR CONFIG_CPU_CORTEX_M1) | ||
set(RUST_TARGET "thumbv6m-none-eabi" PARENT_SCOPE) | ||
elseif(CONFIG_CPU_CORTEX_M3) | ||
set(RUST_TARGET "thumbv7m-none-eabi" PARENT_SCOPE) | ||
elseif(CONFIG_CPU_CORTEX_M4 OR CONFIG_CPU_CORTEX_M7) | ||
if(CONFIG_FP_HARDABI OR FORCE_FP_HARDABI) | ||
set(RUST_TARGET "thumbv7em-none-eabihf" PARENT_SCOPE) | ||
else() | ||
set(RUST_TARGET "thumbv7em-none-eabi" PARENT_SCOPE) | ||
endif() | ||
elseif(CONFIG_CPU_CORTEX_M23) | ||
set(RUST_TARGET "thumbv8m.base-none-eabi" PARENT_SCOPE) | ||
elseif(CONFIG_CPU_CORTEX_M33 OR CONFIG_CPU_CORTEX_M55) | ||
# Not a typo, Zephyr, uses ARMV7_M_ARMV8_M_FP to select the FP even on v8m. | ||
if(CONFIG_FP_HARDABI OR FORCE_FP_HARDABI) | ||
set(RUST_TARGET "thumbv8m.main-none-eabihf" PARENT_SCOPE) | ||
else() | ||
set(RUST_TARGET "thumbv8m.main-none-eabi" PARENT_SCOPE) | ||
endif() | ||
|
||
# Todo: The M55 is thumbv8.1m.main-none-eabi, which can be added when Rust | ||
# gain support for this target. | ||
else() | ||
message(FATAL_ERROR "Unknown Cortex-M target.") | ||
endif() | ||
elseif(CONFIG_RISCV) | ||
if(CONFIG_RISCV_ISA_RV64I) | ||
# TODO: Should fail if the extensions don't match. | ||
set(RUST_TARGET "riscv64imac-unknown-none-elf" PARENT_SCOPE) | ||
elseif(CONFIG_RISCV_ISA_RV32I) | ||
# TODO: We have multiple choices, try to pick the best. | ||
set(RUST_TARGET "riscv32i-unknown-none-elf" PARENT_SCOPE) | ||
else() | ||
message(FATAL_ERROR "Rust: Unsupported riscv ISA") | ||
endif() | ||
else() | ||
message(FATAL_ERROR "Rust: Add support for other target") | ||
endif() | ||
endfunction() | ||
|
||
function(rust_cargo_application) | ||
# For now, hard-code the Zephyr crate directly here. Once we have | ||
# more than one crate, these should be added by the modules | ||
# themselves. | ||
set(LIB_RUST_CRATES zephyr zephyr-build) | ||
|
||
_rust_map_target() | ||
message(STATUS "Building Rust llvm target ${RUST_TARGET}") | ||
|
||
# TODO: Make sure RUSTFLAGS is not set. | ||
|
||
# TODO: Let this be configurable, or based on Kconfig debug? | ||
set(RUST_BUILD_TYPE debug) | ||
set(BUILD_LIB_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${RUST_TARGET}/${RUST_BUILD_TYPE}") | ||
|
||
set(CARGO_TARGET_DIR "${CMAKE_CURRENT_BINARY_DIR}/rust/target") | ||
set(RUST_LIBRARY "${CARGO_TARGET_DIR}/${RUST_TARGET}/${RUST_BUILD_TYPE}/librustapp.a") | ||
set(SAMPLE_CARGO_CONFIG "${CMAKE_CURRENT_BINARY_DIR}/rust/sample-cargo-config.toml") | ||
|
||
# To get cmake to always invoke Cargo requires a bit of a trick. We make the output of the | ||
# command a file that never gets created. This will cause cmake to always rerun cargo. We | ||
# add the actual library as a BYPRODUCTS list of this command, otherwise, the first time the | ||
# link will fail because it doesn't think it knows how to build the library. This will also | ||
# cause the relink when the cargo command actually does rebuild the rust code. | ||
set(DUMMY_FILE "${CMAKE_BINARY_DIR}/always-run-cargo.dummy") | ||
|
||
# For each module in zephyr-rs, add entry both to the .cargo/config template and for the | ||
# command line, since either invocation will need to see these. | ||
set(command_paths) | ||
set(config_paths "") | ||
message(STATUS "Processing crates: ${ZEPHYR_RS_MODULES}") | ||
foreach(module IN LISTS LIB_RUST_CRATES) | ||
message(STATUS "module: ${module}") | ||
set(config_paths | ||
"${config_paths}\ | ||
${module}.path = \"${ZEPHYR_BASE}/lib/rust/${module}\" | ||
") | ||
list(APPEND command_paths | ||
"--config" | ||
"patch.crates-io.${module}.path=\\\"${ZEPHYR_BASE}/lib/rust/${module}\\\"" | ||
) | ||
endforeach() | ||
|
||
# Write out a cargo config file that can be copied into `.cargo/config.toml` (or made a | ||
# symlink) in the source directory to allow various IDE tools and such to work. The build we | ||
# invoke will override these settings, in case they are out of date. Everything set here | ||
# should match the arguments given to the cargo build command below. | ||
file(WRITE ${SAMPLE_CARGO_CONFIG} " | ||
# This is a generated sample .cargo/config.toml file from the Zephyr build. | ||
# At the time of generation, this represented the settings needed to allow | ||
# a `cargo build` command to compile the rust code using the current Zephyr build. | ||
# If any settings in the Zephyr build change, this could become out of date. | ||
[build] | ||
target = \"${RUST_TARGET}\" | ||
target-dir = \"${CARGO_TARGET_DIR}\" | ||
|
||
[env] | ||
BUILD_DIR = \"${CMAKE_CURRENT_BINARY_DIR}\" | ||
DOTCONFIG = \"${DOTCONFIG}\" | ||
ZEPHYR_DTS = \"${ZEPHYR_DTS}\" | ||
|
||
[patch.crates-io] | ||
${config_paths} | ||
") | ||
|
||
# The library is built by invoking Cargo. | ||
add_custom_command( | ||
OUTPUT ${DUMMY_FILE} | ||
BYPRODUCTS ${RUST_LIBRARY} | ||
COMMAND | ||
${CMAKE_EXECUTABLE} | ||
env BUILD_DIR=${CMAKE_CURRENT_BINARY_DIR} | ||
DOTCONFIG=${DOTCONFIG} | ||
ZEPHYR_DTS=${ZEPHYR_DTS} | ||
cargo build | ||
# TODO: release flag if release build | ||
# --release | ||
|
||
# Override the features according to the shield given. For a general case, | ||
# this will need to come from a variable or argument. | ||
# TODO: This needs to be passed in. | ||
# --no-default-features | ||
# --features ${SHIELD_FEATURE} | ||
|
||
# Set a replacement so that packages can just use `zephyr-sys` as a package | ||
# name to find it. | ||
${command_paths} | ||
--target ${RUST_TARGET} | ||
--target-dir ${CARGO_TARGET_DIR} | ||
COMMENT "Building Rust application" | ||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} | ||
) | ||
|
||
add_custom_target(librustapp ALL | ||
DEPENDS ${DUMMY_FILE} | ||
) | ||
|
||
target_link_libraries(app PUBLIC -Wl,--allow-multiple-definition ${RUST_LIBRARY}) | ||
add_dependencies(app librustapp) | ||
|
||
# Presumably, Rust applications will have no C source files, but cmake will require them. | ||
# Add an empty file so that this will build. The main will come from the rust library. | ||
target_sources(app PRIVATE ${ZEPHYR_BASE}/lib/rust/main.c) | ||
endfunction() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,3 +8,4 @@ Language Support | |
|
||
c/index.rst | ||
cpp/index.rst | ||
rust/index.rst |
kartben marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
.. _language_rust: | ||
|
||
Rust Language Support | ||
##################### | ||
|
||
Rust is a systems programming language focused on safety, speed, and concurrency. Designed to | ||
prevent common programming errors such as null pointer dereferencing and buffer overflows, Rust | ||
emphasizes memory safety without sacrificing performance. Its powerful type system and ownership | ||
model ensure thread-safe programming, making it an ideal choice for developing reliable and | ||
efficient low-level code. Rust's expressive syntax and modern features make it a robust alternative | ||
for developers working on embedded systems, operating systems, and other performance-critical | ||
applications. | ||
|
||
Enabling Rust Support | ||
********************* | ||
|
||
Currently, Zephyr supports applications written in Rust and C. The enable Rust support, you must | ||
select the :kconfig:option:`CONFIG_RUST` in the application configuration file. | ||
|
||
The rust toolchain is separate from the rest of the Zephyr SDK. It is recommended to use the | ||
`rustup`_ tool to install the rust toolchain. In addition to the base compiler, you will need to | ||
install core libraries for the target(s) you wish to compile on. It is easiest to determine what | ||
needs to be installed by trying a build. The diagnostics from the rust compilation will indicate | ||
the rust command needed to install the appropriate target support: | ||
|
||
.. _rustup: https://rustup.rs/ | ||
|
||
.. code-block:: console | ||
|
||
$ west build ... | ||
... | ||
error[E0463]: can't find crate for `core` | ||
| | ||
= note: the `thumbv7m-none-eabi` target may not be installed | ||
= help: consider downloading the target with `rustup target add thumbv7m-none-eabi` | ||
|
||
In this case, the given ``rustup`` command will install the needed target support. The target | ||
needed will depend on both the board selected, as well as certain configuration choices (such as | ||
whether floating point is enabled). | ||
|
||
Writing a Rust Application | ||
************************** | ||
|
||
See :zephyr_file:`samples/rust` for examples of an application. | ||
|
||
CMake files | ||
----------- | ||
|
||
The application should contain a :file:`CMakeLists.txt`, similar to the following: | ||
|
||
.. code-block:: cmake | ||
|
||
cmake_minimum_required(VERSION 3.20.0) | ||
|
||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) | ||
project(hello_world) | ||
|
||
rust_cargo_application() | ||
|
||
Cargo files | ||
----------- | ||
|
||
Rust applications are built with Cargo. The Zephyr build system will configure and invoke cargo in | ||
your application directory, with options set so that it can find the Zephyr support libraries, and | ||
that the output will be contained within the Zephyr build directory. | ||
|
||
The :file:`Cargo.toml` will need to have a ``[lib]`` section that sets ``crate-type = | ||
["staticlib"]``, and will need to include ``zephyr = "0.1.0"`` as a dependency. You can use | ||
crates.io and the Crate ecosystem to include any other dependencies you need. Just make sure that | ||
you use crates that support building with no-std. | ||
|
||
Application | ||
----------- | ||
|
||
The application source itself should live in :file:`src/lib.rs`. A few things are needed. A minimal | ||
file would be: | ||
|
||
.. code-block:: rust | ||
|
||
#![no_std] | ||
|
||
extern crate zephyr; | ||
|
||
#[no_mangle] | ||
extern "C" fn rust_main() { | ||
} | ||
|
||
The ``no_std`` declaration is needed to prevent the code from referencing the ``std`` library. The | ||
extern reference will cause the zephyr crate to be brought in, even if nothing from it is used. | ||
Practically, any meaningful Rust application on Zephyr will use something from this crate, and this | ||
line is not necessary. Lastly, the main declaration exports the main symbol so that it can be | ||
called by C code. The build ``rust_cargo_application()`` cmake function will include a small C file | ||
that will call into this from the C main function. | ||
|
||
Zephyr Functionality | ||
******************** | ||
|
||
The bindings to Zephyr for Rust are under development, and are currently rather minimalistic. | ||
|
||
Bool Kconfig settings | ||
--------------------- | ||
|
||
Boolean Kconfig settings can be used from within Rust code. Due to design constraints by the Rust | ||
language, settings that affect compilation must be determined before the build is made. In order to | ||
use this in your application, you will need to use the ``zephyr-build`` crate, provided, to make | ||
these symbols available. | ||
|
||
To your ``Cargo.toml`` file, add the following: | ||
|
||
.. code-block:: toml | ||
|
||
[build-dependencies] | ||
zephyr-build = "0.1.0" | ||
|
||
Then, you will need a ``build.rs`` file to call the support function. The following will work: | ||
|
||
.. code-block:: rust | ||
|
||
fn main() { | ||
zephyr_build::export_bool_kconfig(); | ||
} | ||
|
||
At this point, it will be possible to use the ``cfg`` directive in Rust on boolean Kconfig values. | ||
For example: | ||
|
||
.. code-block:: rust | ||
|
||
#[cfg(CONFIG_SCHED_DUMB)] | ||
one_declaration; | ||
|
||
#[cfg(not(CONFIG_SCHED_DUMB))] | ||
other_declaration; | ||
|
||
Other Kconfig settings | ||
---------------------- | ||
|
||
All bool, numeric and string Kconfig settings are accessible from the ``zephyr::kconfig`` module. | ||
For example: | ||
|
||
.. code-block:: rust | ||
|
||
let ceiling = zephyr::kconfig::CONFIG_PRIORITY_CEILING - 1; | ||
|
||
Other functionality | ||
------------------- | ||
|
||
Access to other functionality within zephyr is a work-in-progress, and this document will be updated | ||
as that is done. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# Rust configuration options | ||
# | ||
# Copyright (c) 2024 Linaro LTD | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
menu "Rust Language Support" | ||
|
||
config RUST_SUPPORTED | ||
bool | ||
default y if (CPU_CORTEX_M || \ | ||
(RISCV && !RISCV_ISA_RV32E && !RISCV_ISA_RV128I)) | ||
help | ||
Selected for platforms that have support for Rust. | ||
|
||
config RUST | ||
bool "Rust support for the application" | ||
depends on RUST_SUPPORTED | ||
select EXPERIMENTAL | ||
help | ||
This option enables the use of applications written in Rust. | ||
|
||
endmenu |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Have you considered adding Rust support in upstream CMake? I don't see anything wrong with maintaining this in Zephyr for now but it would be great if we can add the support to cmake itself.
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.
I'm not exactly sure what would be upstreamed here. everything in this cmake file is specific to building this within Zephyr. I don't see how it would be useful in any other context.