Add chip-specific features for tests/examples (#2175)

* Refactor metadata parsing to allow spaces in keys

* Emit separate examples per chip

* Allow setting features for specific chips
This commit is contained in:
Dániel Buga 2024-09-23 13:42:11 +02:00 committed by GitHub
parent 987f00bb1d
commit d971d65c98
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 57 additions and 34 deletions

View File

@ -73,6 +73,7 @@ pub enum Cores {
Eq, Eq,
PartialOrd, PartialOrd,
Ord, Ord,
Hash,
serde::Deserialize, serde::Deserialize,
serde::Serialize, serde::Serialize,
strum::Display, strum::Display,

View File

@ -1,5 +1,5 @@
use std::{ use std::{
collections::VecDeque, collections::{HashMap, VecDeque},
fs::{self, File}, fs::{self, File},
io::Write as _, io::Write as _,
path::{Path, PathBuf}, path::{Path, PathBuf},
@ -53,24 +53,18 @@ pub enum Package {
XtensaLxRt, XtensaLxRt,
} }
#[derive(Debug, Default, Clone)] #[derive(Debug, Clone)]
pub struct Metadata { pub struct Metadata {
example_path: PathBuf, example_path: PathBuf,
chips: Vec<Chip>, chip: Chip,
feature_set: Vec<String>, feature_set: Vec<String>,
} }
impl Metadata { impl Metadata {
pub fn new(example_path: &Path, chips: Vec<Chip>, feature_set: Vec<String>) -> Self { pub fn new(example_path: &Path, chip: Chip, feature_set: Vec<String>) -> Self {
let chips = if chips.is_empty() {
Chip::iter().collect()
} else {
chips
};
Self { Self {
example_path: example_path.to_path_buf(), example_path: example_path.to_path_buf(),
chips, chip,
feature_set, feature_set,
} }
} }
@ -96,7 +90,7 @@ impl Metadata {
/// If the specified chip is in the list of chips, then it is supported. /// If the specified chip is in the list of chips, then it is supported.
pub fn supports_chip(&self, chip: Chip) -> bool { pub fn supports_chip(&self, chip: Chip) -> bool {
self.chips.contains(&chip) self.chip == chip
} }
} }
@ -167,38 +161,56 @@ pub fn load_examples(path: &Path, action: CargoAction) -> Result<Vec<Metadata>>
let text = fs::read_to_string(&path) let text = fs::read_to_string(&path)
.with_context(|| format!("Could not read {}", path.display()))?; .with_context(|| format!("Could not read {}", path.display()))?;
let mut chips = Vec::new(); let mut chips = Chip::iter().collect::<Vec<_>>();
let mut feature_sets = Vec::new(); let mut feature_sets = Vec::new();
let mut chip_features = HashMap::new();
// We will indicate metadata lines using the `//%` prefix: // We will indicate metadata lines using the `//%` prefix:
for line in text.lines().filter(|line| line.starts_with("//%")) { for line in text.lines().filter(|line| line.starts_with("//%")) {
let mut split = line let Some((key, value)) = line.trim_start_matches("//%").split_once(':') else {
.trim_start_matches("//%") bail!("Metadata line is missing ':': {}", line);
.trim() };
.split_ascii_whitespace()
.map(|s| s.to_string())
.collect::<Vec<_>>();
if split.len() < 2 { let key = key.trim();
bail!(
"Expected at least two elements (key, value), found {}",
split.len()
);
}
// The trailing ':' on metadata keys is optional :)
let key = split.swap_remove(0);
let key = key.trim_end_matches(':');
if key == "CHIPS" { if key == "CHIPS" {
chips = split chips = value
.iter() .split_ascii_whitespace()
.map(|s| Chip::from_str(s, false).unwrap()) .map(|s| Chip::from_str(s, false).unwrap())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
} else if key == "FEATURES" { } else if key == "FEATURES" {
// Base feature set required to run the example.
// If multiple are specified, we compile the same example multiple times.
let mut values = value
.split_ascii_whitespace()
.map(ToString::to_string)
.collect::<Vec<_>>();
// Sort the features so they are in a deterministic order: // Sort the features so they are in a deterministic order:
split.sort(); values.sort();
feature_sets.push(split);
feature_sets.push(values);
} else if key.starts_with("CHIP-FEATURES(") {
// Additional features required for specific chips.
// These are appended to the base feature set(s).
// If multiple are specified, the last entry wins.
let chips = key
.trim_start_matches("CHIP-FEATURES(")
.trim_end_matches(')');
let chips = chips
.split_ascii_whitespace()
.map(|s| Chip::from_str(s, false).unwrap())
.collect::<Vec<_>>();
let values = value
.split_ascii_whitespace()
.map(ToString::to_string)
.collect::<Vec<_>>();
for chip in chips {
chip_features.insert(chip, values.clone());
}
} else { } else {
log::warn!("Unrecognized metadata key '{key}', ignoring"); log::warn!("Unrecognized metadata key '{key}', ignoring");
} }
@ -214,7 +226,17 @@ pub fn load_examples(path: &Path, action: CargoAction) -> Result<Vec<Metadata>>
feature_sets.truncate(1); feature_sets.truncate(1);
} }
for feature_set in feature_sets { for feature_set in feature_sets {
examples.push(Metadata::new(&path, chips.clone(), feature_set)); for chip in &chips {
let mut feature_set = feature_set.clone();
if let Some(chip_features) = chip_features.get(chip) {
feature_set.extend(chip_features.iter().cloned());
// Sort the features so they are in a deterministic order:
feature_set.sort();
}
examples.push(Metadata::new(&path, *chip, feature_set.clone()));
}
} }
} }