Compare commits

...

39 Commits

Author SHA1 Message Date
David Brown
f67ff24ff0 cmake: rust: Comment typo fix
Fix a mispelled word "al" -> "all".

Signed-off-by: David Brown <david.brown@linaro.org>
2024-09-06 09:15:47 -06:00
David Brown
646ee215c7 cmake: rust: Remove redundant call
Remove a redundant call that does exactly what the previous function
call accomplishes.

Signed-off-by: David Brown <david.brown@linaro.org>
2024-09-06 09:15:47 -06:00
David Brown
f7fed4da0f doc: develop: rust: Various cleanups to docs
Minor fixes to the documentation from review feedback.

Signed-off-by: David Brown <david.brown@linaro.org>
2024-09-06 09:15:47 -06:00
David Brown
71619deaee cmake: rust: Add header dependencies to cargo
With bindgen needing to read the headers, make sure CMake knows about
this.

Signed-off-by: David Brown <david.brown@linaro.org>
2024-09-06 09:15:47 -06:00
David Brown
389c78d573 .gitignore: Ignore Rust 'target' directories
Although the Cmake rules to build Rust applications keeps the target
directory inside of the build directory, some IDE tools may generate a
target directory while editing the code.  Ignore these so they never get
checked in.

Signed-off-by: David Brown <david.brown@linaro.org>
2024-09-06 09:15:47 -06:00
David Brown
60fde89b38 rust: zephyr-sys: Fixup clang targets for RISCV
Rustc for RISCV encodes optional features on the CPU available as part
of the target tuple.  Clang, on the other hand does not.  In order to be
able to use libclang with bindgen on RISCV, we need to simplify the
target tuples a bit.  Do this by just matching 'riscv32' or 'riscv64'
and then passing in a generic tuple.  We aren't generating any code, and
the structs should always match between the targets.

Signed-off-by: David Brown <david.brown@linaro.org>
2024-09-06 09:15:47 -06:00
David Brown
0332ce8554 rust: Workaround gcc/clang differences with soft fp
GCC automatically defines a `__SOFTFP__` define on targets that are
using software floating point.  The clang compiler does not do this by
default, so check this, and define it.

Signed-off-by: David Brown <david.brown@linaro.org>
2024-09-06 09:15:47 -06:00
David Brown
a57ceb78ed Revert "include: Add dummy field for Rust as well as CPP"
This reverts commit 2046760e71.

Put these back so we get the zero element structures when using just
rust and not CPP.  A subsequent patch will suppress the warning.

Signed-off-by: David Brown <david.brown@linaro.org>
2024-09-06 09:15:47 -06:00
David Brown
c93d7a5ee6 rust: Suppress warning about improper C types
Zephyr takes advantage of a gcc/clang extension that allows structs that
have no elements.  Rust is perfectly happy with this (it is quite common
in Rust code), but generates a warning when a struct containing no
elements is passed to C code.

For now, suppress this warning on the generated bindings.  This has the
disadvantage of suppressing it entirely, which might possibly detect
other cases of invalid structs.  However, the bindings are
auto-generated from C structs so should always be valid.

Signed-off-by: David Brown <david.brown@linaro.org>
2024-09-06 09:15:47 -06:00
David Brown
a40ddef8d9 cmake: rust: Fix typo on variable name
Fix `WRAPPER_FiLE` to `WRAPPER_FILE`.

Signed-off-by: David Brown <david.brown@linaro.org>
2024-09-06 09:15:47 -06:00
David Brown
0756a9cfbb rust: Export zephyr-sys as zephyr::raw
Re-export all of the bindgen generated bindings in the zephyr-sys crate
into `zephyr::raw`.  This keeps things easier, as users of `zephyr` only
need to worry about the single `zephyr` crate.

Signed-off-by: David Brown <david.brown@linaro.org>
2024-09-06 09:15:47 -06:00
David Brown
fc8d858ce8 doc: rust: Add docs on bindings
Add documentation on the bindings between Rust and C, and the bindgen
tool used to generate them.

Signed-off-by: David Brown <david.brown@linaro.org>
2024-09-06 09:15:47 -06:00
David Brown
d98eae8ca9 rust: zephyr-sys: Use absolute path for wrapper
Change the header passed into bindgen to be an absolute path.  This will
cause the generated wrapper to refer to this file also using an absolute
path.  As such, remove the explicit include path added as part of the
build.

