[Concept,04/13] ulib: Add Rust demo example

Message ID 20260220001926.2366140-5-sjg@u-boot.org
State New
Headers
Series ulib: Enable the Rust demo on more architectures |

Commit Message

Simon Glass Feb. 20, 2026, 12:19 a.m. UTC
  From: Simon Glass <simon.glass@canonical.com>

Add a #![no_std] Rust equivalent of the C ulib demo, compiled to an
object file with rustc and linked into U-Boot via the existing
u-boot-link mechanism. The Rust demo calls the same C helpers
(demo_show_banner, demo_show_footer, demo_add_numbers) via FFI and
produces identical output, so assert_demo_output() works unchanged.

Use core::ptr::addr_of!() rather than a reference cast to access the
extern static version_string, since the compiler cannot prove that an
extern static is non-null and would emit a call to an undefined panic
symbol.

Add CONFIG_RUST_EXAMPLES Kconfig option to gate the Rust examples.
When enabled, rustc must be available with the appropriate target for
the architecture.

Clear MAKEFLAGS when invoking rustc so that it does not inherit
make's --jobserver-auth file descriptors, which would produce a
spurious warning on every compilation.

Co-developed-by: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
---

 examples/Kconfig              | 13 +++++++++
 examples/ulib/rust_demo.rs    | 55 +++++++++++++++++++++++++++++++++++
 scripts/Makefile.ulib-example | 17 +++++++++++
 3 files changed, 85 insertions(+)
 create mode 100644 examples/ulib/rust_demo.rs
  

Patch

diff --git a/examples/Kconfig b/examples/Kconfig
index 5738d555d22..7f099808908 100644
--- a/examples/Kconfig
+++ b/examples/Kconfig
@@ -9,6 +9,19 @@  config EXAMPLES
 	  U-Boot provides an legacy API for standalone applications. Examples
 	  are provided in directory examples/.
 
+config RUST_EXAMPLES
+	bool "Build Rust example programs"
+	depends on EXAMPLES
+	help
+	  Build example programs written in Rust alongside the C
+	  examples. The Rust demo calls the same C helpers via FFI
+	  and produces identical output.
+
+	  Requires a Rust toolchain (rustc) with the appropriate
+	  cross-compilation target for the architecture, e.g.
+	  x86_64-unknown-none for x86_64 or aarch64-unknown-none
+	  for ARM64.
+
 config EXAMPLES_STANDALONE
 	bool "Compile standalone examples"
 	depends on !SANDBOX
diff --git a/examples/ulib/rust_demo.rs b/examples/ulib/rust_demo.rs
new file mode 100644
index 00000000000..7a85658520d
--- /dev/null
+++ b/examples/ulib/rust_demo.rs
@@ -0,0 +1,55 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Rust demo program showing U-Boot library functionality
+//
+// Demonstrates calling C helper functions from Rust via FFI, producing
+// identical output to demo.c so assert_demo_output() works unchanged.
+//
+// Copyright 2026 Canonical Ltd.
+// Written by Simon Glass <simon.glass@canonical.com>
+
+#![no_std]
+#![no_main]
+
+use core::ffi::c_int;
+
+extern "C" {
+    fn printf(fmt: *const u8, ...) -> c_int;
+    fn demo_show_banner();
+    fn demo_show_footer();
+    fn demo_add_numbers(a: c_int, b: c_int) -> c_int;
+    static version_string: u8;
+}
+
+#[no_mangle]
+pub extern "C" fn ulib_has_main() -> bool {
+    true
+}
+
+fn demo_run() -> c_int {
+    unsafe {
+        demo_show_banner();
+        // Use addr_of!() rather than &version_string to avoid a
+        // null-pointer check: &T must be non-null, but the compiler
+        // cannot prove that for an extern static, so it emits a call
+        // to an undefined panic symbol that crashes ld.bfd on aarch64.
+        printf(
+            b"U-Boot version: %s\n\0".as_ptr(),
+            core::ptr::addr_of!(version_string),
+        );
+        printf(b"\n\0".as_ptr());
+        demo_add_numbers(42, 13);
+        demo_show_footer();
+    }
+    0
+}
+
+#[no_mangle]
+pub extern "C" fn main() -> c_int {
+    demo_run()
+}
+
+#[panic_handler]
+fn panic(_: &core::panic::PanicInfo) -> ! {
+    loop {}
+}
diff --git a/scripts/Makefile.ulib-example b/scripts/Makefile.ulib-example
index 796b74b0c14..18d526f5b6b 100644
--- a/scripts/Makefile.ulib-example
+++ b/scripts/Makefile.ulib-example
@@ -19,11 +19,28 @@  PHONY += examples_$(EXAMPLE_ARCH)
 
 ULIB_EXAMPLES := demo
 
+# --- Rust examples ---
+RUSTC := rustc
+RUST_TARGET := $(RUST_TARGET_$(EXAMPLE_ARCH))
+
+ifeq ($(CONFIG_RUST_EXAMPLES),y)
+ULIB_EXAMPLES += rust-demo
+endif
+
 quiet_cmd_u-boot-example = LD      $@
       cmd_u-boot-example = $(call u-boot-link,$(example-objs),$@.map)
 
+quiet_cmd_rustc_obj = RUSTC   $@
+      cmd_rustc_obj = \
+	mkdir -p $(dir $@) && \
+	MAKEFLAGS= $(RUSTC) --edition 2021 --emit=obj -o $@ --target=$(RUST_TARGET) $<
+
+examples/ulib/rust_demo.o: examples/ulib/rust_demo.rs FORCE
+	$(call if_changed,rustc_obj)
+
 # Per-example object lists (matches examples/ulib/Kbuild)
 example-demo-objs := examples/ulib/demo.o examples/ulib/demo_helper.o
+example-rust-demo-objs := examples/ulib/rust_demo.o examples/ulib/demo_helper.o
 
 # Generate link rule for each example
 define example_link_rule