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

Experiment: Devicetree and device driver access in Rust #76199

Closed
wants to merge 35 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
a0611a1
rust: Initial config option
d3zd3z Jul 15, 2024
79eb8a2
rust: Simple main wrapper
d3zd3z Jul 15, 2024
6646068
rust: Basic `zephyr` crate
d3zd3z Jul 15, 2024
62af97a
rust: Add cmake support for building rust apps
d3zd3z Jul 15, 2024
775a3a0
rust: Simple rust hello_world application
d3zd3z Jul 15, 2024
564d96d
MAINTAINERS: Add Rust to maintainers file
d3zd3z Jul 15, 2024
191eca3
rust: Move Kconfig bool values into crate
d3zd3z Jul 15, 2024
98f0291
rust: Make Kconfig values available to Rust code
d3zd3z Jul 15, 2024
62770bf
samples: rust: Access CONFIG_BOARD
d3zd3z Jul 15, 2024
6f55e18
doc: languages: Add Rust documentation
d3zd3z Jul 16, 2024
cf88e6f
samples: rust: Rename hello
d3zd3z Jul 16, 2024
6052ca4
doc: Use proper quote block for shell
d3zd3z Jul 16, 2024
c95dc43
rust: Support negative Kconfig int values
d3zd3z Jul 17, 2024
db90a84
rust: Mark RUST support as experimental
d3zd3z Jul 17, 2024
285c9d5
cmake: rust: Use proper FPU config
d3zd3z Jul 18, 2024
a8d1745
doc: rust: Fix code block
d3zd3z Jul 18, 2024
2f39272
doc: rust: Use real config settings
d3zd3z Jul 18, 2024
f883380
cmake: rust: Fix Cortex-M4 non-fp target
d3zd3z Jul 18, 2024
b72fdeb
rust: Fix prototype for rust_main
d3zd3z Jul 18, 2024
157448e
remove board specific options
mjaun Jul 16, 2024
98d0bf7
target mapping for cortex m7
mjaun Jul 16, 2024
680250e
first trial of providing dts information to rust
mjaun Jul 17, 2024
e3abd1c
add zephyr-sys library with bindgen
mjaun Jul 18, 2024
05652a7
control gpio from rust
mjaun Jul 18, 2024
96f4e06
call sleep directly
mjaun Jul 18, 2024
57e361e
cleaner implementation for allocator and panic handler
mjaun Jul 18, 2024
1a12f04
better print support
mjaun Jul 18, 2024
9059699
more generic way of determining clang args
mjaun Jul 19, 2024
f041979
move gpio driver
mjaun Jul 19, 2024
fe62b92
start implementing gpio driver
mjaun Jul 19, 2024
f80d219
improved errno handling
mjaun Jul 19, 2024
8f14bb7
support more types in rust dts
mjaun Jul 19, 2024
9eb9540
include generated device tree
mjaun Jul 19, 2024
74afe70
make device tree accessible in application
mjaun Jul 20, 2024
dea5646
cleanups
mjaun Jul 23, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions MAINTAINERS.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3039,6 +3039,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:
Expand Down
221 changes: 221 additions & 0 deletions cmake/modules/rust.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
# SPDX-License-Identifier: Apache-2.0

# Rust make support

# Zephyr targets are defined through Kconfig. We need to map these to
# an appropriate llbm 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()
else()
message(FATAL_ERROR "Rust: Add support for other target")
endif()
endfunction()

function(_generate_clang_args BINDGEN_CLANG_ARGS)
# Get compiler arguments from Zephyr
zephyr_get_system_include_directories_for_lang(C system_includes)
zephyr_get_include_directories_for_lang(C includes)
zephyr_get_compile_definitions_for_lang(C definitions)

# -imacros are needed but are part of zephyr_get_compile_options_for_lang() where many
# things are not supported by Clang. Maybe there is a better way than hard coding.
set(options "-imacros${AUTOCONF_H}")