Signed-off-by: David Brown <david.brown@linaro.org>
2024-09-06 09:15:47 -06:00
David Brown
c440acd3a9 cmake: rust: Compile the bindgen wrapper
When compiling Rust programs, the bindgen utility generates a wrapper file
to expand inline functions, as these otherwise cannot be accessed from
rust.  Pass a consistent name to the cargo build, and add it to our source
build so that this wrapper get compiled.

Signed-off-by: David Brown <david.brown@linaro.org>
2024-09-06 09:15:47 -06:00
David Brown
8dc77158ff include: Add dummy field for Rust as well as CPP
For CPP builds, a few structs that end up empty in some configurations will
generate compile errors.  With the Rust tools, bindgen ends up producing
empty structsw for these as well.  Although the code compiles, it generates
warnings.  For now, add CONFIG_RUST to the ifdef checks so that these
structs don't end up empty with Rust either.

Signed-off-by: David Brown <david.brown@linaro.org>
2024-09-06 09:15:47 -06:00
David Brown
acac09ec6d rust: Convert k_str_out to bindgen one
Remove the manual k_str_out wrapper, and use the one generated by bindgen.

Signed-off-by: David Brown <david.brown@linaro.org>
2024-09-06 09:15:47 -06:00
David Brown
542d65fcd4 rust: Use zephyr-sys to get bindings
Instead of trying to manually generate the bindings, use those generated by
bindgen in the zephyr-sys crate.

Signed-off-by: David Brown <david.brown@linaro.org>
2024-09-06 09:15:47 -06:00
David Brown
f806a3f9e5 rust: Create zephyr-sys for low-level bindings
With a lot of work done by Mario Jaun <mario.jaun@zuehlke.com>.

Use the rust-bindgen tool to extract bindings from the Zephyr header files.
The tool is run with the exact configuration of the current build, and
therefore the bindings will match the current target.  The ifdefs and such
are not translated into the Rust code, and this must be generated live for
each build.

Signed-off-by: David Brown <david.brown@linaro.org>
2024-09-06 09:15:47 -06:00
David Brown
4dd43cafbd samples: rust: Include rust samples in docs
Include the Sample Rust applications in the doc generation.

Signed-off-by: David Brown <david.brown@linaro.org>
2024-08-27 08:47:59 -06:00
David Brown
be6c708901 doc: languages: rust: typo fixes
Fix various minor typos in the Rust documentation.

Signed-off-by: David Brown <david.brown@linaro.org>
2024-08-27 08:47:59 -06:00
David Brown
efd15c89d1 doc: languagues: rust: Reformat
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>
2024-08-27 08:47:59 -06:00
David Brown
63097dfac5 samples: rust: Rename hello world
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>
2024-08-27 08:47:59 -06:00
David Brown
21a58bebed samples: rust: Add README for rust hello world
Create a Readme for this sample, explaining how to build and what it
does.

Signed-off-by: David Brown <david.brown@linaro.org>
2024-08-27 08:47:59 -06:00
David Brown
42b25ccef0 rust: Move ignores to top .gitignore
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>
2024-08-27 08:47:59 -06:00
David Brown
9daf9a6238 samples: rust: Tag the rust sample as rust
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>
2024-08-27 08:47:59 -06:00
David Brown
5249c82425 ci: tags: Add rust tag
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>
2024-08-27 08:47:59 -06:00
David Brown
24a71d59b4 cmake: rust: Add Cortex M7 support
The Cortex-M7 is build the same as M4.  Catch it in the same rules.

Signed-off-by: David Brown <david.brown@linaro.org>
2024-08-27 08:47:59 -06:00
David Brown
6c8b63cee6 rust: Ignore unknown cfgs in the zephyr crate
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>
2024-08-27 08:47:59 -06:00
David Brown
15556acd18 doc: languages: Add Rust documentation
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>
2024-08-27 08:47:59 -06:00
David Brown
6b436713f1 MAINTAINERS: Add Rust to maintainers file
Indicate the new code is maintained.

Signed-off-by: David Brown <david.brown@linaro.org>
2024-08-27 08:47:59 -06:00
David Brown
3f8ebadde7 rust: Simple rust hello_world application
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>
2024-08-27 08:47:59 -06:00
David Brown
68e2023837 lib: rust: Add simple printk support to Rust
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>
2024-08-27 08:47:59 -06:00
David Brown
1ed0aeab6b rust: Add cmake support for building rust apps
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>
2024-08-27 08:47:59 -06:00
David Brown
5230bb462e rust: Basic zephyr crates
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>
2024-08-27 08:47:59 -06:00
David Brown
148e135137 rust: Simple main wrapper
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>
2024-08-27 08:47:59 -06:00
David Brown
3496844d37 rust: Initial config option
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>
2024-08-27 08:47:59 -06:00
David Brown
5cbb204210 github: workflows: Update other docker image reference
The twister workflow contains two references to the docker image to use.
The earlier change only updated one of these.  Update the other to
match.  This should allow rust code to be built in the whole twister
workflow.

