Skip to content

Commit f59019b

Browse files
committed
examples: New app to build Rust with Cargo
Build Rust applictions with cargo is the most commn way, and it's more easy to cooporate with Rust ecosystem. This example shows how to use cargo to build a simple hello world application. And please notice that you need to install nighly version of rustc to support this feature, any version after rust-lang/rust#127755 is merged, can use NuttX as cargo target directly. Build ----- To build hello_rust_cargo application, you can use any target that based on RISCV32IMAC, for example: ``` cmake -B build -DBOARD_CONFIG=rv-virt:nsh -GNinja . ``` And disable ARCH_FPU in menuconfig, since the hard coded target triple in this demo is `riscv32imac`. Signed-off-by: Huang Qi <[email protected]>
1 parent 2cfbdbb commit f59019b

File tree

10 files changed

+493
-0
lines changed

10 files changed

+493
-0
lines changed

CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ if(CONFIG_APPS_DIR)
3333
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake)
3434
include(nuttx_add_luamod)
3535
include(nuttx_add_wamrmod)
36+
include(nuttx_add_rust)
3637
nuttx_add_library(apps)
3738
if(NOT EXISTS {NUTTX_APPS_BINDIR}/dummy.c)
3839
file(TOUCH ${NUTTX_APPS_BINDIR}/dummy.c)

cmake/nuttx_add_rust.cmake

