Skip to content

Commit 5230bb4

Browse files
committed
rust: Basic zephyr crates
This is the initial Zephyr-specific crates that provide support for Rust on Zephyr. Currently, what they do is fairly minimal, but important. `zephyr-build` is a build time crate (linked against the `zephyr` crate's build.rs) that processes the current build's Kconfig settings, and does three things with them: - Boolean Kconfig values given given to the Rust toolchain so that conditional compilation can be based off of them. - Numeric Kconfig settings end up as constants in `zephyr::kconfig`. - String valued Kconfig settings end up as constants in `zephyr::kconfig`. None of these cause code or data to be generated or allocated (but note that if there is a reference to a string, that string will be placed in read-only memory). The `zephyr` crate is built for the target, and intended to be referenced by the application. It provides minimal support needed for a "bare" Rust build, notably a panic handler. At this point, the panic handler is not implemented as we need better support for calling into Zephyr's C code, so it just stops in an infinite loop. It also ensures that `CONFIG_RUST` is set as a sanity check, and includes the generated kconfig.rs file with the kconfig definitions for the current build. Signed-off-by: David Brown <[email protected]>
1 parent 148e135 commit 5230bb4

File tree

5 files changed

+152
-0
lines changed

5 files changed

+152
-0
lines changed

lib/rust/zephyr-build/Cargo.toml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Copyright (c) 2024 Linaro LTD
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
[package]
5+
name = "zephyr-build"
6+
version = "0.1.0"
7+
edition = "2021"
8+
description = """
9+
Build-time support for Rust-based applications that run on Zephyr.
10+
Provides utilities for accessing Kconfig and devicetree information.
11+
"""
12+
13+
# These are needed at build time.
14+
# Whether these need to be vendored is an open question. They are not
15+
# used by the core Zephyr tree, but are needed by zephyr applications.
16+
[dependencies]
17+
regex = "1.10.3"

lib/rust/zephyr-build/src/lib.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Copyright (c) 2024 Linaro LTD
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
// Pre-build code for zephyr module.
5+
6+
// This module makes the values from the generated .config available as conditional compilation.
7+
// Note that this only applies to the zephyr module, and the user's application will not be able to
8+
// see these definitions. To make that work, this will need to be moved into a support crate which
9+
// can be invoked by the user's build.rs.
10+
11+
// This builds a program that is run on the compilation host before the code is compiled. It can
12+
// output configuration settings that affect the compilation.
13+
14+
use std::io::{BufRead, BufReader, Write};
15+
use std::env;
16+
use std::fs::File;
17+
use std::path::Path;
18+
19+
use regex::Regex;
20+
21+
/// Export boolean Kconfig entries. This must happen in any crate that wishes to access the
22+
/// configuration settings.
23+
pub fn export_bool_kconfig() {
24+
let dotconfig = env::var("DOTCONFIG").expect("DOTCONFIG must be set by wrapper");
25+
26+
// Ensure the build script is rerun when the dotconfig changes.
27+
println!("cargo:rerun-if-env-changed=DOTCONFIG");
28+
println!("cargo-rerun-if-changed={}", dotconfig);
29+
30+
let config_y = Regex::new(r"^(CONFIG_.*)=y$").unwrap();
31+
32+
let file = File::open(&dotconfig).expect("Unable to open dotconfig");
33+
for line in BufReader::new(file).lines() {
34+
let line = line.expect("reading line from dotconfig");
35+
if let Some(caps) = config_y.captures(&line) {
36+
println!("cargo:rustc-cfg={}", &caps[1]);
37+
}
38+
}
39+
}
40+
41+
/// Capture bool, numeric and string kconfig values in a 'kconfig' module.
42+
/// This is a little simplistic, and will make the entries numeric if they look like numbers.
43+
/// Ideally, this would be built on the types of the values, but that will require more
44+
/// introspection.
45+
pub fn build_kconfig_mod() {
46+
let dotconfig = env::var("DOTCONFIG").expect("DOTCONFIG must be set by wrapper");
47+
let outdir = env::var("OUT_DIR").expect("OUT_DIR must be set");
48+
49+
// The assumption is that hex values are unsigned, and decimal are signed.
50+
let config_hex = Regex::new(r"^(CONFIG_.*)=(0x[0-9a-fA-F]+)$").unwrap();
51+
let config_int = Regex::new(r"^(CONFIG_.*)=(-?[1-9][0-9]*)$").unwrap();
52+
// It is unclear what quoting might be used in the .config.
53+
let config_str = Regex::new(r#"^(CONFIG_.*)=(".*")$"#).unwrap();
54+
let gen_path = Path::new(&outdir).join("kconfig.rs");
55+
56+
let mut f = File::create(&gen_path).unwrap();
57+
writeln!(&mut f, "pub mod kconfig {{").unwrap();
58+
59+
let file = File::open(&dotconfig).expect("Unable to open dotconfig");
60+
for line in BufReader::new(file).lines() {
61+
let line = line.expect("reading line from dotconfig");
62+
if let Some(caps) = config_hex.captures(&line) {
63+
writeln!(&mut f, " #[allow(dead_code)]").unwrap();
64+
writeln!(&mut f, " pub const {}: usize = {};",
65+
&caps[1], &caps[2]).unwrap();
66+
} else if let Some(caps) = config_int.captures(&line) {
67+
writeln!(&mut f, " #[allow(dead_code)]").unwrap();
68+
writeln!(&mut f, " pub const {}: isize = {};",
69+
&caps[1], &caps[2]).unwrap();
70+
} else if let Some(caps) = config_str.captures(&line) {
71+
writeln!(&mut f, " #[allow(dead_code)]").unwrap();
72+
writeln!(&mut f, " pub const {}: &'static str = {};",
73+
&caps[1], &caps[2]).unwrap();
74+
}
75+
}
76+
writeln!(&mut f, "}}").unwrap();
77+
}

lib/rust/zephyr/Cargo.toml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Copyright (c) 2024 Linaro LTD
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
[package]
5+
name = "zephyr"
6+
version = "0.1.0"
7+
edition = "2021"
8+
description = """
9+
Functionality for Rust-based applications that run on Zephyr.
10+
"""
11+
12+
# These are needed at build time.
13+
# Whether these need to be vendored is an open question. They are not
14+
# used by the core Zephyr tree, but are needed by zephyr applications.
15+
[build-dependencies]
16+
zephyr-build = "0.1.0"

lib/rust/zephyr/build.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright (c) 2024 Linaro LTD
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
// Pre-build code for zephyr module.
5+
6+
// This module makes the values from the generated .config available as conditional compilation.
7+
// Note that this only applies to the zephyr module, and the user's application will not be able to
8+
// see these definitions. To make that work, this will need to be moved into a support crate which
9+
// can be invoked by the user's build.rs.
10+
11+
// This builds a program that is run on the compilation host before the code is compiled. It can
12+
// output configuration settings that affect the compilation.
13+
14+
fn main() {
15+
zephyr_build::export_bool_kconfig();
16+
zephyr_build::build_kconfig_mod();
17+
}

lib/rust/zephyr/src/lib.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright (c) 2024 Linaro LTD
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
//! Zephyr application support for Rust
5+
//!
6+
//! This crates provides the core functionality for applications written in Rust that run on top of
7+
//! Zephyr.
8+
9+
#![no_std]
10+
11+
// Bring in the generated kconfig module
12+
include!(concat!(env!("OUT_DIR"), "/kconfig.rs"));
13+
14+
// Ensure that Rust is enabled.
15+
#[cfg(not(CONFIG_RUST))]
16+
compile_error!("CONFIG_RUST must be set to build Rust in Zephyr");
17+
18+
use core::panic::PanicInfo;
19+
20+
/// Override rust's panic. This simplistic initial version just hangs in a loop.
21+
#[panic_handler]
22+
fn panic(_ :&PanicInfo) -> ! {
23+
loop {
24+
}
25+
}

0 commit comments

Comments
 (0)