if(CONFIG_ENFORCE_ZEPHYR_STDINT)
list(APPEND options "-imacros${ZEPHYR_BASE}/include/zephyr/toolchain/zephyr_stdint.h")
endif()

# Determine standard include directories of compiler.
# I hope someone knows a nicer way of doing this.
file(TOUCH ${CMAKE_CURRENT_BINARY_DIR}/empty.c)

execute_process(
COMMAND ${CMAKE_C_COMPILER} -E -Wp,-v ${CMAKE_CURRENT_BINARY_DIR}/empty.c
OUTPUT_QUIET
ERROR_VARIABLE output
COMMAND_ERROR_IS_FATAL ANY
)

set(standard_includes "-nostdinc")
if(output MATCHES "#include <\.\.\.> search starts here:\n(.*)\nEnd of search list\.")
string(REGEX MATCHALL "[^ \n]+" paths "${CMAKE_MATCH_1}")
foreach(path ${paths})
get_filename_component(path ${path} ABSOLUTE)
list(APPEND standard_includes "-isystem${path}")
endforeach()
else()
message(WARNING "Unable to determine compiler standard include directories.")
endif()

# Not sure if a proper target should be provided as well to generate the correct bindings.

# Generate file containing arguments for Clang. Note that the file is generated after the
# CMake configure stage as the variables contain generator expressions which cannot be
# evaluated right now.
file(
GENERATE
OUTPUT ${BINDGEN_CLANG_ARGS}
CONTENT "${standard_includes};${system_includes};${includes};${definitions};${options}"
)
endfunction()

function(_generate_rust_dts RUST_DTS)
execute_process(
COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/dts/gen_dts_rust.py
--edt-pickle ${CMAKE_BINARY_DIR}/zephyr/edt.pickle
--rust-out ${RUST_DTS}
COMMAND_ERROR_IS_FATAL ANY
)

set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${GEN_DTS_RUST_SCRIPT})
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 zephyr-sys)

_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")

set(RUST_DTS "${CMAKE_CURRENT_BINARY_DIR}/rust/dts.rs")
set(BINDGEN_CLANG_ARGS "${CMAKE_CURRENT_BINARY_DIR}/rust/clang_args.txt")
set(BINDGEN_WRAP_STATIC_FNS "${CMAKE_CURRENT_BINARY_DIR}/rust/wrap_static_fns.c")

file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/rust")

_generate_clang_args(${BINDGEN_CLANG_ARGS})
_generate_rust_dts(${RUST_DTS})

# 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_BASE = \"${ZEPHYR_BASE}\"
RUST_DTS = \"${RUST_DTS}\"
BINDGEN_CLANG_ARGS = \"${BINDGEN_CLANG_ARGS}\"
BINDGEN_WRAP_STATIC_FNS = \"${BINDGEN_WRAP_STATIC_FNS}\"

[patch.crates-io]
${config_paths}
")

# The library is built by invoking Cargo.
add_custom_command(
OUTPUT ${DUMMY_FILE}
BYPRODUCTS ${RUST_LIBRARY} ${BINDGEN_WRAP_STATIC_FNS}
COMMAND
${CMAKE_EXECUTABLE}
env BUILD_DIR=${CMAKE_CURRENT_BINARY_DIR}
DOTCONFIG=${DOTCONFIG}
ZEPHYR_BASE=${ZEPHYR_BASE}
RUST_DTS=${RUST_DTS}
BINDGEN_CLANG_ARGS=${BINDGEN_CLANG_ARGS}
BINDGEN_WRAP_STATIC_FNS="${BINDGEN_WRAP_STATIC_FNS}"
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)

target_sources(app PRIVATE
${ZEPHYR_BASE}/lib/rust/main.c
${ZEPHYR_BASE}/lib/rust/panic.c
${BINDGEN_WRAP_STATIC_FNS}
)
endfunction()
1 change: 1 addition & 0 deletions cmake/modules/zephyr_default.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions doc/develop/languages/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ Language Support

c/index.rst
cpp/index.rst
rust/index.rst
Loading
Loading