+166
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
# ##############################################################################
2+
# cmake/nuttx_add_rust.cmake
3+
#
4+
# Licensed to the Apache Software Foundation (ASF) under one or more contributor
5+
# license agreements. See the NOTICE file distributed with this work for
6+
# additional information regarding copyright ownership. The ASF licenses this
7+
# file to you under the Apache License, Version 2.0 (the "License"); you may not
8+
# use this file except in compliance with the License. You may obtain a copy of
9+
# the License at
10+
#
11+
# http://www.apache.org/licenses/LICENSE-2.0
12+
#
13+
# Unless required by applicable law or agreed to in writing, software
14+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16+
# License for the specific language governing permissions and limitations under
17+
# the License.
18+
#
19+
# ##############################################################################
20+
21+
include(nuttx_parse_function_args)
22+
23+
# ~~~
24+
# Convert architecture type to Rust NuttX target
25+
#
26+
# Supported architectures:
27+
# - armv7a: armv7a-nuttx-eabi, armv7a-nuttx-eabihf
28+
# - thumbv6m: thumbv6m-nuttx-eabi
29+
# - thumbv7a: thumbv7a-nuttx-eabi, thumbv7a-nuttx-eabihf
30+
# - thumbv7m: thumbv7m-nuttx-eabi
31+
# - thumbv7em: thumbv7em-nuttx-eabihf
32+
# - thumbv8m.main: thumbv8m.main-nuttx-eabi, thumbv8m.main-nuttx-eabihf
33+
# - thumbv8m.base: thumbv8m.base-nuttx-eabi, thumbv8m.base-nuttx-eabihf
34+
# - riscv32: riscv32imc/imac/imafc-unknown-nuttx-elf
35+
# - riscv64: riscv64imac/imafdc-unknown-nuttx-elf
36+
#
37+
# Inputs:
38+
# ARCHTYPE - Architecture type (e.g. thumbv7m, riscv32)
39+
# ABITYPE - ABI type (e.g. eabi, eabihf)
40+
# CPUTYPE - CPU type (e.g. cortex-m4, sifive-e20)
41+
#
42+
# Output:
43+
# OUTPUT - Rust target triple (e.g. riscv32imac-unknown-nuttx-elf,
44+
# thumbv7m-nuttx-eabi, thumbv7em-nuttx-eabihf)
45+
# ~~~
46+
47+
function(nuttx_rust_target_triple ARCHTYPE ABITYPE CPUTYPE OUTPUT)
48+
if(ARCHTYPE MATCHES "thumb")
49+
if(ARCHTYPE MATCHES "thumbv8m")
50+
# Extract just the base architecture type (thumbv8m.main or thumbv8m.base)
51+
if(ARCHTYPE MATCHES "thumbv8m.main")
52+
set(ARCH_BASE "thumbv8m.main")
53+
elseif(ARCHTYPE MATCHES "thumbv8m.base")
54+
set(ARCH_BASE "thumbv8m.base")
55+
else()
56+
# Otherwise determine if we should use thumbv8m.main or thumbv8m.base
57+
# based on CPU type
58+
if(CPUTYPE MATCHES "cortex-m23")
59+
set(ARCH_BASE "thumbv8m.base")
60+
else()
61+
set(ARCH_BASE "thumbv8m.main")
62+
endif()
63+
endif()
64+
set(TARGET_TRIPLE "${ARCH_BASE}-nuttx-${ABITYPE}")
65+
else()
66+
set(TARGET_TRIPLE "${ARCHTYPE}-nuttx-${ABITYPE}")
67+
endif()
68+
elseif(ARCHTYPE STREQUAL "riscv32")
69+
if(CPUTYPE STREQUAL "sifive-e20")
70+
set(TARGET_TRIPLE "riscv32imc-unknown-nuttx-elf")
71+
elseif(CPUTYPE STREQUAL "sifive-e31")
72+
set(TARGET_TRIPLE "riscv32imac-unknown-nuttx-elf")
73+
elseif(CPUTYPE STREQUAL "sifive-e76")
74+
set(TARGET_TRIPLE "riscv32imafc-unknown-nuttx-elf")
75+
else()
76+
set(TARGET_TRIPLE "riscv32imc-unknown-nuttx-elf")
77+
endif()
78+
elseif(ARCHTYPE STREQUAL "riscv64")
79+
if(CPUTYPE STREQUAL "sifive-s51")
80+
set(TARGET_TRIPLE "riscv64imac-unknown-nuttx-elf")
81+
elseif(CPUTYPE STREQUAL "sifive-u54")
82+
set(TARGET_TRIPLE "riscv64imafdc-unknown-nuttx-elf")
83+
else()
84+
set(TARGET_TRIPLE "riscv64imac-unknown-nuttx-elf")
85+
endif()
86+
endif()
87+
set(${OUTPUT}
88+
${TARGET_TRIPLE}
89+
PARENT_SCOPE)
90+
endfunction()
91+
92+
# ~~~
93+
# nuttx_add_rust
94+
#
95+
# Description:
96+
# Build a Rust crate and add it as a static library to the NuttX build system
97+
#
98+
# Example:
99+
# nuttx_add_rust(
100+
# CRATE_NAME
101+
# hello
102+
# CRATE_PATH
103+
# ${CMAKE_CURRENT_SOURCE_DIR}/hello
104+
# )
105+
# ~~~
106+
107+
function(nuttx_add_rust)
108+
109+
# parse arguments into variables
110+
nuttx_parse_function_args(
111+
FUNC
112+
nuttx_add_rust
113+
ONE_VALUE
114+
CRATE_NAME
115+
CRATE_PATH
116+
REQUIRED
117+
CRATE_NAME
118+
CRATE_PATH
119+
ARGN
120+
${ARGN})
121+
122+
# Determine build profile based on CONFIG_DEBUG_FULLOPT
123+
if(CONFIG_DEBUG_FULLOPT)
124+
set(RUST_PROFILE "release")
125+
else()
126+
set(RUST_PROFILE "debug")
127+
endif()
128+
129+
# Get the Rust target triple
130+
message(STATUS "LLVM_ARCHTYPE: ${LLVM_ARCHTYPE}")
131+
nuttx_rust_target_triple(${LLVM_ARCHTYPE} ${LLVM_ABITYPE} ${LLVM_CPUTYPE}
132+
RUST_TARGET)
133+
134+
# Set up build directory in current binary dir
135+
set(RUST_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/${CRATE_NAME})
136+
set(RUST_LIB_PATH
137+
${RUST_BUILD_DIR}/${RUST_TARGET}/${RUST_PROFILE}/lib${CRATE_NAME}.a)
138+
139+
# Create build directory
140+
file(MAKE_DIRECTORY ${RUST_BUILD_DIR})
141+
142+
# Add a custom command to build the Rust crate
143+
add_custom_command(
144+
OUTPUT ${RUST_LIB_PATH}
145+
COMMAND
146+
cargo build --${RUST_PROFILE} -Zbuild-std=std,panic_abort --manifest-path
147+
${CRATE_PATH}/Cargo.toml --target ${RUST_TARGET} --target-dir
148+
${RUST_BUILD_DIR}
149+
COMMENT "Building Rust crate ${CRATE_NAME}"
150+
VERBATIM)
151+
152+
# Add a custom target that depends on the built library
153+
add_custom_target(${CRATE_NAME}_build ALL DEPENDS ${RUST_LIB_PATH})
154+
155+
# Add imported library target
156+
add_library(${CRATE_NAME} STATIC IMPORTED GLOBAL)
157+
set_target_properties(${CRATE_NAME} PROPERTIES IMPORTED_LOCATION
158+
${RUST_LIB_PATH})
159+
160+
# Add the Rust library to NuttX build
161+
nuttx_add_extra_library(${RUST_LIB_PATH})
162+
163+
# Ensure the Rust library is built before linking
164+
add_dependencies(${CRATE_NAME} ${CRATE_NAME}_build)
165+
166+
endfunction()
+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# ##############################################################################
2+
# apps/examples/hello_rust_cargo/CMakeLists.txt
3+
#
4+
# Licensed to the Apache Software Foundation (ASF) under one or more contributor
5+
# license agreements. See the NOTICE file distributed with this work for
6+
# additional information regarding copyright ownership. The ASF licenses this
7+
# file to you under the Apache License, Version 2.0 (the "License"); you may not
8+
# use this file except in compliance with the License. You may obtain a copy of
9+
# the License at
10+
#
11+
# http://www.apache.org/licenses/LICENSE-2.0
12+
#
13+
# Unless required by applicable law or agreed to in writing, software
14+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16+
# License for the specific language governing permissions and limitations under
17+
# the License.
18+
#
19+
# ##############################################################################
20+
21+
if(CONFIG_EXAMPLES_HELLO_RUST_CARGO)
22+
23+
# Build the Rust crate using nuttx_add_rust
24+
nuttx_add_rust(CRATE_NAME hello CRATE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/hello)
25+
26+
nuttx_add_application(
27+
NAME ${CONFIG_EXAMPLES_HELLO_RUST_CARGO_PROGNAME} STACKSIZE
28+
${CONFIG_EXAMPLES_HELLO_STACKSIZE} PRIORITY
29+
${CONFIG_EXAMPLES_HELLO_PRIORITY})
30+
31+
endif() # CONFIG_EXAMPLES_HELLO_RUST_CARGO

