From ba6786974ec1cfe33ba07b64fe77ba37e9b02463 Mon Sep 17 00:00:00 2001 From: Jesse Braham Date: Fri, 9 Feb 2024 11:21:33 -0800 Subject: [PATCH 1/3] Create the `xtask` package, add command for building examples --- .cargo/config.toml | 2 + Cargo.toml | 17 +++++ xtask/Cargo.toml | 12 +++ xtask/README.md | 16 ++++ xtask/src/lib.rs | 181 +++++++++++++++++++++++++++++++++++++++++++++ xtask/src/main.rs | 50 +++++++++++++ 6 files changed, 278 insertions(+) create mode 100644 .cargo/config.toml create mode 100644 Cargo.toml create mode 100644 xtask/Cargo.toml create mode 100644 xtask/README.md create mode 100644 xtask/src/lib.rs create mode 100644 xtask/src/main.rs diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 00000000000..35049cbcb13 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,2 @@ +[alias] +xtask = "run --package xtask --" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 00000000000..66181587301 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,17 @@ +[workspace] +members = ["xtask"] +exclude = [ + "esp-hal", + "esp-hal-procmacros", + "esp-hal-smartled", + "esp-lp-hal", + "esp-riscv-rt", + "esp32-hal", + "esp32c2-hal", + "esp32c3-hal", + "esp32c6-hal", + "esp32h2-hal", + "esp32p4-hal", + "esp32s2-hal", + "esp32s3-hal", +] diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml new file mode 100644 index 00000000000..ccdd1bc7169 --- /dev/null +++ b/xtask/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "xtask" +version = "0.0.0" +edition = "2021" +publish = false + +[dependencies] +anyhow = "1.0.79" +clap = { version = "4.5.0", features = ["derive"] } +env_logger = "0.11.1" +log = "0.4.20" +strum = { version = "0.26.1", features = ["derive"] } diff --git a/xtask/README.md b/xtask/README.md new file mode 100644 index 00000000000..84ded0d543c --- /dev/null +++ b/xtask/README.md @@ -0,0 +1,16 @@ +# xtask + +Automation using [cargo-xtask](https://github.com/matklad/cargo-xtask). + +## Usage + +```text +Usage: xtask + +Commands: + build-examples Build all examples for the specified chip + help Print this message or the help of the given subcommand(s) + +Options: + -h, --help Print help +``` diff --git a/xtask/src/lib.rs b/xtask/src/lib.rs new file mode 100644 index 00000000000..2d73ddcc9c7 --- /dev/null +++ b/xtask/src/lib.rs @@ -0,0 +1,181 @@ +use std::{ + collections::VecDeque, + fs, + path::{Path, PathBuf}, + process::{Command, Stdio}, +}; + +use anyhow::{bail, Result}; +use clap::ValueEnum; +use strum::{Display, EnumIter, IntoEnumIterator}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Display, EnumIter, ValueEnum)] +#[strum(serialize_all = "kebab-case")] +pub enum Chip { + Esp32, + Esp32c2, + Esp32c3, + Esp32c6, + Esp32h2, + Esp32p4, + Esp32s2, + Esp32s3, +} + +impl Chip { + pub fn target(&self) -> &str { + use Chip::*; + + match self { + Esp32 => "xtensa-esp32-none-elf", + Esp32c2 | Esp32c3 => "riscv32imc-unknown-none-elf", + Esp32c6 | Esp32h2 => "riscv32imac-unknown-none-elf", + Esp32p4 => "riscv32imafc-unknown-none-elf", + Esp32s2 => "xtensa-esp32s2-none-elf", + Esp32s3 => "xtensa-esp32s3-none-elf", + } + } + + pub fn toolchain(&self) -> &str { + use Chip::*; + + match self { + Esp32 | Esp32s2 | Esp32s3 => "xtensa", + _ => "nightly", + } + } +} + +#[derive(Debug)] +pub struct Metadata { + path: PathBuf, + chips: Vec, + features: Vec, +} + +impl Metadata { + pub fn new(path: PathBuf, chips: Vec, features: Vec) -> Self { + let chips = if chips.is_empty() { + Chip::iter().collect() + } else { + chips + }; + + Self { + path, + chips, + features, + } + } + + /// Absolute path to the example. + pub fn path(&self) -> &Path { + &self.path + } + + /// A list of all features required for building a given examples. + pub fn features(&self) -> &[String] { + &self.features + } + + /// If the specified chip is in the list of chips, then it is supported. + pub fn supports_chip(&self, chip: Chip) -> bool { + self.chips.contains(&chip) + } +} + +pub fn load_examples(workspace: &Path) -> Result> { + let bin_path = workspace + .join("examples") + .join("src") + .join("bin") + .canonicalize()?; + + let mut examples = Vec::new(); + + for entry in fs::read_dir(bin_path)? { + let path = entry?.path(); + let text = fs::read_to_string(&path)?; + + let mut chips = Vec::new(); + let mut features = Vec::new(); + + // We will indicate metadata lines using the `//%` prefix: + let lines = text + .lines() + .filter(|line| line.starts_with("//%")) + .collect::>(); + + for line in lines { + let mut split = line + .trim_start_matches("//%") + .trim() + .split_ascii_whitespace() + .map(|s| s.to_string()) + .collect::>(); + + if split.len() < 2 { + bail!( + "Expected at least two elements (key, value), found {}", + split.len() + ); + } + + // The trailing ':' on metadata keys is optional :) + let key = split.pop_front().unwrap(); + let key = key.trim_end_matches(':'); + + if key == "CHIPS" { + chips = split + .iter() + .map(|s| Chip::from_str(s, false).unwrap()) + .collect::>(); + } else if key == "FEATURES" { + features = split.into(); + } else { + log::warn!("Unregognized metadata key '{key}', ignoring"); + } + } + + let meta = Metadata::new(path, chips, features); + examples.push(meta); + } + + Ok(examples) +} + +pub fn build_example(workspace: &Path, chip: Chip, example: &Metadata) -> Result<()> { + let path = example.path(); + let features = example.features(); + + log::info!("Building example '{}' for '{}'", path.display(), chip); + if !features.is_empty() { + log::info!(" Features: {}", features.join(",")); + } + + let bin_name = example + .path() + .file_name() + .unwrap() + .to_string_lossy() + .replace(".rs", ""); + + let args = &[ + &format!("+{}", chip.toolchain()), + "build", + "--release", + &format!("--target={}", chip.target()), + &format!("--features={},{}", chip, features.join(",")), + &format!("--bin={bin_name}"), + ]; + log::debug!("{args:#?}"); + + Command::new("cargo") + .args(args) + .current_dir(workspace.join("examples")) + .stdout(Stdio::piped()) + .stderr(Stdio::inherit()) + .output()?; + + Ok(()) +} diff --git a/xtask/src/main.rs b/xtask/src/main.rs new file mode 100644 index 00000000000..5a32ae3e2de --- /dev/null +++ b/xtask/src/main.rs @@ -0,0 +1,50 @@ +use std::path::{Path, PathBuf}; + +use anyhow::Result; +use clap::{Args, Parser}; +use xtask::Chip; + +// ---------------------------------------------------------------------------- +// Command-line Interface + +#[derive(Debug, Parser)] +enum Cli { + /// Build all examples for the specified chip. + BuildExamples(BuildExamplesArgs), +} + +#[derive(Debug, Args)] +struct BuildExamplesArgs { + /// Which chip to build the examples for. + #[clap(value_enum)] + chip: Chip, +} + +// ---------------------------------------------------------------------------- +// Application + +fn main() -> Result<()> { + env_logger::Builder::new() + .filter_module("xtask", log::LevelFilter::Info) + .init(); + + let workspace = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let workspace = workspace.parent().unwrap().canonicalize()?; + + match Cli::parse() { + Cli::BuildExamples(args) => build_examples(&workspace, args), + } +} + +// ---------------------------------------------------------------------------- +// Subcommands + +fn build_examples(workspace: &Path, args: BuildExamplesArgs) -> Result<()> { + // Load all examples and parse their metadata. Filter down the examples to only + // those for which our chip is supported, and then attempt to build each + // remaining example, with the required features enabled: + xtask::load_examples(workspace)? + .iter() + .filter(|example| example.supports_chip(args.chip)) + .try_for_each(|example| xtask::build_example(workspace, args.chip, example)) +} From af09a000d644bf1a9b4a81e8d3be148bc695365b Mon Sep 17 00:00:00 2001 From: Jesse Braham Date: Fri, 9 Feb 2024 11:23:55 -0800 Subject: [PATCH 2/3] Do not perform changelog check for `xtask` package changes --- .github/workflows/changelog.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml index 034026c7f37..a012534db7b 100644 --- a/.github/workflows/changelog.yml +++ b/.github/workflows/changelog.yml @@ -1,7 +1,10 @@ -name: Change log check +name: Changelog check on: pull_request: + # We will not track changes for the `xtask` package. + paths-ignore: + - "/xtask/" # Run on labeled/unlabeled in addition to defaults to detect # adding/removing skip-changelog labels. types: [opened, reopened, labeled, unlabeled, synchronize] From 93eed7272f525afca82b891a9475e8728bb7dfb4 Mon Sep 17 00:00:00 2001 From: Jesse Braham Date: Mon, 12 Feb 2024 07:18:20 -0800 Subject: [PATCH 3/3] Fix unrelated `rustfmt` error --- esp-hal/src/rom/crc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esp-hal/src/rom/crc.rs b/esp-hal/src/rom/crc.rs index e5961d51dc9..c2585f6ee9f 100644 --- a/esp-hal/src/rom/crc.rs +++ b/esp-hal/src/rom/crc.rs @@ -26,7 +26,7 @@ //! //! ``` //! // CRC-32/MPEG-2 -//! const CRC_INITIAL = 0xffffffff; // "init" or "xorin" of all ones +//! const CRC_INITIAL: _ = 0xffffffff; // "init" or "xorin" of all ones //! let mut crc = crc32_be(!CRC_INITIAL, &data0); // start //! crc = crc32_be(crc, &data1); //! crc = !crc32_be(crc, &data2); // finish