Signed-off-by: David Brown <david.brown@linaro.org>
2024-08-24 07:58:26 -04:00
David Brown
45c96c74e2 github: workflows: Add cargo support to twister
Add cargo's bin to the path, and print out the versioning of the tool to
make it easy to ensure the right version has been installed.

Signed-off-by: David Brown <david.brown@linaro.org>
2024-08-23 09:13:35 -06:00
David Brown
8c4b1635ba github: workflows: Update docker image
Use the v0.24.14 docker image, which adds rust target support.

Signed-off-by: David Brown <david.brown@linaro.org>

fix
2024-08-23 09:13:35 -06:00
30 changed files with 1021 additions and 2 deletions

View File

@@ -25,7 +25,7 @@ jobs:
runs-on:
group: zephyr-runner-v2-linux-x64-4xlarge
container:
image: ghcr.io/zephyrproject-rtos/ci-repo-cache:v0.26.13.20240601
image: ghcr.io/zephyrproject-rtos/ci-repo-cache:v0.26.14.20240823
options: '--entrypoint /bin/bash'
outputs:
subset: ${{ steps.output-services.outputs.subset }}
@@ -129,7 +129,7 @@ jobs:
needs: twister-build-prep
if: needs.twister-build-prep.outputs.size != 0
container:
image: ghcr.io/zephyrproject-rtos/ci-repo-cache:v0.26.13.20240601
image: ghcr.io/zephyrproject-rtos/ci-repo-cache:v0.26.14.20240823
options: '--entrypoint /bin/bash'
strategy:
fail-fast: false
@@ -188,6 +188,7 @@ jobs:
git log --pretty=oneline | head -n 10
fi
echo "$HOME/.local/bin" >> $GITHUB_PATH
echo "$HOME/.cargo/bin" >> $GITHUB_PATH
west init -l . || true
west config manifest.group-filter -- +ci,+optional
@@ -201,6 +202,8 @@ jobs:
run: |
cmake --version
gcc --version
cargo --version
rustup target list --installed
ls -la
echo "github.ref: ${{ github.ref }}"
echo "github.base_ref: ${{ github.base_ref }}"

12
.gitignore vendored
View File

@@ -59,6 +59,18 @@ venv
.clangd
new.info
# Cargo drops lock files in projects to capture resolved dependencies.
# We don't want to record these.
Cargo.lock
# Cargo encourages a .cargo/config.toml file to symlink to a generated
# file. Don't save these.
.cargo/
# Normal west builds will place the Rust target directory under the build directory. However,
# sometimes IDEs and such will litter these target directories as well.
target/
# CI output
compliance.xml
_error.types

View File

@@ -3172,6 +3172,17 @@ Retention:
labels:
- "area: Retention"
Rust:
status: maintained
maintainers:
- d3zd3z
files:
- cmake/modules/rust.cmake
- lib/rust/
- samples/rust/
labels:
- "area: Rust"
Samples:
status: maintained
maintainers:

185
cmake/modules/rust.cmake Normal file
View File

@@ -0,0 +1,185 @@
# 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(get_include_dirs target dirs)
get_target_property(include_dirs ${target} INTERFACE_INCLUDE_DIRECTORIES)
if(include_dirs)
set(${dirs} ${include_dirs} PARENT_SCOPE)
else()
set(${dirs} "" PARENT_SCOPE)
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)
get_include_dirs(zephyr_interface include_dirs)
get_property(include_defines TARGET zephyr_interface PROPERTY INTERFACE_COMPILE_DEFINITIONS)
message(STATUS "Includes: ${include_dirs}")
message(STATUS "Defines: ${include_defines}")
_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")
# The generated C binding wrappers. These are bindgen-generated wrappers for the inline functions
# within Zephyr.
set(WRAPPER_FILE "${CMAKE_CURRENT_BINARY_DIR}/rust/wrapper.c")
# 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}\"
INCLUDE_DIRS = \"${include_dirs}\"
INCLUDE_DEFINES = \"${include_defines}\"
WRAPPER_FILE = \"${WRAPPER_FILE}\"
[patch.crates-io]
${config_paths}
")
# The library is built by invoking Cargo.
add_custom_command(
OUTPUT ${DUMMY_FILE}
BYPRODUCTS ${RUST_LIBRARY} ${WRAPPER_FILE}
COMMAND
${CMAKE_EXECUTABLE}
env BUILD_DIR=${CMAKE_CURRENT_BINARY_DIR}
DOTCONFIG=${DOTCONFIG}
ZEPHYR_DTS=${ZEPHYR_DTS}
INCLUDE_DIRS="${include_dirs}"
INCLUDE_DEFINES="${include_defines}"
WRAPPER_FILE="${WRAPPER_FILE}"
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}
)
# Be sure we don't try building this until all of the generated headers have been generated.
add_custom_target(librustapp ALL
DEPENDS ${DUMMY_FILE}
# The variables, defined at the top level, don't seem to be accessible here.
syscall_list_h_target
driver_validation_h_target
kobj_types_h_target
)
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 ${WRAPPER_FILE})
endfunction()