examples/hello_rust_cargo/Kconfig

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#
2+
# For a description of the syntax of this configuration file,
3+
# see the file kconfig-language.txt in the NuttX tools repository.
4+
#
5+
6+
config EXAMPLES_HELLO_RUST_CARGO
7+
tristate "\"Hello, Rust!\" example with Cargo"
8+
default n
9+
---help---
10+
Enable the \"Hello, Rust!\" example using Cargo to build.
11+
12+
if EXAMPLES_HELLO_RUST_CARGO
13+
14+
config EXAMPLES_HELLO_RUST_CARGO_PROGNAME
15+
string "Program name"
16+
default "hello_rust_cargo"
17+
---help---
18+
This is the name of the program that will be used when the
19+
program is installed.
20+
21+
config EXAMPLES_HELLO_RUST_CARGO_PRIORITY
22+
int "Hello Rust task priority"
23+
default 100
24+
25+
config EXAMPLES_HELLO_RUST_CARGO_STACKSIZE
26+
int "Hello Rust stack size"
27+
default DEFAULT_TASK_STACKSIZE
28+
29+
endif

examples/hello_rust_cargo/Make.defs

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
############################################################################
2+
# apps/examples/hello_rust_cargo/Make.defs
3+
#
4+
# Licensed to the Apache Software Foundation (ASF) under one or more
5+
# contributor license agreements. See the NOTICE file distributed with
6+
# this work for additional information regarding copyright ownership. The
7+
# ASF licenses this file to you under the Apache License, Version 2.0 (the
8+
# "License"); you may not use this file except in compliance with the
9+
# License. You may obtain a copy of the License at
10+
#
11+
# http://www.apache.org/licenses/LICENSE-2.0
12+
#
13+
# Unless required by applicable law or agreed to in writing, software
14+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16+
# License for the specific language governing permissions and limitations
17+
# under the License.
18+
#
19+
############################################################################
20+
21+
include $(APPDIR)/tools/Rust.mk
22+
23+
ifneq ($(CONFIG_EXAMPLES_HELLO_RUST_CARGO),)
24+
CONFIGURED_APPS += $(APPDIR)/examples/hello_rust_cargo
25+
EXTRA_LIBS += $(call RUST_GET_BINDIR,hello,$(APPDIR)/examples/hello_rust_cargo)
26+
endif

