Commit f806a3f9 authored by David Brown's avatar David Brown Committed by David Brown
Browse files

rust: Create zephyr-sys for low-level bindings

With a lot of work done by Mario Jaun <mario.jaun@zuehlke.com>.

Use the rust-bindgen tool to extract bindings from the Zephyr header files.
The tool is run with the exact configuration of the current build, and
therefore the bindings will match the current target.  The ifdefs and such
are not translated into the Rust code, and this must be generated live for
each build.

Signed-off-by: default avatarDavid Brown <david.brown@linaro.org>
parent 4dd43caf
Loading
Loading
Loading
Loading
+18 −0
Changes for lib/rust/zephyr-sys/Cargo.toml: 18 added lines, 0 removed lines.
Original line number Diff line number Diff line
# Copyright (c) 2024 Linaro LTD
# SPDX-License-Identifier: Apache-2.0

[package]
name = "zephyr-sys"
version = "0.1.0"
edition = "2021"
description = """
Zephyr low-level API bindings.
"""

# These are needed at build time.
# Whether these need to be vendored is an open question.  They are not
# used by the core Zephyr tree, but are needed by zephyr applications.
[build-dependencies]
anyhow = "1.0"
bindgen = { version = "0.69.4", features = ["experimental"] }
# zephyr-build = { version = "0.1.0", path = "../zephyr-build" }
+71 −0
Changes for lib/rust/zephyr-sys/build.rs: 71 added lines, 0 removed lines.
Original line number Diff line number Diff line
// Copyright (c) 2024 Linaro LTD
// SPDX-License-Identifier: Apache-2.0

// Pre-build code for zephyr module.

// This module makes the values from the generated .config available as conditional compilation.
// Note that this only applies to the zephyr module, and the user's application will not be able to
// see these definitions.  To make that work, this will need to be moved into a support crate which
// can be invoked by the user's build.rs.

// This builds a program that is run on the compilation host before the code is compiled.  It can
// output configuration settings that affect the compilation.

use anyhow::Result;

use bindgen::Builder;

use std::env;
use std::path::PathBuf;

fn main() -> Result<()> {
    // Pass in the target used to build the native code.
    let target_arg = format!("--target={}", env::var("TARGET")?);

    // println!("includes: {:?}", env::var("INCLUDE_DIRS"));
    // println!("defines: {:?}", env::var("INCLUDE_DEFINES"));

    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    let wrapper_path = PathBuf::from(env::var("WRAPPER_FILE").unwrap());

    // Bindgen everything.
    let bindings = Builder::default()
        .header("wrapper.h")
        .use_core()
        .clang_arg(&target_arg);
    let bindings = define_args(bindings, "-I", "INCLUDE_DIRS");
    let bindings = define_args(bindings, "-D", "INCLUDE_DEFINES");
    let bindings = bindings
        .wrap_static_fns(true)
        .wrap_static_fns_path(wrapper_path)
        // <inttypes.h> seems to come from somewhere mysterious in Zephyr.  For us, just pull in the
        // one from the minimal libc.
        .clang_arg("-DRUST_BINDGEN")
        .clang_arg("-I../../../lib/libc/minimal/include")
        .derive_copy(false)
        .allowlist_function("k_.*")
        .allowlist_function("gpio_.*")
        .parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
        .generate()
        .expect("Unable to generate bindings");

    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("Couldn't write bindings!");

    Ok(())
}

fn define_args(bindings: Builder, prefix: &str, var_name: &str) -> Builder {
    let text = env::var(var_name).unwrap();
    let mut bindings = bindings;
    for entry in text.split(" ") {
        if entry.is_empty() {
            continue;
        }
        println!("Entry: {}{}", prefix, entry);
        let arg = format!("{}{}", prefix, entry);
        bindings = bindings.clang_arg(arg);
    }
    bindings
}
+16 −0
Changes for lib/rust/zephyr-sys/src/lib.rs: 16 added lines, 0 removed lines.
Original line number Diff line number Diff line
// Copyright (c) 2024 Linaro LTD
// SPDX-License-Identifier: Apache-2.0

//! Zephyr application support for Rust
//!
//! This crates provides the core functionality for applications written in Rust that run on top of
//! Zephyr.

#![no_std]

// Allow rust naming convention violations.
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]

include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
+25 −0
Changes for lib/rust/zephyr-sys/wrapper.h: 25 added lines, 0 removed lines.
Original line number Diff line number Diff line
/*
 * Copyright (c) 2024 Linaro LTD
 *
 * SPDX-License-Identifier: Apache-2.0
 */

/*
 * This file is the seed point for bindgen.  This determines every header that will be visited for
 * binding generation.  It should include any Zephyr headers we need bindings for.  The driver in
 * build.rs will also select which functions need generation, which will determine the types that
 * are output.
 */

#ifdef RUST_BINDGEN
/* errno is coming from somewhere in Zephyr's build.  Add the symbol when running bindgen so that it
 * is defined here.
 */
extern int errno;
#endif

/* First, make sure we have all of our config settings. */
#include <zephyr/autoconf.h>

#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>