From a53e8f84b6fcc2eb1aeecbc1f6e80f958369cd16 Mon Sep 17 00:00:00 2001 From: Matthew Richey Date: Tue, 3 Dec 2024 11:55:58 -0600 Subject: [PATCH 1/2] cmake: support armv8r target for Cortex-R52 This commit adds Rust build support for the Cortex-R52 CPU type. Signed-off-by: Matthew Richey --- CMakeLists.txt | 10 ++++++++++ Kconfig | 1 + 2 files changed, 11 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index bb0529f8..b90e72f0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,6 +49,15 @@ function(_rust_map_target) else() message(FATAL_ERROR "Rust: Unsupported riscv ISA") endif() + elseif(CONFIG_CPU_CORTEX_R52) + set(RUST_TARGET "armv8r-none-eabihf" PARENT_SCOPE) + + # build core (and maybe also alloc) from source for tier 3 target + if(CONFIG_RUST_ALLOC) + set(CARGO_EXTRA_FLAGS -Z build-std=core,alloc PARENT_SCOPE) + else() + set(CARGO_EXTRA_FLAGS -Z build-std=core PARENT_SCOPE) + endif() else() message(FATAL_ERROR "Rust: Add support for other target") endif() @@ -182,6 +191,7 @@ ${config_paths} ${command_paths} --target ${RUST_TARGET} --target-dir ${CARGO_TARGET_DIR} + ${CARGO_EXTRA_FLAGS} COMMENT "Building Rust application" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) diff --git a/Kconfig b/Kconfig index 4952d773..f4285ec3 100644 --- a/Kconfig +++ b/Kconfig @@ -8,6 +8,7 @@ menu "Rust Language Support" config RUST_SUPPORTED bool default y if ((CPU_CORTEX_M || \ + CPU_CORTEX_R52 || \ (RISCV && !RISCV_ISA_RV32E && !RISCV_ISA_RV128I)) && \ !TIMER_READS_ITS_FREQUENCY_AT_RUNTIME) help From 9b3967398147da426ab133eb78c30b054aee4518 Mon Sep 17 00:00:00 2001 From: Matthew Richey Date: Mon, 16 Dec 2024 13:03:09 -0600 Subject: [PATCH 2/2] cmake: support building Rust libraries This commit adds a new cmake function rust_cargo_library() to build a Rust staticlib library with cbindgen-generated header file, which can be linked into a C application. Signed-off-by: Matthew Richey --- CMakeLists.txt | 129 ++++++++++++++++++++++++++++++++++++++++++++++--- Kconfig | 18 +++++++ 2 files changed, 141 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b90e72f0..accb9d63 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -89,12 +89,13 @@ function(rust_cargo_application) # TODO: Make sure RUSTFLAGS is not set. - if(CONFIG_DEBUG) - set(RUST_BUILD_TYPE "debug") - set(rust_build_type_arg "") + # choose debug/release build based on Kconfig choice + if(CONFIG_RUST_CARGO_PROFILE_RELEASE) + message(STATUS "Cargo build profile: release") + set(RUST_BUILD_TYPE release) else() - set(RUST_BUILD_TYPE "release") - set(rust_build_type_arg "--release") + message(STATUS "Cargo build profile: dev") + set(RUST_BUILD_TYPE debug) endif() set(BUILD_LIB_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${RUST_TARGET}/${RUST_BUILD_TYPE}") @@ -178,7 +179,7 @@ ${config_paths} DT_AUGMENTS="${DT_AUGMENTS}" BINARY_DIR_INCLUDE_GENERATED="${BINARY_DIR_INCLUDE_GENERATED}" cargo build - ${rust_build_type_arg} + --profile $,release,dev> # Override the features according to the shield given. For a general case, # this will need to come from a variable or argument. @@ -194,6 +195,7 @@ ${config_paths} ${CARGO_EXTRA_FLAGS} COMMENT "Building Rust application" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + USES_TERMINAL ) # Be sure we don't try building this until all of the generated headers have been generated. @@ -261,3 +263,118 @@ ${config_paths} # Add an empty file so that this will build. The main will come from the rust library. target_sources(app PRIVATE $CACHE{RUST_MODULE_DIR}/main.c ${WRAPPER_FILE}) endfunction() + +# Function to build a Rust library using cargo, to be integrated into a C-based +# Zephyr application. +# +# In contrast to the rust_cargo_application function, which builds an entire +# Zephyr application from primarily Rust source files, this function is designed +# to build a standalone Rust crate into a library that can be integrated into a +# Zephyr application whose source code base is primarily written in C. +# +# A library built with this function will typically provide a C API through a +# Foreign Function Interface (FFI) whose C header files will be automatically +# generated from the Rust source code by the cbindgen tool, therefore use of +# this function requires the cbindgen tool to be installed on the build host. +# +# The caller must specify the following arguments: +# +# LIBRARY_NAME - the name of the library +# CRATE_PATH - path to the root of the Rust crate to build +# +# The caller may optionally specify the following argument: +# +# MEMORY_PARTITION +# +# which, if specified, will place any static global symbols built from the Rust +# sources into the specified memory partition, which can allow the symbols to be +# used from user mode threads. +# +# The function will add the specified library name into the build environment as +# a symbol that can be linked into the target Zephyr application using e.g. +# target_link_libraries. +# +# Usage: +# rust_cargo_library(LIBRARY_NAME +# CRATE_PATH +# |MEMORY_PARTITION | +# ) +# +function(rust_cargo_library) + # parse function arguments + set(flags) + set(args LIBRARY_NAME CRATE_PATH MEMORY_PARTITION) + set(listArgs) + cmake_parse_arguments(arg "${flags}" "${args}" "${listArgs}" ${ARGN}) + + # verify required arguments + if (NOT arg_LIBRARY_NAME) + message(FATAL_ERROR "[rust_cargo_library]: LIBRARY_NAME is a required argument") + endif() + if (NOT arg_CRATE_PATH) + message(FATAL_ERROR "[rust_cargo_library]: CRATE_PATH is a required argument") + endif() + + # locate cbindgen executable + find_program(CBINDGEN_EXE cbindgen REQUIRED) + + _rust_map_target() + message(STATUS "Building Rust library ${arg_LIBRARY_NAME} for llvm target ${RUST_TARGET}") + + # choose debug/release build based on Kconfig choice + if(CONFIG_RUST_CARGO_PROFILE_RELEASE) + message(STATUS "Cargo build profile: release") + set(RUST_BUILD_TYPE release) + else() + message(STATUS "Cargo build profile: dev") + set(RUST_BUILD_TYPE debug) + endif() + set(BUILD_LIB_DIR ${CMAKE_CURRENT_SOURCE_DIR}/${RUST_TARGET}/${RUST_BUILD_TYPE}) + + # library filename is based on arg_LIBRARY_NAME + set(CARGO_TARGET_DIR ${CMAKE_CURRENT_BINARY_DIR}/rust/target) + set(RUST_LIBRARY ${CARGO_TARGET_DIR}/${RUST_TARGET}/${RUST_BUILD_TYPE}/lib${arg_LIBRARY_NAME}.a) + + # cbindgen header filename is based on arg_LIBRARY_NAME with _ replaced by - + string(REPLACE "_" "-" CBINDGEN_FILENAME "${arg_LIBRARY_NAME}-cbindgen.h") + set(CBINDGEN_HEADER ${CMAKE_CURRENT_BINARY_DIR}/${CBINDGEN_FILENAME}) + + # The library is built by invoking Cargo. + add_custom_target( + ${arg_LIBRARY_NAME}_builder + BYPRODUCTS ${RUST_LIBRARY} ${CBINDGEN_HEADER} + + # build the library + COMMAND + cargo build + --profile $,release,dev> + --target ${RUST_TARGET} + --target-dir ${CARGO_TARGET_DIR} + ${CARGO_EXTRA_FLAGS} + + # autogenerate the C header file using cbindgen + COMMAND + ${CMAKE_COMMAND} + -E env ${CBINDGEN_EXE} + --config cbindgen.toml + --output ${CBINDGEN_HEADER} + --lang c + + WORKING_DIRECTORY ${arg_CRATE_PATH} + USES_TERMINAL + ) + + # Create a library target and add the location of the generated header file + # to its include path. + add_library(${arg_LIBRARY_NAME} STATIC IMPORTED GLOBAL) + add_dependencies(${arg_LIBRARY_NAME} ${arg_LIBRARY_NAME}_builder) + set_target_properties(${arg_LIBRARY_NAME} PROPERTIES IMPORTED_LOCATION ${RUST_LIBRARY}) + set_target_properties(${arg_LIBRARY_NAME} PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_BINARY_DIR}) + + # Place any statics from the rust library into the specified memory partition. + if (arg_MEMORY_PARTITION) + zephyr_append_cmake_library(${arg_LIBRARY_NAME}) + set(ZEPHYR_CURRENT_LIBRARY ${arg_LIBRARY_NAME}) + zephyr_library_app_memory(${arg_MEMORY_PARTITION}) + endif() +endfunction() diff --git a/Kconfig b/Kconfig index f4285ec3..a17db579 100644 --- a/Kconfig +++ b/Kconfig @@ -31,6 +31,24 @@ config RUST_ALLOC Zephyr allocator (malloc/free). This this enabled, Rust applications can use the `alloc` crate. +choice RUST_CARGO_PROFILE + prompt "Cargo profile" + default RUST_CARGO_PROFILE_DEV + help + Select the profile to use when invoking cargo. + +config RUST_CARGO_PROFILE_DEV + bool "Development profile" + help + Cargo profile suitable for development and debugging builds. + +config RUST_CARGO_PROFILE_RELEASE + bool "Release profile" + help + Cargo profile suitable for release builds. + +endchoice # RUST_BUILD_TYPE + endif # RUST endmenu