examples/hello_rust_cargo/Makefile

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
############################################################################
2+
# apps/examples/hello_rust/Makefile
3+
#
4+
# Licensed to the Apache Software Foundation (ASF) under one or more
5+
# contributor license agreements. See the NOTICE file distributed with
6+
# this work for additional information regarding copyright ownership. The
7+
# ASF licenses this file to you under the Apache License, Version 2.0 (the
8+
# "License"); you may not use this file except in compliance with the
9+
# License. You may obtain a copy of the License at
10+
#
11+
# http://www.apache.org/licenses/LICENSE-2.0
12+
#
13+
# Unless required by applicable law or agreed to in writing, software
14+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16+
# License for the specific language governing permissions and limitations
17+
# under the License.
18+
#
19+
############################################################################
20+
21+
include $(APPDIR)/Make.defs
22+
23+
# Hello, Rust! built-in application info
24+
25+
PROGNAME = $(CONFIG_EXAMPLES_HELLO_RUST_CARGO_PROGNAME)
26+
PRIORITY = $(CONFIG_EXAMPLES_HELLO_RUST_CARGO_PRIORITY)
27+
STACKSIZE = $(CONFIG_EXAMPLES_HELLO_RUST_CARGO_STACKSIZE)
28+
MODULE = $(CONFIG_EXAMPLES_HELLO_RUST_CARGO)
29+
30+
context::
31+
$(call RUST_CARGO_BUILD,hello,$(APPDIR)/examples/hello_rust_cargo)
32+
33+
clean::
34+
$(call RUST_CARGO_CLEAN,hello,$(APPDIR)/examples/hello_rust_cargo)
35+
36+
include $(APPDIR)/Application.mk
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
target
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
[package]
2+
name = "hello"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[lib]
7+
crate-type = ["staticlib"]
8+
9+
[profile.dev]
10+
panic = "abort"
11+
12+
# Special hanlding for the panic! macro, can be removed once
13+
# the libstd port for NuttX is complete.
14+
[profile.release]
15+
panic = "abort"
16+
lto = true
17+
18+
[dependencies]
19+
serde = { version = "1.0", features = ["derive"] }
20+
serde_json = "1.0"
21+
22+
tokio = { version = "1", features = ["rt"] }
+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
extern crate serde;
2+
extern crate serde_json;
3+
4+
use serde::{Deserialize, Serialize};
5+
6+
#[derive(Serialize, Deserialize)]
7+
struct Person {
8+
name: String,
9+
age: u8,
10+
}
11+
12+
// Function hello_rust_cargo without manglng
13+
#[no_mangle]
14+
pub extern "C" fn hello_rust_cargo_main() {
15+
// Print hello world to stdout
16+
17+
let john = Person {
18+
name: "John".to_string(),
19+
age: 30,
20+
};
21+
22+
let json_str = serde_json::to_string(&john).unwrap();
23+
println!("{}", json_str);
24+
25+
let jane = Person {
26+
name: "Jane".to_string(),
27+
age: 25,
28+
};
29+
30+
let json_str_jane = serde_json::to_string(&jane).unwrap();
31+
println!("{}", json_str_jane);
32+
33+
let json_data = r#"
34+
{
35+
"name": "Alice",
36+
"age": 28
37+
}"#;
38+
39+
let alice: Person = serde_json::from_str(json_data).unwrap();
40+
println!("Deserialized: {} is {} years old", alice.name, alice.age);
41+
42+
let pretty_json_str = serde_json::to_string_pretty(&alice).unwrap();
43+
println!("Pretty JSON:\n{}", pretty_json_str);
44+
45+
tokio::runtime::Builder::new_current_thread()
46+
.enable_all()
47+
.build()
48+
.unwrap()
49+
.block_on(async {
50+
println!("Hello world from tokio!");
51+
});
52+
53+
loop {
54+
// Do nothing
55+
}
56+
}

0 commit comments

Comments
 (0)