View File

@@ -112,6 +112,7 @@ list(APPEND zephyr_cmake_modules kconfig)
list(APPEND zephyr_cmake_modules arch_v2)
list(APPEND zephyr_cmake_modules soc_v1)
list(APPEND zephyr_cmake_modules soc_v2)
list(APPEND zephyr_cmake_modules rust)
foreach(component ${SUB_COMPONENTS})
if(NOT ${component} IN_LIST zephyr_cmake_modules)

View File

@@ -8,3 +8,4 @@ Language Support
c/index.rst
cpp/index.rst
rust/index.rst

View File

@@ -0,0 +1,52 @@
.. _rust_bindings:
Bindings to Zephyr for Rust
###########################
Zephyr is written in C, and its primary API is also made available to C. It is written as a
mixture of types, function prototypes, inline functions, and macros.
Although Rust interfaces fairly easily with C at an ABI level, the compiler does not have any
support for generating the code necessary for these bindings. In order to call C code, the types
must be reproduced in Rust, function prototypes written in Rust, and often wrappers made for inline
functions and macros (or this functionality replicated in Rust).
This is a tedious, and error-prone process, and the end result would quickly get out of date with
the development of Zephyr.
The `bindgen`_ project seeks to address much of this issue by automatically generating bindings to C
code for Rust. It makes use of ``libclang`` to parse and interpret a given set of headers, and
generate the Rust code needed to call this code.
.. _bindgen: https://github.com/rust-lang/rust-bindgen
Because the Zephyr headers use numerous conditional compilation macros, the bindings needed will be
very specialized to a given board, and even a given configuration. To do this, the file
:file:`lib/rust/zephyr-sys/build.rs`, which ``cargo`` knows to run at build time, will
generate the bindings for the particular build of Zephyr being used by the current Rust application.
These bindings will be made available in the ``zephyr-sys`` crate, as well as under ``zephyr::raw``.
Using the Bindings
******************
In general, using direct bindings to C functions from Rust is a bit more difficult than calling them
from C. Although all of these calls are considered "unsafe", and must be placed in an ``unsafe``
block, the Rust language has stricter constraints on what is allowed, even by unsafe code. The
intent of supporting the Rust Language on Zephyr project is to allow full use of Zephyr, without
needing to resort to unsafe code, it is understandable that this implementation will be incomplete,
and some applications may require resorting to, what is sometimes referred to as "The Dark Arts".
The `Rustinomicon`_ is a good resource for those wishing to delve into this area.
.. _Rustinomicon: https://doc.rust-lang.org/nomicon/
In addition, the code in :file:`zephyr/lib/rust/zephyr` that provides the higher level abstractions
will primarily be implemented using these auto-generated bindings.
Generation
**********
The generation of the bindings is controlled by the ``build.rs`` program. This attempts to capture
the symbols that are needed for successful bindings, but there may be things missing. Additional
bindings can be included by adding their patterns to the list of patterns in ``build.rs``, and
possibly adding additional ``#include`` directives to :file:`lib/rust/zephyr-sys/wrapper.h`.

View File

@@ -0,0 +1,153 @@
.. _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.
.. toctree::
:maxdepth: 2
bindings.rst
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.

View File

@@ -21,6 +21,8 @@ source "lib/posix/Kconfig"
source "lib/open-amp/Kconfig"
source "lib/rust/Kconfig"
source "lib/smf/Kconfig"
source "lib/acpi/Kconfig"

