Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
15 changes: 15 additions & 0 deletions .ci/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,21 @@
platforms=["linux"],
build_dir="build/posix-freertos",
),
"posix-rust": BuildOpTpl(
config_cmd="cmake --preset posix-rust",
build_cmd="cmake --build --preset posix-rust",
configs=["Debug", "Release"],
platforms=["linux"],
build_dir="build/posix-rust",
),
"s32k148-rust-gcc": BuildOpTpl(
config_cmd="cmake --preset s32k148-rust-gcc",
build_cmd="cmake --build --preset s32k148-rust-gcc",
configs=["Debug", "Release", "RelWithDebInfo"],
platforms=["arm"],
cxxids=["gcc"],
build_dir="build/s32k148-rust-gcc",
),
"s32k148-freertos-gcc": BuildOpTpl(
config_cmd="cmake --preset s32k148-freertos-gcc",
build_cmd="cmake --build --preset s32k148-freertos-gcc",
Expand Down
11 changes: 10 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
strategy:
# max-parallel: 1
matrix:
preset: [ "tests-posix-debug", "tests-posix-release", "tests-s32k1xx-debug", "tests-s32k1xx-release", "posix-freertos", "posix-threadx", "posix-freertos-with-tracing", "s32k148-freertos-gcc", "s32k148-threadx-gcc", "s32k148-freertos-clang", "s32k148-threadx-clang"]
preset: [ "tests-posix-debug", "tests-posix-release", "tests-s32k1xx-debug", "tests-s32k1xx-release", "posix-freertos", "posix-threadx", "posix-freertos-with-tracing", "posix-rust", "s32k148-freertos-gcc", "s32k148-threadx-gcc", "s32k148-freertos-clang", "s32k148-threadx-clang", "s32k148-rust-gcc" ]
platform: [ "arm", "linux" ]
config: [ "Debug", "Release", "RelWithDebInfo" ]
cxxid: ["gcc", "clang"]
Expand Down Expand Up @@ -53,14 +53,23 @@ jobs:
- preset: "posix-freertos-with-tracing"
config: "RelWithDebInfo"

- preset: "posix-rust"
platform: "arm"
- preset: "posix-rust"
config: "RelWithDebInfo"

- preset: "s32k148-freertos-gcc"
platform: "linux"
- preset: "s32k148-threadx-gcc"
platform: "linux"
- preset: "s32k148-rust-gcc"
platform: "linux"
- preset: "s32k148-freertos-gcc"
cxxid: "clang"
- preset: "s32k148-threadx-gcc"
cxxid: "clang"
- preset: "s32k148-rust-gcc"
cxxid: "clang"

- preset: "s32k148-freertos-clang"
platform: "linux"
Expand Down
22 changes: 22 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")

option(BUILD_TRACING "Build CTF tracing" OFF)

option(BUILD_RUST "Build Rust components" OFF)

add_compile_options(
#[[
Supressing stringop-overflow and maybe-uninitialized, as they are often
Expand All @@ -82,6 +84,26 @@ add_compile_options(
"$<$<COMPILE_LANG_AND_ID:CXX,GNU>:-Wno-error=stringop-overflow;-Wno-error=maybe-uninitialized>"
)

# Rust support Note: Only one static Rust library can be linked in the final
# binary, otherwise the linker will complain about duplicate symbol definitions
# from the Rust core crate.
if (BUILD_RUST)
# Set Rust target for cross-compilation (ARM Cortex-M4F for S32K148)
if (BUILD_TARGET_PLATFORM STREQUAL "S32K148EVB")
set(Rust_CARGO_TARGET
"thumbv7em-none-eabihf"
CACHE STRING "Rust target triple")
endif ()

add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/libs/3rdparty/corrosion)

corrosion_import_crate(
MANIFEST_PATH
${CMAKE_CURRENT_SOURCE_DIR}/executables/referenceApp/rustHelloWorld/Cargo.toml
)

endif ()

if (BUILD_EXECUTABLE STREQUAL "unitTest")
include(GoogleTest)
include(CTest)
Expand Down
45 changes: 45 additions & 0 deletions CMakePresets.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,39 @@
"BUILD_TARGET_RTOS": "THREADX"
}
},
{
"name": "posix-rust",
"displayName": "POSIX with Rust configuration and FreeRTOS",
"description": "Configure for POSIX-compliant environment with Rust support enabled, gcc and FreeRTOS",
"inherits": "_config-base",
"binaryDir": "${sourceDir}/build/${presetName}",
"cacheVariables": {
"BUILD_EXECUTABLE": "referenceApp",
"BUILD_RUST": "ON",
"BUILD_TARGET_PLATFORM": "POSIX",
"BUILD_TARGET_RTOS": "FREERTOS"
}
},
{
"name": "s32k148-rust-gcc",
"generator": "Ninja Multi-Config",
"displayName": "S32K148 with Rust configuration and FreeRTOS",
"description": "Configure for S32K148 platform with Rust support enabled, gcc and FreeRTOS",
"inherits": "_config-base",
"toolchainFile": "${sourceDir}/cmake/toolchains/ArmNoneEabi-gcc.cmake",
"binaryDir": "${sourceDir}/build/${presetName}",
"cacheVariables": {
"BUILD_EXECUTABLE": "referenceApp",
"BUILD_RUST": "ON",
"BUILD_TARGET_PLATFORM": "S32K148EVB",
"BUILD_TARGET_RTOS": "FREERTOS",
"CMAKE_ASM_FLAGS_RELWITHDEBINFO": "-g3",
"CMAKE_CONFIGURATION_TYPES": "RelWithDebInfo;Debug;Release",
"CMAKE_C_FLAGS_RELWITHDEBINFO": "-g3 -O2 -DNDEBUG",
"CMAKE_CXX_FLAGS_RELWITHDEBINFO": "-g3 -O2 -DNDEBUG",
"CMAKE_DEFAULT_BUILD_TYPE": "RelWithDebInfo"
}
},
{
"name": "s32k148-freertos-gcc",
"generator": "Ninja Multi-Config",
Expand Down Expand Up @@ -207,6 +240,18 @@
"description": "Build reference application for POSIX-compliant environment (Release by default; for Debug use --config Debug)",
"configurePreset": "posix-threadx"
},
{
"name": "posix-rust",
"displayName": "build POSIX with Rust build and FreeRTOS",
"description": "Build reference application for POSIX-compliant environment with Rust support, gcc and FreeRTOS (Release by default; for Debug use --config Debug)",
"configurePreset": "posix-rust"
},
{
"name": "s32k148-rust-gcc",
"displayName": "S32K148 with Rust build and FreeRTOS",
"description": "Build reference application for S32K148 platform with Rust support, gcc and FreeRTOS",
"configurePreset": "s32k148-rust-gcc"
},
{
"name": "s32k148-freertos-gcc",
"displayName": "S32K148 FreeRTOS build (GCC)",
Expand Down
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 30 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[workspace]
resolver = "3"

members = [
"executables/referenceApp/rustHelloWorld",
]

[workspace.package]
version = "0.1.0"
documentation = "https://eclipse-openbsw.github.io/openbsw/"

# Workspace dependencies - add new Rust crates here as they are developed
[workspace.dependencies]

# Similar to C++ we always build optimized (matching C++ -O2)
[profile.dev]
panic = "abort"
lto = true
opt-level = 2
incremental = false
codegen-units = 1
debug = true

[profile.release]
panic = "abort"
lto = true
opt-level = 2
incremental = false
codegen-units = 1
debug = true
1 change: 1 addition & 0 deletions NOTICE.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ We recommend to read their licenses, as their terms may differ from the terms de

| Project | Version | License | Path |
|---------------------------|---------|-----------|----------------------------------------------------------------------|
| Corrosion | 0.6 | MIT | ``libs/3rdparty/corrosion/LICENSE`` |
| ETL | 20.45.0 | MIT | ``libs/3rdparty/etl/LICENSE`` |
| LwIP | 2.2.1 | BSD-3 | ``libs/3rdparty/lwip/COPYING`` |
| googletest | 1.12.1 | BSD-3 | ``libs/3rdparty/googletest/LICENSE`` |
Expand Down
1 change: 1 addition & 0 deletions doc/dev/guidelines/3rdparty.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Third party libraries under the project root's ``libs/3rdparty`` are
recommended to be maintained by `RIM <https://github.com/esrlabs/esr-rim>`,
if possible:

* ``corrosion``
* ``etl``
* ``googletest``
* ``lwip``
Expand Down
21 changes: 21 additions & 0 deletions doc/dev/learning/setup/setup_posix_build.rst
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,24 @@ You should be able to run and see output like this in your shell terminal...
Press ``CTRL-C`` should exit the running application.

Now that you can build the code and run it, you can explore the code, make changes and learn how it works.

Optional: Rust Support
----------------------

To build OpenBSW with Rust components for the POSIX platform, you need:

1. The build tools set up as described above (gcc, cmake, make)
2. The Rust compiler

Install Rust 1.90.0 to be compatible with the CI builds:

.. code-block:: bash

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain 1.90.0

Then build using the Rust preset:

.. code-block:: bash

cmake --preset posix-rust
cmake --build --preset posix-rust --parallel
22 changes: 22 additions & 0 deletions doc/dev/learning/setup/setup_s32k148_ubuntu_build.rst
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,26 @@ The build files should be written to a new subdirectory named ``build/s32k148-gc
and the built executable should be found at ``build/s32k148-clang/executables/referenceApp/application/RelWithDebInfo/app.referenceApp.elf``
which you can flash on the S32K148 development board.

Optional: Rust Support
----------------------

To build OpenBSW with Rust components for the S32K148 platform, you need:

1. The GCC toolchain set up as described in `Using the GCC toolchain`_ above (including CC and CXX environment variables)
2. The Rust compiler with the ARM cross-compilation target

Install Rust 1.90.0 to be compatible with the CI builds and add the ARM target:

.. code-block:: bash

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain 1.90.0
rustup target add thumbv7em-none-eabihf

Then, with the GCC toolchain environment variables set, build using the Rust preset:

.. code-block:: bash

cmake --preset s32k148-rust-gcc
cmake --build --preset s32k148-rust-gcc

Next :doc:`setup_s32k148_ubuntu_nxpide`
8 changes: 8 additions & 0 deletions docker/development/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@ RUN tar -xf treefmt.tar.gz \

RUN gem install esr-rim


ENV RUSTUP_HOME=/opt/rustup
ENV CARGO_HOME=/opt/cargo
ENV PATH=/opt/cargo/bin:${PATH}
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain 1.90.0 --profile minimal \
&& rustup target add thumbv7em-none-eabihf \
&& cargo install cbindgen --version 0.27.0 --locked

RUN python3 -m venv /opt/venv
ENV PATH=/opt/venv/bin:${PATH}
RUN --mount=type=bind,source=files/requirements.lock,target=/tmp/requirements.lock pip3 install -r /tmp/requirements.lock
Expand Down
10 changes: 10 additions & 0 deletions executables/referenceApp/application/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,13 @@ endif ()
if (PLATFORM_SUPPORT_ROM_CHECK)
target_link_libraries(app.referenceApp PRIVATE safeMemory)
endif ()

if (BUILD_RUST)
target_compile_definitions(app.referenceApp PRIVATE BUILD_RUST)
# Link against Rust static library(should be only one static library)
target_link_libraries(app.referenceApp PRIVATE rust_hello_world)
# Add include directory for Rust C/C++ headers
target_include_directories(
app.referenceApp
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../rustHelloWorld/include)
endif ()
10 changes: 10 additions & 0 deletions executables/referenceApp/application/src/app/app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@
#include <lifecycle/LifecycleLogger.h>
#include <lifecycle/LifecycleManager.h>

#include <cstdio>

#ifdef BUILD_RUST
#include <rust_hello_world.h>
#endif

alignas(32)::async::internal::Stack<safety_task_stackSize> safetyStack;

#ifdef PLATFORM_SUPPORT_CAN
Expand Down Expand Up @@ -214,6 +220,10 @@ void run()
{
staticInit();
etl::print("hello\r\n");
#ifdef BUILD_RUST
etl::print("Hello Rust!\r\n");
etl::print("Rust add(3, 4) = {}\r\n", static_cast<unsigned int>(rust_add(3U, 4U)));
#endif
idleHandler.init();
AsyncAdapter::run(AsyncAdapter::StartAppFunctionType::create<&startApp>());
}
Expand Down
11 changes: 11 additions & 0 deletions executables/referenceApp/rustHelloWorld/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "rust_hello_world"
version.workspace = true
documentation.workspace = true
edition = "2024"

[lib]
crate-type = ["staticlib"]

[dependencies]

24 changes: 24 additions & 0 deletions executables/referenceApp/rustHelloWorld/include/rust_hello_world.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright 2026 Accenture.

#ifndef RUST_HELLO_WORLD_H
#define RUST_HELLO_WORLD_H

#include <stdint.h>

#ifdef __cplusplus
extern "C"
{
#endif

/// Adds two numbers and returns the result.
///
/// \param a First number to add
/// \param b Second number to add
/// \return The sum of a and b
uint32_t rust_add(uint32_t a, uint32_t b);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example shows a C-only interface use case.

For interfacing between C++ and Rust, would it be possible to give a more complex example, e.g. mapping between C++ class and Rust crate interface? Maybe put it on the linked agenda/Rust discussion, but we would need it at some point to support reasonably complex interfaces.

Copy link
Contributor Author

@M-Hassanin M-Hassanin Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point! This initial PR intentionally uses a minimal C-style interface (extern "C") to establish the basic Rust build infrastructure with Corrosion. The upcoming features in the agenda will include more interfaces between C++ and Rust.


#ifdef __cplusplus
}
#endif

#endif // RUST_HELLO_WORLD_H
47 changes: 47 additions & 0 deletions executables/referenceApp/rustHelloWorld/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright 2026 Accenture.

//! A simple "Hello World" Rust library demonstrating Rust integration with OpenBSW.
//!
//! This crate provides a minimal example of how to expose Rust functions to C++ code
//! in the OpenBSW build system.
//!
//! # FFI Approach
//!
//! This example uses the **manual FFI approach**, where:
//! - Rust functions are marked with `#[no_mangle]` and `extern "C"`
//! - A corresponding C/C++ header file is written by hand
//!
//! This is not the only way to expose Rust to C++. Alternative approaches include:
//! - **[cbindgen](https://github.com/mozilla/cbindgen)**: Automatically generates C/C++ headers from Rust code
//! - **[cxx](https://cxx.rs/)**: Provides safe bidirectional interop between Rust and C++
//!
//! The manual approach was chosen here for simplicity.
//!
//! # Target Compatibility
//!
//! Uses `no_std` for compatibility with both POSIX and embedded targets.

#![no_std]

/// Panic handler for no_std environments.
#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
loop {}
}



/// Adds two numbers and returns the result.
///
/// # Arguments
///
/// * `a` - First number to add
/// * `b` - Second number to add
///
/// # Returns
///
/// The sum of `a` and `b`.
#[unsafe(no_mangle)]
pub extern "C" fn rust_add(a: u32, b: u32) -> u32 {
a.wrapping_add(b)
}
1 change: 1 addition & 0 deletions libs/3rdparty/corrosion/.github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
github: ["jschwe"]
Loading