22
lib/rust/Kconfig Normal file
View File

@@ -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

19
lib/rust/main.c Normal file
View File

@@ -0,0 +1,19 @@
/*
* Copyright (c) 2024 Linaro LTD
* SPDX-License-Identifier: Apache-2.0
*/
/* This main is brought into the Rust application. */
#include <zephyr/kernel.h>
#ifdef CONFIG_RUST
extern void rust_main(void);
int main(void)
{
rust_main();
return 0;
}
#endif

View File

@@ -0,0 +1,17 @@
# Copyright (c) 2024 Linaro LTD
# SPDX-License-Identifier: Apache-2.0
[package]
name = "zephyr-build"
version = "0.1.0"
edition = "2021"
description = """
Build-time support for Rust-based applications that run on Zephyr.
Provides utilities for accessing Kconfig and devicetree information.
"""
# These are needed at build time.
# Whether these need to be vendored is an open question. They are not
# used by the core Zephyr tree, but are needed by zephyr applications.
[dependencies]
regex = "1.10.3"

View File

@@ -0,0 +1,77 @@
// Copyright (c) 2024 Linaro LTD
// SPDX-License-Identifier: Apache-2.0
// Pre-build code for zephyr module.
// This module makes the values from the generated .config available as conditional compilation.
// Note that this only applies to the zephyr module, and the user's application will not be able to
// see these definitions. To make that work, this will need to be moved into a support crate which
// can be invoked by the user's build.rs.
// This builds a program that is run on the compilation host before the code is compiled. It can
// output configuration settings that affect the compilation.
use std::io::{BufRead, BufReader, Write};
use std::env;
use std::fs::File;
use std::path::Path;
use regex::Regex;
/// Export boolean Kconfig entries. This must happen in any crate that wishes to access the
/// configuration settings.
pub fn export_bool_kconfig() {
let dotconfig = env::var("DOTCONFIG").expect("DOTCONFIG must be set by wrapper");
// Ensure the build script is rerun when the dotconfig changes.
println!("cargo:rerun-if-env-changed=DOTCONFIG");
println!("cargo-rerun-if-changed={}", dotconfig);
let config_y = Regex::new(r"^(CONFIG_.*)=y$").unwrap();
let file = File::open(&dotconfig).expect("Unable to open dotconfig");
for line in BufReader::new(file).lines() {
let line = line.expect("reading line from dotconfig");
if let Some(caps) = config_y.captures(&line) {
println!("cargo:rustc-cfg={}", &caps[1]);
}
}
}
/// Capture bool, numeric and string kconfig values in a 'kconfig' module.
/// This is a little simplistic, and will make the entries numeric if they look like numbers.
/// Ideally, this would be built on the types of the values, but that will require more
/// introspection.
pub fn build_kconfig_mod() {
let dotconfig = env::var("DOTCONFIG").expect("DOTCONFIG must be set by wrapper");
let outdir = env::var("OUT_DIR").expect("OUT_DIR must be set");
// The assumption is that hex values are unsigned, and decimal are signed.
let config_hex = Regex::new(r"^(CONFIG_.*)=(0x[0-9a-fA-F]+)$").unwrap();
let config_int = Regex::new(r"^(CONFIG_.*)=(-?[1-9][0-9]*)$").unwrap();
// It is unclear what quoting might be used in the .config.
let config_str = Regex::new(r#"^(CONFIG_.*)=(".*")$"#).unwrap();
let gen_path = Path::new(&outdir).join("kconfig.rs");
let mut f = File::create(&gen_path).unwrap();
writeln!(&mut f, "pub mod kconfig {{").unwrap();
let file = File::open(&dotconfig).expect("Unable to open dotconfig");
for line in BufReader::new(file).lines() {
let line = line.expect("reading line from dotconfig");
if let Some(caps) = config_hex.captures(&line) {
writeln!(&mut f, " #[allow(dead_code)]").unwrap();
writeln!(&mut f, " pub const {}: usize = {};",
&caps[1], &caps[2]).unwrap();
} else if let Some(caps) = config_int.captures(&line) {
writeln!(&mut f, " #[allow(dead_code)]").unwrap();
writeln!(&mut f, " pub const {}: isize = {};",
&caps[1], &caps[2]).unwrap();
} else if let Some(caps) = config_str.captures(&line) {
writeln!(&mut f, " #[allow(dead_code)]").unwrap();
writeln!(&mut f, " pub const {}: &'static str = {};",
&caps[1], &caps[2]).unwrap();
}
}
writeln!(&mut f, "}}").unwrap();
}

View File

@@ -0,0 +1,18 @@
# Copyright (c) 2024 Linaro LTD
# SPDX-License-Identifier: Apache-2.0
[package]
name = "zephyr-sys"
version = "0.1.0"
edition = "2021"
description = """
Zephyr low-level API bindings.
"""
# These are needed at build time.
# Whether these need to be vendored is an open question. They are not
# used by the core Zephyr tree, but are needed by zephyr applications.
[build-dependencies]
anyhow = "1.0"
bindgen = { version = "0.69.4", features = ["experimental"] }
# zephyr-build = { version = "0.1.0", path = "../zephyr-build" }

View File

@@ -0,0 +1,93 @@
// Copyright (c) 2024 Linaro LTD
// SPDX-License-Identifier: Apache-2.0
// Pre-build code for zephyr module.
// This module makes the values from the generated .config available as conditional compilation.
// Note that this only applies to the zephyr module, and the user's application will not be able to
// see these definitions. To make that work, this will need to be moved into a support crate which
// can be invoked by the user's build.rs.
// This builds a program that is run on the compilation host before the code is compiled. It can
// output configuration settings that affect the compilation.
use anyhow::Result;
use bindgen::Builder;
use std::env;
use std::path::{Path, PathBuf};
fn main() -> Result<()> {
// Determine which version of Clang we linked with.
let version = bindgen::clang_version();
println!("Clang version: {:?}", version);
// Pass in the target used to build the native code.
let target = env::var("TARGET")?;
// Rustc uses some complex target tuples for the riscv targets, whereas clang uses other
// options. Fortunately, these variants shouldn't affect the structures generated, so just
// turn this into a generic target.
let target = if target.starts_with("riscv32") {
"riscv32-unknown-none-elf".to_string()
} else {
target
};
// Likewise, do the same with RISCV-64.
let target = if target.starts_with("riscv64") {
"riscv64-unknown-none-elf".to_string()
} else {
target
};
let target_arg = format!("--target={}", target);
// println!("includes: {:?}", env::var("INCLUDE_DIRS"));
// println!("defines: {:?}", env::var("INCLUDE_DEFINES"));
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
let wrapper_path = PathBuf::from(env::var("WRAPPER_FILE").unwrap());
// Bindgen everything.
let bindings = Builder::default()
.header(Path::new("wrapper.h").canonicalize().unwrap().to_str().unwrap())
.use_core()
.clang_arg(&target_arg);
let bindings = define_args(bindings, "-I", "INCLUDE_DIRS");
let bindings = define_args(bindings, "-D", "INCLUDE_DEFINES");
let bindings = bindings
.wrap_static_fns(true)
.wrap_static_fns_path(wrapper_path)
// <inttypes.h> seems to come from somewhere mysterious in Zephyr. For us, just pull in the
// one from the minimal libc.
.clang_arg("-DRUST_BINDGEN")
.clang_arg("-I../../../lib/libc/minimal/include")
.derive_copy(false)
.allowlist_function("k_.*")
.allowlist_function("gpio_.*")
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
.generate()
.expect("Unable to generate bindings");
bindings
.write_to_file(out_path.join("bindings.rs"))
.expect("Couldn't write bindings!");
Ok(())
}
fn define_args(bindings: Builder, prefix: &str, var_name: &str) -> Builder {
let text = env::var(var_name).unwrap();
let mut bindings = bindings;
for entry in text.split(" ") {
if entry.is_empty() {
continue;
}
println!("Entry: {}{}", prefix, entry);
let arg = format!("{}{}", prefix, entry);
bindings = bindings.clang_arg(arg);
}
bindings
}

View File

@@ -0,0 +1,20 @@
// Copyright (c) 2024 Linaro LTD
// SPDX-License-Identifier: Apache-2.0
//! Zephyr application support for Rust
//!
//! This crates provides the core functionality for applications written in Rust that run on top of
//! Zephyr.
#![no_std]
// Allow rust naming convention violations.
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
// Zephyr makes use of zero-sized structs, which Rustc considers invalid. Suppress this warning.
// Note, however, that this suppresses any warnings in the bindings about improper C types.
#![allow(improper_ctypes)]
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 2024 Linaro LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* This file is the seed point for bindgen. This determines every header that will be visited for
* binding generation. It should include any Zephyr headers we need bindings for. The driver in
* build.rs will also select which functions need generation, which will determine the types that
* are output.
*/
#ifdef RUST_BINDGEN
/* errno is coming from somewhere in Zephyr's build. Add the symbol when running bindgen so that it
* is defined here.
*/
extern int errno;
#endif
/* First, make sure we have all of our config settings. */
#include <zephyr/autoconf.h>
/* Gcc defines __SOFT_FP__ when the target uses software floating point, and the CMSIS headers get
* confused without this.
*/
#if defined(CONFIG_CPU_CORTEX_M)
#if !defined(CONFIG_FP_HARDABI) && !defined(FORCE_FP_HARDABI) && !defined(__SOFTFP__)
#define __SOFTFP__
#endif
#endif
#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>

View File

@@ -0,0 +1,19 @@
# Copyright (c) 2024 Linaro LTD
# SPDX-License-Identifier: Apache-2.0
[package]
name = "zephyr"
version = "0.1.0"
edition = "2021"
description = """
Functionality for Rust-based applications that run on Zephyr.
"""
[dependencies]
zephyr-sys = { version = "0.1.0", path = "../zephyr-sys" }
# These are needed at build time.
# Whether these need to be vendored is an open question. They are not
# used by the core Zephyr tree, but are needed by zephyr applications.
[build-dependencies]
zephyr-build = { version = "0.1.0", path = "../zephyr-build" }

17
lib/rust/zephyr/build.rs Normal file
View File

@@ -0,0 +1,17 @@
// Copyright (c) 2024 Linaro LTD
// SPDX-License-Identifier: Apache-2.0
// Pre-build code for zephyr module.
// This module makes the values from the generated .config available as conditional compilation.
// Note that this only applies to the zephyr module, and the user's application will not be able to
// see these definitions. To make that work, this will need to be moved into a support crate which
// can be invoked by the user's build.rs.
// This builds a program that is run on the compilation host before the code is compiled. It can
// output configuration settings that affect the compilation.
fn main() {
zephyr_build::export_bool_kconfig();
zephyr_build::build_kconfig_mod();
}

View File

@@ -0,0 +1,41 @@
// Copyright (c) 2024 Linaro LTD
// SPDX-License-Identifier: Apache-2.0
//! Zephyr application support for Rust
//!
//! This crates provides the core functionality for applications written in Rust that run on top of
//! Zephyr.
#![no_std]
#![allow(unexpected_cfgs)]
// Bring in the generated kconfig module
include!(concat!(env!("OUT_DIR"), "/kconfig.rs"));
// Ensure that Rust is enabled.
#[cfg(not(CONFIG_RUST))]
compile_error!("CONFIG_RUST must be set to build Rust in Zephyr");
// Printk is provided if it is configured into the build.
#[cfg(CONFIG_PRINTK)]
pub mod printk;
use core::panic::PanicInfo;
/// Override rust's panic. This simplistic initial version just hangs in a loop.
#[panic_handler]
fn panic(_ :&PanicInfo) -> ! {
loop {
}
}
/// Re-export of zephyr-sys as `zephyr::raw`.
pub mod raw {
pub use zephyr_sys::*;
}
/// Provide symbols used by macros in a crate-local namespace.
#[doc(hidden)]
pub mod _export {
pub use core::format_args;
}

View File

@@ -0,0 +1,113 @@
// Copyright (c) 2024 Linaro LTD
// SPDX-License-Identifier: Apache-2.0
//! Printk implementation for Rust.
//!
//! This uses the `k_str_out` syscall, which is part of printk to output to the console.
use core::fmt::{
Arguments,
Result,
Write,
write,
};
#[macro_export]
macro_rules! printk {
($($arg:tt)*) => {{
$crate::printk::printk(format_args!($($arg)*));
}};
}
#[macro_export]
macro_rules! printkln {
($($arg:tt)*) => {{
$crate::printk::printkln(format_args!($($arg)*));
}};
}
// This could readily be optimized for the configuration where we don't have userspace, as well as
// when we do, and are not running in userspace. This initial implementation will always use a
// string buffer, as it doesn't depend on static symbols in print.c.
//
// A consequence is that the CONFIG_PRINTK_SYNC is enabled, the synchonization will only occur at
// the granularity of these buffers rather than at the print message level.
/// The buffer size for syscall. This is a tradeoff between efficiency (large buffers need fewer
/// syscalls) and needing more stack space.
const BUF_SIZE: usize = 32;
struct Context {
// How many characters are used in the buffer.
count: usize,
// Bytes written.
buf: [u8; BUF_SIZE],
}
fn utf8_byte_length(byte: u8) -> usize {
if byte & 0b1000_0000 == 0 {
// Single byte (0xxxxxxx)
1
} else if byte & 0b1110_0000 == 0b1100_0000 {
// Two-byte sequence (110xxxxx)
2
} else if byte & 0b1111_0000 == 0b1110_0000 {
// Three-byte sequence (1110xxxx)
3
} else if byte & 0b1111_1000 == 0b1111_0000 {
// Four-byte sequence (11110xxx)
4
} else {
// Continuation byte or invalid (10xxxxxx)
1
}
}
impl Context {
fn add_byte(&mut self, b: u8) {
// Ensure we have room for an entire UTF-8 sequence.
if self.count + utf8_byte_length(b) > self.buf.len() {
self.flush();
}
self.buf[self.count] = b;
self.count += 1;
}
fn flush(&mut self) {
if self.count > 0 {
unsafe {
zephyr_sys::k_str_out(self.buf.as_mut_ptr() as *mut i8, self.count);
}
self.count = 0;
}
}
}
impl Write for Context {
fn write_str(&mut self, s: &str) -> Result {
for b in s.bytes() {
self.add_byte(b);
}
Ok(())
}
}
pub fn printk(args: Arguments<'_>) {
let mut context = Context {
count: 0,
buf: [0; BUF_SIZE],
};
write(&mut context, args).unwrap();
context.flush();
}
pub fn printkln(args: Arguments<'_>) {
let mut context = Context {
count: 0,
buf: [0; BUF_SIZE],
};
write(&mut context, args).unwrap();
context.add_byte(b'\n');
context.flush();
}

View File

@@ -24,6 +24,7 @@ Samples and Demos
application_development/*
shields/*
cpp/*
rust/*
posix/*
kernel/*
tfm_integration/tfm_integration.rst

View File

@@ -0,0 +1,8 @@
# SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(hello_rust_world)
rust_cargo_application()

View File

@@ -0,0 +1,16 @@
# Copyright (c) 2024 Linaro LTD
# SPDX-License-Identifier: Apache-2.0
[package]
# This must be rustapp for now.
name = "rustapp"
version = "0.1.0"
edition = "2021"
description = "A sample hello world application in Rust"
license = "Apache-2.0 or MIT"
[lib]
crate-type = ["staticlib"]
[dependencies]
zephyr = "0.1.0"

View File

@@ -0,0 +1,35 @@
.. _hello_rust_world:
Hello Rust World
################
Overview
********
A simple :ref:`Rust <language_rust>` sample that can be used with many
supported boards and prints a Hello World message to the console.
Building and Running
********************
Once the proper rust toolchain has been installed. This configuration
can be built and executed on QEMU as follows:
.. zephyr-app-commands::
:zephyr-app: samples/rust/hello_world
:host-os: unix
:board: qemu_riscv32
:goals: run
:compact:
To build for another board, change "qemu_riscv32" above to that
board's name.
Sample Output
=============
.. code-block: console
Hello world from Rust on qemu_riscv32
Exit QEMU by pressing :kbd:`CTRL+C`

View File

@@ -0,0 +1,4 @@
# Copyright (c) 2024 Linaro LTD
# SPDX-License-Identifier: Apache-2.0
CONFIG_RUST=y

View File

@@ -0,0 +1,14 @@
sample:
description: Hello world, but in Rust
name: hello rust world
common:
harness: console
harness_config:
type: one_line
regex:
- "Hello world from Rust on (.*)"
tags: rust
filter: CONFIG_RUST_SUPPORTED
tests:
sample.rust.helloworld:
tags: introduction

View File

@@ -0,0 +1,16 @@
// Copyright (c) 2024 Linaro LTD
// SPDX-License-Identifier: Apache-2.0
#![no_std]
use zephyr::printkln;
// Reference the Zephyr crate so that the panic handler gets used. This is only needed if no
// symbols from the crate are directly used.
extern crate zephyr;
#[no_mangle]
extern "C" fn rust_main() {
printkln!("Hello world from Rust on {}",
zephyr::kconfig::CONFIG_BOARD);
}

10
samples/rust/rust.rst Normal file
View File

@@ -0,0 +1,10 @@
.. _rust-samples:
Rust Samples
############
.. toctree::
:maxdepth: 1
:glob:
**/*

View File

@@ -85,6 +85,11 @@ posix:
files:
- lib/posix/
rust:
files:
- lib/rust/
- cmake/modules/rust.cmake
# cbprintf:
# files:
# - lib/os/cbprintf*