mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-26 20:00:32 +00:00
Even more cargo-batch, encode configs in Cargo.toml (#4134)
* Abstract out LP-core targeting packages * Encode targets_lp_core in Cargo.toml * Encode architecture compatibility in Cargo.toml * Move semver_checked into Cargo.toml * Cache parsed tomls * Parse simple feature sets from Cargo.toml * Move all basic feature rules to Cargo.toml * Add check configs * Limit command length on Windows * Update cargo.rs * Add clippy configs * Use a single syntax, use a single doc-config line * Fix known problems * Run cargo check in CI command * Fix more problems * Fix esp-storage
This commit is contained in:
parent
9e892db654
commit
69776eb638
@ -10,6 +10,16 @@ categories = ["embedded", "memory-management", "no-std"]
|
||||
repository = "https://github.com/esp-rs/esp-hal"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[package.metadata.espressif]
|
||||
doc-config = { features = ["defmt"] }
|
||||
check-configs = [
|
||||
{ features = [] },
|
||||
{ features = ["defmt"] }
|
||||
]
|
||||
clippy-configs = [
|
||||
{ features = ["defmt"] },
|
||||
]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
default-target = "riscv32imc-unknown-none-elf"
|
||||
features = ["nightly"]
|
||||
|
@ -10,6 +10,19 @@ categories = ["embedded", "hardware-support", "no-std"]
|
||||
repository = "https://github.com/esp-rs/esp-hal"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[package.metadata.espressif]
|
||||
doc-config = { features = ["defmt"] }
|
||||
check-configs = [
|
||||
{ features = ["println", "esp-println/auto"] },
|
||||
{ features = ["defmt"] },
|
||||
{ features = ["defmt", "panic-handler", "custom-halt"] },
|
||||
{ features = ["defmt", "panic-handler", "halt-cores"] },
|
||||
{ features = ["defmt", "panic-handler", "semihosting"] }
|
||||
]
|
||||
clippy-configs = [
|
||||
{ features = ["panic-handler", "halt-cores", "defmt"] },
|
||||
]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
default-target = "riscv32imc-unknown-none-elf"
|
||||
features = ["esp32c3", "panic-handler", "exception-handler", "println", "esp-println/uart"]
|
||||
@ -60,6 +73,7 @@ print-float-registers = [] # TODO support esp32p4
|
||||
# additional functionality:
|
||||
## Print messages in red
|
||||
colors = []
|
||||
# TODO: these features assume panic-handler is enabled but they don't enforce it.
|
||||
## Invoke the extern function `custom_halt()` instead of doing a loop {} in case of a panic. This feature does not imply the `halt-cores` feature.
|
||||
custom-halt = []
|
||||
## Invoke the extern function `custom_pre_backtrace()` before handling a panic
|
||||
|
@ -120,7 +120,7 @@ fn panic_handler(info: &core::panic::PanicInfo) -> ! {
|
||||
println!("0x{:x}", frame.program_counter());
|
||||
}
|
||||
|
||||
abort();
|
||||
abort()
|
||||
}
|
||||
|
||||
// Ensure that the address is in DRAM.
|
||||
@ -186,7 +186,7 @@ fn abort() -> ! {
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "semihosting")] {
|
||||
critical_section::with(|_| {
|
||||
arch::interrupt_free(|| {
|
||||
semihosting::process::abort();
|
||||
});
|
||||
} else if #[cfg(feature = "halt-cores")] {
|
||||
@ -201,5 +201,8 @@ fn abort() -> ! {
|
||||
}
|
||||
|
||||
#[allow(unreachable_code)]
|
||||
arch::interrupt_free(|| loop {})
|
||||
arch::interrupt_free(|| {
|
||||
#[allow(clippy::empty_loop)]
|
||||
loop {}
|
||||
})
|
||||
}
|
||||
|
@ -10,6 +10,17 @@ categories = ["embedded", "hardware-support", "no-std"]
|
||||
repository = "https://github.com/esp-rs/esp-hal"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[package.metadata.espressif]
|
||||
doc-config = { features = ["defmt", "validation"] }
|
||||
check-configs = [
|
||||
{ features = [] },
|
||||
{ features = ["log-04"] },
|
||||
{ features = ["defmt", "validation"] },
|
||||
]
|
||||
clippy-configs = [
|
||||
{ features = ["defmt", "validation"] },
|
||||
]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
default-target = "riscv32imac-unknown-none-elf"
|
||||
|
||||
|
@ -8,6 +8,16 @@ documentation = "https://docs.espressif.com/projects/rust/esp-config/latest/"
|
||||
repository = "https://github.com/esp-rs/esp-hal"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[package.metadata.espressif]
|
||||
doc-config = { features = ["build"] }
|
||||
check-configs = [
|
||||
{ features = [] },
|
||||
{ features = ["build"] },
|
||||
]
|
||||
clippy-configs = [
|
||||
{ features = ["tui"] },
|
||||
]
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
test = true
|
||||
|
@ -70,7 +70,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
.map(|entry| entry.file_name().to_string_lossy().to_string())
|
||||
.collect();
|
||||
|
||||
if files.len() > 0 {
|
||||
if !files.is_empty() {
|
||||
let terminal = tui::init_terminal()?;
|
||||
let mut chooser = tui::ConfigChooser::new(files);
|
||||
config_file = chooser.run(terminal)?;
|
||||
@ -134,7 +134,7 @@ fn apply_config(
|
||||
previous_cfg: Vec<CrateConfig>,
|
||||
config_toml_path: &PathBuf,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
let mut config = std::fs::read_to_string(&config_toml_path)?
|
||||
let mut config = std::fs::read_to_string(config_toml_path)?
|
||||
.as_str()
|
||||
.parse::<DocumentMut>()?;
|
||||
|
||||
@ -171,7 +171,7 @@ fn apply_config(
|
||||
}
|
||||
}
|
||||
|
||||
std::fs::write(&config_toml_path, config.to_string().as_bytes())?;
|
||||
std::fs::write(config_toml_path, config.to_string().as_bytes())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -10,6 +10,19 @@ categories = ["asynchronous", "embedded", "hardware-support", "no-std"]
|
||||
repository = "https://github.com/esp-rs/esp-hal"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[package.metadata.espressif]
|
||||
doc-config = { features = ["esp-hal/unstable", "esp-hal/rt", "defmt", "executors"] }
|
||||
check-configs = [
|
||||
{ features = ["esp-hal/unstable", "esp-hal/rt"] },
|
||||
{ features = ["esp-hal/unstable", "esp-hal/rt", "defmt"] },
|
||||
{ features = ["esp-hal/unstable", "esp-hal/rt", "log-04"] },
|
||||
{ features = ["esp-hal/unstable", "esp-hal/rt", "defmt", "executors"] },
|
||||
{ features = ["esp-hal/unstable", "esp-hal/rt", "log-04", "executors"] },
|
||||
]
|
||||
clippy-configs = [
|
||||
{ features = ["esp-hal/unstable", "esp-hal/rt", "log-04", "executors"] },
|
||||
]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
default-target = "riscv32imac-unknown-none-elf"
|
||||
features = ["esp32c6"]
|
||||
|
@ -8,6 +8,16 @@ documentation = "https://docs.espressif.com/projects/rust/esp-hal-procmacros/lat
|
||||
repository = "https://github.com/esp-rs/esp-hal"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[package.metadata.espressif]
|
||||
doc-config = { features = ["embassy"] }
|
||||
check-configs = [
|
||||
{ features = [] },
|
||||
{ features = ["embassy"] }
|
||||
]
|
||||
clippy-configs = [
|
||||
{ features = ["embassy"] },
|
||||
]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = ["embassy", "has-ulp-core", "interrupt", "ram", "is-ulp-core"]
|
||||
|
||||
|
@ -11,6 +11,30 @@ repository = "https://github.com/esp-rs/esp-hal"
|
||||
license = "MIT OR Apache-2.0"
|
||||
exclude = [ "api-baseline", "MIGRATING-*", "CHANGELOG.md" ]
|
||||
|
||||
[package.metadata.espressif]
|
||||
semver_checked = true
|
||||
doc-config = { features = ["unstable", "rt"], append = [
|
||||
{ if = 'chip_has("psram")', features = ["psram"] },
|
||||
{ if = 'chip_has("soc_has_usb0")', features = ["__usb_otg"] },
|
||||
{ if = 'chip_has("bt")', features = ["__bluetooth"] },
|
||||
] }
|
||||
check-configs = [
|
||||
{ features = [] },
|
||||
{ features = ["rt"] },
|
||||
{ features = ["unstable", "rt"] },
|
||||
{ features = ["unstable", "rt", "psram"], if = 'chip_has("psram")' },
|
||||
{ features = ["unstable", "rt", "__usb_otg"], if = 'chip_has("soc_has_usb0")' },
|
||||
{ features = ["unstable", "rt", "__bluetooth"], if = 'chip_has("bt")' },
|
||||
]
|
||||
# Prefer fewer, but more complex clippy rules. A clippy run should cover as much code as possible.
|
||||
clippy-configs = [
|
||||
{ features = ["unstable", "rt"], append = [
|
||||
{ if = 'chip_has("psram")', features = ["psram"] },
|
||||
{ if = 'chip_has("soc_has_usb0")', features = ["__usb_otg"] },
|
||||
{ if = 'chip_has("bt")', features = ["__bluetooth"] },
|
||||
] },
|
||||
]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
default-target = "riscv32imac-unknown-none-elf"
|
||||
features = ["esp32c6", "unstable"]
|
||||
|
@ -47,12 +47,14 @@
|
||||
use core::ops::Range;
|
||||
|
||||
#[cfg(feature = "psram")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "psram")))]
|
||||
#[cfg_attr(esp32, path = "esp32.rs")]
|
||||
#[cfg_attr(esp32s2, path = "esp32s2.rs")]
|
||||
#[cfg_attr(esp32s3, path = "esp32s3.rs")]
|
||||
pub(crate) mod implem;
|
||||
|
||||
#[cfg(feature = "psram")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "psram")))]
|
||||
pub use implem::*;
|
||||
|
||||
/// Size of PSRAM
|
||||
|
@ -15,6 +15,21 @@ default-target = "riscv32imac-unknown-none-elf"
|
||||
features = ["esp32c6"]
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
|
||||
[package.metadata.espressif]
|
||||
targets_lp_core = true
|
||||
doc-config = { features = ["embedded-hal"], append = [
|
||||
{ features = ["embedded-io"], if = 'chip_has("lp_core")' },
|
||||
] }
|
||||
check-configs = [
|
||||
{ features = [] },
|
||||
{ features = ["embedded-hal"] },
|
||||
{ features = ["embedded-io"] },
|
||||
{ features = ["embedded-hal", "embedded-io"] },
|
||||
]
|
||||
clippy-configs = [
|
||||
{ features = ["embedded-hal", "embedded-io"] },
|
||||
]
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
test = false
|
||||
|
@ -8,6 +8,13 @@ documentation = "https://docs.espressif.com/projects/rust/esp-metadata-generated
|
||||
repository = "https://github.com/esp-rs/esp-hal"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[package.metadata.espressif]
|
||||
check-configs = [
|
||||
{ features = [] },
|
||||
{ features = ["build-script"] },
|
||||
]
|
||||
clippy-configs = [] # don't waste time on this
|
||||
|
||||
[dependencies]
|
||||
|
||||
[build-dependencies]
|
||||
|
@ -8,6 +8,13 @@ documentation = "https://docs.espressif.com/projects/rust/esp-metadata/latest/"
|
||||
repository = "https://github.com/esp-rs/esp-hal"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[package.metadata.espressif]
|
||||
check-configs = [
|
||||
{ features = [] },
|
||||
{ features = ["clap"] },
|
||||
]
|
||||
clippy-configs = [] # don't waste time on this
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
clap = { version = "4.5", features = ["derive"], optional = true }
|
||||
|
@ -10,6 +10,16 @@ categories = ["embedded", "hardware-support", "no-std"]
|
||||
repository = "https://github.com/esp-rs/esp-hal"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[package.metadata.espressif]
|
||||
doc-config = { features = ["esp-hal/unstable"] }
|
||||
check-configs = [
|
||||
{ features = ["esp-hal/unstable"] },
|
||||
{ features = ["esp-hal/unstable", "esp-alloc"] },
|
||||
]
|
||||
clippy-configs = [
|
||||
{ features = ["esp-hal/unstable", "esp-alloc", "defmt"] },
|
||||
]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
default-target = "riscv32imac-unknown-none-elf"
|
||||
features = ["esp32c6"]
|
||||
|
@ -11,6 +11,21 @@ repository = "https://github.com/esp-rs/esp-hal"
|
||||
license = "MIT OR Apache-2.0"
|
||||
links = "esp-println"
|
||||
|
||||
[package.metadata.espressif]
|
||||
doc-config = { features = ["auto", "defmt-espflash", "critical-section"] }
|
||||
check-configs = [
|
||||
{ features = ["auto"] },
|
||||
{ features = ["jtag-serial"], if = 'chip_has("soc_has_usb_serial_jtag")' },
|
||||
{ features = ["uart"] },
|
||||
{ features = ["no-op"] },
|
||||
{ features = ["auto", "log-04", "timestamp"] },
|
||||
{ features = ["auto", "defmt-espflash", "timestamp"] },
|
||||
]
|
||||
clippy-configs = [
|
||||
{ features = ["auto", "log-04", "timestamp"] },
|
||||
{ features = ["auto", "defmt-espflash", "timestamp"] },
|
||||
]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
cargo-args = ["-Z", "build-std=core"]
|
||||
default-target = "riscv32imc-unknown-none-elf"
|
||||
|
@ -15,7 +15,7 @@ macro_rules! assert_unique_used_features {
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
// Ensure that only a single communication method is specified
|
||||
assert_unique_used_features!("jtag-serial", "uart", "auto");
|
||||
assert_unique_used_features!("jtag-serial", "uart", "auto", "no-op");
|
||||
|
||||
let chip = esp_metadata_generated::Chip::from_cargo_feature()?;
|
||||
// Ensure that, if the `jtag-serial` communication method feature is enabled,
|
||||
|
@ -129,6 +129,9 @@ type PrinterImpl = uart_printer::Printer;
|
||||
#[cfg(feature = "auto")]
|
||||
type PrinterImpl = auto_printer::Printer;
|
||||
|
||||
#[cfg(feature = "no-op")]
|
||||
type PrinterImpl = noop::Printer;
|
||||
|
||||
#[cfg(all(
|
||||
feature = "auto",
|
||||
any(
|
||||
@ -469,6 +472,17 @@ mod uart_printer {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "no-op")]
|
||||
mod noop {
|
||||
pub struct Printer;
|
||||
|
||||
impl Printer {
|
||||
pub fn write_bytes_in_cs(_bytes: &[u8], _token: super::LockToken<'_>) {}
|
||||
|
||||
pub fn flush(_token: super::LockToken<'_>) {}
|
||||
}
|
||||
}
|
||||
|
||||
use core::marker::PhantomData;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
|
@ -52,7 +52,7 @@ impl log::Log for EspEnvLogger {
|
||||
|
||||
#[allow(unused)]
|
||||
fn log(&self, record: &log::Record) {
|
||||
if self.enabled(&record.metadata()) {
|
||||
if self.enabled(record.metadata()) {
|
||||
print_log_record(record);
|
||||
}
|
||||
}
|
||||
@ -61,28 +61,26 @@ impl log::Log for EspEnvLogger {
|
||||
}
|
||||
|
||||
fn print_log_record(record: &log::Record) {
|
||||
const RESET: &str = "\u{001B}[0m";
|
||||
const RED: &str = "\u{001B}[31m";
|
||||
const GREEN: &str = "\u{001B}[32m";
|
||||
const YELLOW: &str = "\u{001B}[33m";
|
||||
const BLUE: &str = "\u{001B}[34m";
|
||||
const CYAN: &str = "\u{001B}[35m";
|
||||
let (color, reset) = if cfg!(feature = "colors") {
|
||||
const RESET: &str = "\u{001B}[0m";
|
||||
const RED: &str = "\u{001B}[31m";
|
||||
const GREEN: &str = "\u{001B}[32m";
|
||||
const YELLOW: &str = "\u{001B}[33m";
|
||||
const BLUE: &str = "\u{001B}[34m";
|
||||
const CYAN: &str = "\u{001B}[35m";
|
||||
|
||||
#[cfg(feature = "colors")]
|
||||
let color = match record.level() {
|
||||
log::Level::Error => RED,
|
||||
log::Level::Warn => YELLOW,
|
||||
log::Level::Info => GREEN,
|
||||
log::Level::Debug => BLUE,
|
||||
log::Level::Trace => CYAN,
|
||||
let color = match record.level() {
|
||||
log::Level::Error => RED,
|
||||
log::Level::Warn => YELLOW,
|
||||
log::Level::Info => GREEN,
|
||||
log::Level::Debug => BLUE,
|
||||
log::Level::Trace => CYAN,
|
||||
};
|
||||
let reset = RESET;
|
||||
(color, reset)
|
||||
} else {
|
||||
("", "")
|
||||
};
|
||||
#[cfg(feature = "colors")]
|
||||
let reset = RESET;
|
||||
|
||||
#[cfg(not(feature = "colors"))]
|
||||
let color = "";
|
||||
#[cfg(not(feature = "colors"))]
|
||||
let reset = "";
|
||||
|
||||
#[cfg(feature = "timestamp")]
|
||||
println!(
|
||||
|
@ -10,4 +10,8 @@ categories = ["embedded", "hardware-support", "no-std"]
|
||||
repository = "https://github.com/esp-rs/esp-hal"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[package.metadata.espressif]
|
||||
check-configs = [{ features = [] }]
|
||||
clippy-configs = [{ features = [] }]
|
||||
|
||||
[dependencies]
|
||||
|
@ -10,6 +10,30 @@ categories = ["embedded", "hardware-support", "no-std"]
|
||||
repository = "https://github.com/esp-rs/esp-hal"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[package.metadata.espressif]
|
||||
doc-config = { features = ["esp-hal/unstable", "esp-hal/rt", "defmt"], append = [
|
||||
{ if = 'chip_has("wifi")', features = ["wifi", "wifi-eap", "esp-now", "sniffer", "smoltcp/proto-ipv4", "smoltcp/proto-ipv6"] },
|
||||
{ if = 'chip_has("bt")', features = ["ble"] },
|
||||
{ if = 'chip_has("ieee802154")', features = ["ieee802154", "__docs_build"] },
|
||||
{ if = 'chip_has("wifi") && chip_has("bt")', features = ["coex"] },
|
||||
{ if = 'chip_has("wifi") || chip_has("bt") || chip_has("ieee802154")', features = ["unstable"] },
|
||||
] }
|
||||
check-configs = [
|
||||
{ features = ["esp-hal/unstable", "esp-hal/rt"] },
|
||||
{ features = ["esp-hal/unstable", "esp-hal/rt", "defmt"] },
|
||||
{ features = ["esp-hal/unstable", "esp-hal/rt", "wifi"], if = 'chip_has("wifi")' },
|
||||
{ features = ["esp-hal/unstable", "esp-hal/rt", "unstable", "defmt", "wifi", "wifi-eap", "esp-now", "sniffer", "smoltcp/proto-ipv4", "smoltcp/proto-ipv6"], if = 'chip_has("wifi")' },
|
||||
{ features = ["esp-hal/unstable", "esp-hal/rt", "unstable", "ble"], if = 'chip_has("bt")' },
|
||||
{ features = ["esp-hal/unstable", "esp-hal/rt", "unstable", "ieee802154"], if = 'chip_has("ieee802154")' },
|
||||
{ features = ["esp-hal/unstable", "esp-hal/rt", "unstable", "defmt", "wifi", "wifi-eap", "esp-now", "sniffer", "smoltcp/proto-ipv4", "smoltcp/proto-ipv6", "ble", "coex"], if = 'chip_has("wifi") && chip_has("bt")' },
|
||||
{ features = ["esp-hal/unstable", "esp-hal/rt", "wifi-eap", "unstable"], if = 'chip_has("wifi")' },
|
||||
]
|
||||
clippy-configs = [
|
||||
{ features = ["esp-hal/unstable", "esp-hal/rt"] },
|
||||
{ features = ["esp-hal/unstable", "esp-hal/rt", "wifi"], if = 'chip_has("wifi")' },
|
||||
{ features = ["esp-hal/unstable", "esp-hal/rt", "wifi-eap", "unstable"], if = 'chip_has("wifi")' },
|
||||
]
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
test = false
|
||||
|
@ -11,6 +11,17 @@ repository = "https://github.com/esp-rs/esp-hal"
|
||||
license = "MIT OR Apache-2.0"
|
||||
links = "esp-riscv-rt"
|
||||
|
||||
[package.metadata.espressif]
|
||||
doc-config = { features = ["rtc-ram"] }
|
||||
requires_target = ["riscv32imc-unknown-none-elf", "riscv32imac-unknown-none-elf"]
|
||||
check-configs = [
|
||||
{ features = [] },
|
||||
{ features = ["rtc-ram"] },
|
||||
{ features = ["no-mie-mip"] },
|
||||
{ features = ["rtc-ram", "no-mie-mip"] },
|
||||
]
|
||||
clippy-configs = [{ features = ["rtc-ram"] }]
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
test = false
|
||||
|
@ -12,6 +12,10 @@ license = "MIT OR Apache-2.0"
|
||||
|
||||
links = "esp_rom_sys"
|
||||
|
||||
[package.metadata.espressif]
|
||||
check-configs = [{ features = [] }]
|
||||
clippy-configs = [{ features = [] }]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
default-target = "riscv32imac-unknown-none-elf"
|
||||
features = ["esp32c6"]
|
||||
|
@ -10,6 +10,25 @@ categories = ["embedded", "hardware-support", "no-std"]
|
||||
repository = "https://github.com/esp-rs/esp-hal"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[package.metadata.espressif]
|
||||
check-configs = [
|
||||
{ features = [], append = [
|
||||
{ features = ["portable-atomic/unsafe-assume-single-core"], if = 'chip == "esp32c2" || chip == "esp32c3" || chip == "esp32s2"' }
|
||||
] },
|
||||
{ features = ["critical-section"], append = [
|
||||
{ features = ["portable-atomic/unsafe-assume-single-core"], if = 'chip == "esp32c2" || chip == "esp32c3" || chip == "esp32s2"' }
|
||||
] },
|
||||
{ features = ["bytewise-read"], append = [
|
||||
{ features = ["portable-atomic/unsafe-assume-single-core"], if = 'chip == "esp32c2" || chip == "esp32c3" || chip == "esp32s2"' }
|
||||
] },
|
||||
{ features = ["critical-section", "bytewise-read"], append = [
|
||||
{ features = ["portable-atomic/unsafe-assume-single-core"], if = 'chip == "esp32c2" || chip == "esp32c3" || chip == "esp32s2"' }
|
||||
] },
|
||||
]
|
||||
clippy-configs = [{ features = ["critical-section", "bytewise-read"], append = [
|
||||
{ features = ["portable-atomic/unsafe-assume-single-core"], if = 'chip == "esp32c2" || chip == "esp32c3" || chip == "esp32s2"' }
|
||||
]}]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
default-target = "riscv32imac-unknown-none-elf"
|
||||
features = ["esp32c6"]
|
||||
|
@ -25,7 +25,7 @@ fn maybe_with_critical_section<R>(f: impl FnOnce() -> R) -> R {
|
||||
{
|
||||
static LOCK: esp_sync::RawMutex = esp_sync::RawMutex::new();
|
||||
|
||||
return LOCK.lock(f);
|
||||
LOCK.lock(f)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "critical-section"))]
|
||||
|
@ -10,6 +10,14 @@ repository = "https://github.com/esp-rs/esp-hal"
|
||||
license = "MIT OR Apache-2.0"
|
||||
exclude = [ "MIGRATING-*", "CHANGELOG.md" ]
|
||||
|
||||
[package.metadata.espressif]
|
||||
check-configs = [
|
||||
{ features = [] },
|
||||
{ features = ["log-04"] },
|
||||
{ features = ["defmt"] },
|
||||
]
|
||||
clippy-configs = [{ features = ["defmt"] }]
|
||||
|
||||
[dependencies]
|
||||
cfg-if = "1"
|
||||
document-features = "0.2"
|
||||
|
@ -16,12 +16,14 @@ kuchikiki = { version = "0.8.2", optional = true }
|
||||
log = "0.4.22"
|
||||
minijinja = { version = "2.5.0", default-features = false }
|
||||
opener = { version = "0.7.2", optional = true }
|
||||
parking_lot = "0.12.3"
|
||||
prettyplease = { version = "0.2.34" }
|
||||
regex = { version = "1.11.1", optional = true }
|
||||
rocket = { version = "0.5.1", optional = true }
|
||||
semver = { version = "1.0.23", features = ["serde"] }
|
||||
serde = { version = "1.0.215", default-features = false, features = ["derive"] }
|
||||
serde_json = "1.0.70"
|
||||
somni-expr = { version = "0.1.0" }
|
||||
strum = { version = "0.27.1", features = ["derive"] }
|
||||
syn = { version = "2", default-features = false, features = ["full", "parsing"] }
|
||||
toml_edit = { version = "0.22.22", features = ["serde"] }
|
||||
|
@ -10,7 +10,7 @@ use std::{
|
||||
use anyhow::{Context as _, Result, bail};
|
||||
use clap::ValueEnum as _;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use toml_edit::{DocumentMut, Formatted, Item, Value};
|
||||
use toml_edit::{DocumentMut, Formatted, Item, Table, Value};
|
||||
|
||||
use crate::{Package, windows_safe_path};
|
||||
|
||||
@ -367,29 +367,19 @@ impl CargoCommandBatcher {
|
||||
}
|
||||
|
||||
let mut command = Vec::new();
|
||||
|
||||
if let Some(tc) = key.toolchain.as_ref() {
|
||||
command.push(format!("+{tc}"));
|
||||
}
|
||||
|
||||
command.push("batch".to_string());
|
||||
if !key.config_file.is_empty()
|
||||
&& let Some(config_path) = &group[0].config_path
|
||||
{
|
||||
// All grouped projects have the same config file content, pick one:
|
||||
command.push("--config".to_string());
|
||||
command.push(config_path.display().to_string());
|
||||
}
|
||||
|
||||
let mut batch_len = 0;
|
||||
let mut commands_in_batch = 0;
|
||||
|
||||
command.extend_from_slice(&key.config);
|
||||
// Windows be Windows, it has a command length limit.
|
||||
let limit = if cfg!(target_os = "windows") {
|
||||
Some(8191)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
for item in group.iter() {
|
||||
// Only build and doc can be batched
|
||||
let batchable = [
|
||||
"build", "doc",
|
||||
// "check" // soon(TM)
|
||||
];
|
||||
// Only some commands can be batched
|
||||
let batchable = ["build", "doc", "check"];
|
||||
if !batchable
|
||||
.iter()
|
||||
.any(|&subcommand| subcommand == item.subcommand)
|
||||
@ -398,16 +388,56 @@ impl CargoCommandBatcher {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Build the new command
|
||||
let mut c = item.clone();
|
||||
|
||||
c.toolchain = None;
|
||||
c.configs = Vec::new();
|
||||
c.config_path = None;
|
||||
|
||||
let args = c.build();
|
||||
|
||||
let command_chars = 4 + args.iter().map(|arg| arg.len() + 1).sum::<usize>();
|
||||
|
||||
if !command.is_empty()
|
||||
&& let Some(limit) = limit
|
||||
&& batch_len + command_chars > limit
|
||||
{
|
||||
// Command would be too long, cut here.
|
||||
all.push(BuiltCommand {
|
||||
artifact_name: String::from("batch"),
|
||||
command: std::mem::take(&mut command),
|
||||
env_vars: key.env_vars.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
// Set up head part if empty
|
||||
if command.is_empty() {
|
||||
if let Some(tc) = key.toolchain.as_ref() {
|
||||
command.push(format!("+{tc}"));
|
||||
}
|
||||
|
||||
command.push("batch".to_string());
|
||||
if !key.config_file.is_empty()
|
||||
&& let Some(config_path) = &group[0].config_path
|
||||
{
|
||||
// All grouped projects have the same config file content, pick one:
|
||||
command.push("--config".to_string());
|
||||
command.push(config_path.display().to_string());
|
||||
}
|
||||
command.extend_from_slice(&key.config);
|
||||
|
||||
commands_in_batch = 0;
|
||||
batch_len = command.iter().map(|s| s.len() + 1).sum::<usize>() - 1;
|
||||
}
|
||||
|
||||
// Append the new command
|
||||
|
||||
command.push("---".to_string());
|
||||
command.extend_from_slice(&c.build());
|
||||
command.extend_from_slice(&args);
|
||||
|
||||
commands_in_batch += 1;
|
||||
batch_len += command_chars;
|
||||
}
|
||||
|
||||
if commands_in_batch > 0 {
|
||||
@ -484,9 +514,9 @@ impl Drop for CargoCommandBatcher {
|
||||
}
|
||||
|
||||
/// A representation of a Cargo.toml file for a specific package.
|
||||
pub struct CargoToml<'a> {
|
||||
pub struct CargoToml {
|
||||
/// The workspace path where the Cargo.toml is located.
|
||||
pub workspace: &'a Path,
|
||||
pub workspace: PathBuf,
|
||||
/// The package this Cargo.toml belongs to.
|
||||
pub package: Package,
|
||||
/// The parsed Cargo.toml manifest.
|
||||
@ -496,9 +526,9 @@ pub struct CargoToml<'a> {
|
||||
const DEPENDENCY_KINDS: [&'static str; 3] =
|
||||
["dependencies", "dev-dependencies", "build-dependencies"];
|
||||
|
||||
impl<'a> CargoToml<'a> {
|
||||
impl CargoToml {
|
||||
/// Load and parse the Cargo.toml for the specified package in the given workspace.
|
||||
pub fn new(workspace: &'a Path, package: Package) -> Result<Self> {
|
||||
pub fn new(workspace: &Path, package: Package) -> Result<Self> {
|
||||
let package_path = workspace.join(package.to_string());
|
||||
let manifest_path = package_path.join("Cargo.toml");
|
||||
if !manifest_path.exists() {
|
||||
@ -514,11 +544,24 @@ impl<'a> CargoToml<'a> {
|
||||
Self::from_str(workspace, package, &manifest)
|
||||
}
|
||||
|
||||
pub fn espressif_metadata(&self) -> Option<&Table> {
|
||||
let Some(package) = self.manifest.get("package") else {
|
||||
return None;
|
||||
};
|
||||
let Some(metadata) = package.get("metadata") else {
|
||||
return None;
|
||||
};
|
||||
let Some(espressif) = metadata.get("espressif") else {
|
||||
return None;
|
||||
};
|
||||
Some(espressif.as_table()?)
|
||||
}
|
||||
|
||||
/// Create a `CargoToml` instance from a manifest string.
|
||||
pub fn from_str(workspace: &'a Path, package: Package, manifest: &str) -> Result<Self> {
|
||||
pub fn from_str(workspace: &Path, package: Package, manifest: &str) -> Result<Self> {
|
||||
// Parse the manifest string into a mutable TOML document.
|
||||
Ok(Self {
|
||||
workspace,
|
||||
workspace: workspace.to_path_buf(),
|
||||
package,
|
||||
manifest: manifest
|
||||
.parse::<DocumentMut>()
|
||||
|
@ -65,7 +65,7 @@ pub fn bump_version(workspace: &Path, args: BumpVersionArgs) -> Result<()> {
|
||||
|
||||
/// Update the specified package by bumping its version, updating its changelog,
|
||||
pub fn update_package(
|
||||
package: &mut CargoToml<'_>,
|
||||
package: &mut CargoToml,
|
||||
version: &VersionBump,
|
||||
dry_run: bool,
|
||||
) -> Result<semver::Version> {
|
||||
@ -77,7 +77,7 @@ pub fn update_package(
|
||||
Ok(new_version)
|
||||
}
|
||||
|
||||
fn check_crate_before_bumping(manifest: &mut CargoToml<'_>) -> Result<()> {
|
||||
fn check_crate_before_bumping(manifest: &mut CargoToml) -> Result<()> {
|
||||
// Collect errors into a vector to preserve order.
|
||||
let mut errors = Vec::new();
|
||||
|
||||
@ -175,7 +175,7 @@ fn check_dependency_before_bumping(item: &Item) -> Result<()> {
|
||||
|
||||
/// Bump the version of the specified package by the specified amount.
|
||||
fn bump_crate_version(
|
||||
bumped_package: &mut CargoToml<'_>,
|
||||
bumped_package: &mut CargoToml,
|
||||
amount: &VersionBump,
|
||||
dry_run: bool,
|
||||
) -> Result<semver::Version> {
|
||||
@ -197,7 +197,7 @@ fn bump_crate_version(
|
||||
|
||||
let package_name = bumped_package.package.to_string();
|
||||
for pkg in Package::iter() {
|
||||
let mut dependent = CargoToml::new(bumped_package.workspace, pkg)
|
||||
let mut dependent = CargoToml::new(&bumped_package.workspace, pkg)
|
||||
.with_context(|| format!("Could not load Cargo.toml of {pkg}"))?;
|
||||
|
||||
if dependent.change_version_of_dependency(&package_name, &version) {
|
||||
@ -268,7 +268,7 @@ pub fn do_version_bump(version: &semver::Version, amount: &VersionBump) -> Resul
|
||||
}
|
||||
|
||||
fn finalize_changelog(
|
||||
bumped_package: &CargoToml<'_>,
|
||||
bumped_package: &CargoToml,
|
||||
new_version: &semver::Version,
|
||||
dry_run: bool,
|
||||
) -> Result<()> {
|
||||
@ -306,7 +306,7 @@ fn finalize_changelog(
|
||||
}
|
||||
|
||||
fn finalize_placeholders(
|
||||
bumped_package: &CargoToml<'_>,
|
||||
bumped_package: &CargoToml,
|
||||
new_version: &semver::Version,
|
||||
dry_run: bool,
|
||||
) -> Result<()> {
|
||||
@ -405,7 +405,7 @@ mod tests {
|
||||
let mut doc = CargoToml {
|
||||
manifest: toml.parse::<DocumentMut>().unwrap(),
|
||||
package: Package::EspHal,
|
||||
workspace: Path::new(""),
|
||||
workspace: PathBuf::new(),
|
||||
};
|
||||
let errors = check_crate_before_bumping(&mut doc);
|
||||
pretty_assertions::assert_eq!(
|
||||
|
@ -81,7 +81,7 @@ pub fn plan(workspace: &Path, args: PlanArgs) -> Result<()> {
|
||||
let mut packages_to_release = args
|
||||
.packages
|
||||
.iter()
|
||||
.filter(|p| p.is_published(workspace))
|
||||
.filter(|p| p.is_published())
|
||||
.flat_map(|p| related_crates(workspace, *p))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
|
@ -23,7 +23,7 @@ pub fn publish(workspace: &Path, args: PublishArgs) -> Result<()> {
|
||||
let package_path = windows_safe_path(&workspace.join(&package_name));
|
||||
|
||||
ensure!(
|
||||
args.package.is_published(workspace),
|
||||
args.package.is_published(),
|
||||
"Invalid package '{}' specified, this package should not be published!",
|
||||
args.package
|
||||
);
|
||||
|
@ -33,7 +33,7 @@ pub fn tag_releases(workspace: &Path, mut args: TagReleasesArgs) -> Result<()> {
|
||||
// If a package does not require documentation, this also means that it is not
|
||||
// published (maybe this function needs a better name), so we can skip tagging
|
||||
// it:
|
||||
if !package.is_published(workspace) {
|
||||
if !package.is_published() {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,7 @@ pub fn run_doc_tests(workspace: &Path, args: DocTestArgs) -> Result<()> {
|
||||
let target = args.package.target_triple(&chip)?;
|
||||
let mut features = args
|
||||
.package
|
||||
.feature_rules(&esp_metadata::Config::for_chip(&chip));
|
||||
.doc_feature_rules(&esp_metadata::Config::for_chip(&chip));
|
||||
features.push(chip.to_string());
|
||||
|
||||
// We need `nightly` for building the doc tests, unfortunately:
|
||||
|
@ -39,7 +39,7 @@ pub fn build_documentation(
|
||||
|
||||
for package in packages {
|
||||
// Not all packages need documentation built:
|
||||
if !package.is_published(workspace) {
|
||||
if !package.is_published() {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -205,9 +205,9 @@ fn cargo_doc(workspace: &Path, package: Package, chip: Option<Chip>) -> Result<P
|
||||
let mut features = vec![];
|
||||
if let Some(chip) = &chip {
|
||||
features.push(chip.to_string());
|
||||
features.extend(package.feature_rules(Config::for_chip(chip)));
|
||||
features.extend(package.doc_feature_rules(Config::for_chip(chip)));
|
||||
} else {
|
||||
features.extend(package.feature_rules(&Config::empty()));
|
||||
features.extend(package.doc_feature_rules(&Config::empty()));
|
||||
}
|
||||
|
||||
// Build up an array of command-line arguments to pass to `cargo`:
|
||||
@ -326,7 +326,7 @@ pub fn build_documentation_index(workspace: &Path, packages: &mut [Package]) ->
|
||||
for package in packages {
|
||||
log::debug!("Building documentation index for package '{package}'");
|
||||
// Not all packages have documentation built:
|
||||
if !package.is_published(workspace) {
|
||||
if !package.is_published() {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -462,7 +462,7 @@ fn generate_documentation_meta_for_index(workspace: &Path) -> Result<Vec<Value>>
|
||||
|
||||
for package in Package::iter() {
|
||||
// Not all packages have documentation built:
|
||||
if !package.is_published(workspace) {
|
||||
if !package.is_published() {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
454
xtask/src/lib.rs
454
xtask/src/lib.rs
@ -1,4 +1,5 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
@ -6,7 +7,9 @@ use std::{
|
||||
use anyhow::{Context, Result, anyhow};
|
||||
use cargo::CargoAction;
|
||||
use esp_metadata::{Chip, Config, TokenStream};
|
||||
use parking_lot::{MappedMutexGuard, Mutex, MutexGuard};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use toml_edit::{InlineTable, Item, Value};
|
||||
|
||||
use crate::{
|
||||
cargo::{CargoArgsBuilder, CargoCommandBatcher, CargoToml},
|
||||
@ -72,24 +75,31 @@ pub enum Package {
|
||||
impl Package {
|
||||
/// Does the package have chip-specific cargo features?
|
||||
pub fn has_chip_features(&self) -> bool {
|
||||
use Package::*;
|
||||
use strum::IntoEnumIterator;
|
||||
let chips = Chip::iter()
|
||||
.map(|chip| chip.to_string())
|
||||
.collect::<Vec<_>>();
|
||||
let toml = self.toml();
|
||||
let Some(Item::Table(features)) = toml.manifest.get("features") else {
|
||||
return false;
|
||||
};
|
||||
|
||||
matches!(
|
||||
self,
|
||||
EspBacktrace
|
||||
| EspBootloaderEspIdf
|
||||
| EspAlloc
|
||||
| EspHal
|
||||
| EspHalEmbassy
|
||||
| EspMetadataGenerated
|
||||
| EspRomSys
|
||||
| EspLpHal
|
||||
| EspPrintln
|
||||
| EspPreempt
|
||||
| EspStorage
|
||||
| EspSync
|
||||
| EspRadio
|
||||
)
|
||||
// This is intended to opt-out in case there are features that look like chip names, but
|
||||
// aren't supposed to be handled like them.
|
||||
if let Some(metadata) = toml.espressif_metadata() {
|
||||
if let Some(Item::Value(ov)) = metadata.get("has_chip_features") {
|
||||
let Value::Boolean(ov) = ov else {
|
||||
log::warn!("Invalid value for 'has_chip_features' in metadata");
|
||||
return false;
|
||||
};
|
||||
|
||||
return *ov.value();
|
||||
}
|
||||
}
|
||||
|
||||
features
|
||||
.iter()
|
||||
.any(|(feature, _)| chips.iter().any(|c| c == feature))
|
||||
}
|
||||
|
||||
/// Does the package have inline assembly?
|
||||
@ -177,18 +187,13 @@ impl Package {
|
||||
|
||||
/// Should documentation be built for the package, and should the package be
|
||||
/// published?
|
||||
pub fn is_published(&self, workspace: &Path) -> bool {
|
||||
pub fn is_published(&self) -> bool {
|
||||
if *self == Package::Examples {
|
||||
// The `examples/` directory does not contain `Cargo.toml` in its root, and even if it
|
||||
// did nothing in this directory will be published.
|
||||
false
|
||||
} else {
|
||||
// TODO: we should use some sort of cache instead of parsing the TOML every
|
||||
// time, but for now this should be good enough.
|
||||
let toml =
|
||||
crate::cargo::CargoToml::new(workspace, *self).expect("Failed to parse Cargo.toml");
|
||||
|
||||
toml.is_published()
|
||||
self.toml().is_published()
|
||||
}
|
||||
}
|
||||
|
||||
@ -201,225 +206,192 @@ impl Package {
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a device config, return the features which should be enabled for
|
||||
/// this package.
|
||||
pub fn feature_rules(&self, config: &Config) -> Vec<String> {
|
||||
let mut features = vec![];
|
||||
match self {
|
||||
Package::EspBacktrace => features.push("defmt".to_owned()),
|
||||
Package::EspConfig => features.push("build".to_owned()),
|
||||
Package::EspHal => {
|
||||
features.push("unstable".to_owned());
|
||||
features.push("rt".to_owned());
|
||||
if config.contains("psram") {
|
||||
// TODO this doesn't test octal psram (since `ESP_HAL_CONFIG_PSRAM_MODE`
|
||||
// defaults to `quad`) as it would require a separate build
|
||||
features.push("psram".to_owned())
|
||||
}
|
||||
if config.contains("usb0") {
|
||||
features.push("__usb_otg".to_owned());
|
||||
}
|
||||
if config.contains("bt") {
|
||||
features.push("__bluetooth".to_owned());
|
||||
}
|
||||
fn parse_conditional_features(table: &InlineTable, config: &Config) -> Option<Vec<String>> {
|
||||
let mut eval_context = somni_expr::Context::new();
|
||||
eval_context.add_function("chip_has", |symbol: &str| {
|
||||
config.all().iter().any(|sym| sym == symbol)
|
||||
});
|
||||
eval_context.add_variable("chip", config.name());
|
||||
|
||||
if let Some(condition) = table.get("if") {
|
||||
let Some(expr) = condition.as_str() else {
|
||||
panic!("`if` condition must be a string.");
|
||||
};
|
||||
|
||||
if !eval_context
|
||||
.evaluate::<bool>(expr)
|
||||
.expect("Failed to evaluate expression")
|
||||
{
|
||||
return None;
|
||||
}
|
||||
Package::EspRadio => {
|
||||
features.push("esp-hal/unstable".to_owned());
|
||||
features.push("esp-hal/rt".to_owned());
|
||||
features.push("defmt".to_owned());
|
||||
if config.contains("wifi") {
|
||||
features.push("wifi".to_owned());
|
||||
features.push("wifi-eap".to_owned());
|
||||
features.push("esp-now".to_owned());
|
||||
features.push("sniffer".to_owned());
|
||||
features.push("smoltcp/proto-ipv4".to_owned());
|
||||
features.push("smoltcp/proto-ipv6".to_owned());
|
||||
}
|
||||
if config.contains("bt") {
|
||||
features.push("ble".to_owned());
|
||||
}
|
||||
if config.contains("ieee802154") {
|
||||
features.push("ieee802154".to_owned());
|
||||
// allow wifi + 802.15.4
|
||||
features.push("__docs_build".to_owned());
|
||||
}
|
||||
if config.contains("wifi") && config.contains("bt") {
|
||||
features.push("coex".to_owned());
|
||||
}
|
||||
if features.iter().any(|f| {
|
||||
f == "csi"
|
||||
|| f == "ble"
|
||||
|| f == "esp-now"
|
||||
|| f == "sniffer"
|
||||
|| f == "coex"
|
||||
|| f == "ieee802154"
|
||||
}) {
|
||||
features.push("unstable".to_owned());
|
||||
}
|
||||
}
|
||||
Package::EspHalProcmacros => {
|
||||
features.push("embassy".to_owned());
|
||||
}
|
||||
Package::EspHalEmbassy => {
|
||||
features.push("esp-hal/unstable".to_owned());
|
||||
features.push("esp-hal/rt".to_owned());
|
||||
features.push("defmt".to_owned());
|
||||
features.push("executors".to_owned());
|
||||
}
|
||||
Package::EspLpHal => {
|
||||
if config.contains("lp_core") {
|
||||
features.push("embedded-io".to_owned());
|
||||
}
|
||||
features.push("embedded-hal".to_owned());
|
||||
}
|
||||
Package::EspPrintln => {
|
||||
features.push("auto".to_owned());
|
||||
features.push("defmt-espflash".to_owned());
|
||||
features.push("critical-section".to_owned());
|
||||
}
|
||||
Package::EspStorage => {
|
||||
if config.name() == "esp32c2"
|
||||
|| config.name() == "esp32c3"
|
||||
|| config.name() == "esp32s2"
|
||||
{
|
||||
features.push("portable-atomic/unsafe-assume-single-core".to_owned());
|
||||
}
|
||||
}
|
||||
Package::EspBootloaderEspIdf => {
|
||||
features.push("defmt".to_owned());
|
||||
features.push("validation".to_owned());
|
||||
}
|
||||
Package::EspAlloc => {
|
||||
features.push("defmt".to_owned());
|
||||
}
|
||||
Package::EspMetadataGenerated => {}
|
||||
Package::EspPreempt => features.push("esp-hal/unstable".to_owned()),
|
||||
Package::EspRiscvRt => features.push("rtc-ram".to_owned()),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
log::debug!("Features for package '{}': {:?}", self, features);
|
||||
let Some(config_features) = table.get("features") else {
|
||||
panic!("Missing features array.");
|
||||
};
|
||||
let Value::Array(config_features) = config_features else {
|
||||
panic!("features must be an array.");
|
||||
};
|
||||
|
||||
let mut features = Vec::new();
|
||||
for feature in config_features {
|
||||
let feature = feature.as_str().expect("features must be strings.");
|
||||
features.push(feature.to_owned());
|
||||
}
|
||||
|
||||
Some(features)
|
||||
}
|
||||
|
||||
fn parse_feature_set(table: &InlineTable, config: &Config) -> Option<Vec<String>> {
|
||||
// Base features. If their condition is not met, the whole item is ignored.
|
||||
let mut features = Self::parse_conditional_features(table, config)?;
|
||||
|
||||
if let Some(conditionals) = table.get("append") {
|
||||
// Optional features. If their conditions are met, they are appended to the base
|
||||
// features.
|
||||
let Value::Array(conditionals) = conditionals else {
|
||||
panic!("append must be an array.");
|
||||
};
|
||||
for cond in conditionals {
|
||||
let Value::InlineTable(cond_table) = cond else {
|
||||
panic!("append items must be inline tables.");
|
||||
};
|
||||
if let Some(cond_features) = Self::parse_conditional_features(cond_table, config) {
|
||||
features.extend(cond_features);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Some(features)
|
||||
}
|
||||
|
||||
/// Given a device config, return the features which should be enabled for
|
||||
/// this package.
|
||||
///
|
||||
/// Features are read from Cargo.toml metadata, from the `doc-config` table. Currently only
|
||||
/// one feature set is supported.
|
||||
// TODO: perhaps we should use the docs.rs metadata for doc features for packages that have no
|
||||
// chip-specific features.
|
||||
pub fn doc_feature_rules(&self, config: &Config) -> Vec<String> {
|
||||
let mut features = vec![];
|
||||
|
||||
let toml = self.toml();
|
||||
if let Some(metadata) = toml.espressif_metadata()
|
||||
&& let Some(config_meta) = metadata.get("doc-config")
|
||||
{
|
||||
let Item::Value(Value::InlineTable(table)) = config_meta else {
|
||||
panic!("doc-config must be inline tables.");
|
||||
};
|
||||
|
||||
if let Some(fs) = Self::parse_feature_set(table, config) {
|
||||
features = fs;
|
||||
}
|
||||
} else {
|
||||
// Nothing
|
||||
}
|
||||
|
||||
log::debug!("Doc features for package '{}': {:?}", self, features);
|
||||
features
|
||||
}
|
||||
|
||||
/// Additional feature rules to test subsets of features for a package.
|
||||
pub fn check_feature_rules(&self, config: &Config) -> Vec<Vec<String>> {
|
||||
let mut cases = Vec::new();
|
||||
let mut cases = vec![];
|
||||
|
||||
// For now we run a lot of checks, but that will change.
|
||||
cases.push(self.feature_rules(config));
|
||||
let toml = self.toml();
|
||||
if let Some(metadata) = toml.espressif_metadata()
|
||||
&& let Some(config_meta) = metadata.get("check-configs")
|
||||
{
|
||||
let Item::Value(Value::Array(tables)) = config_meta else {
|
||||
panic!(
|
||||
"check-configs must be an array of tables. {:?}",
|
||||
config_meta
|
||||
);
|
||||
};
|
||||
|
||||
match self {
|
||||
Package::EspHal => {
|
||||
// This checks if the `esp-hal` crate compiles with the no features (other than the
|
||||
// chip selection)
|
||||
|
||||
// This tests that disabling the `rt` feature works
|
||||
cases.push(vec![]);
|
||||
// This checks if the `esp-hal` crate compiles _without_ the `unstable` feature
|
||||
// enabled
|
||||
cases.push(vec!["rt".to_owned()]);
|
||||
}
|
||||
Package::EspRadio => {
|
||||
// Minimal set of features that when enabled _should_ still compile:
|
||||
cases.push(vec!["esp-hal/rt".to_owned(), "esp-hal/unstable".to_owned()]);
|
||||
if config.contains("wifi") {
|
||||
// This tests if `wifi` feature works without `esp-radio/unstable`
|
||||
cases.push(vec![
|
||||
"esp-hal/rt".to_owned(),
|
||||
"esp-hal/unstable".to_owned(),
|
||||
"wifi".to_owned(),
|
||||
]);
|
||||
// This tests `wifi-eap` feature
|
||||
cases.push(vec![
|
||||
"esp-hal/rt".to_owned(),
|
||||
"esp-hal/unstable".to_owned(),
|
||||
"wifi-eap".to_owned(),
|
||||
"unstable".to_owned(),
|
||||
]);
|
||||
for table in tables {
|
||||
let Value::InlineTable(table) = table else {
|
||||
panic!("check-configs items must be inline tables.");
|
||||
};
|
||||
if let Some(features) = Self::parse_feature_set(table, config) {
|
||||
cases.push(features);
|
||||
}
|
||||
}
|
||||
Package::EspMetadataGenerated => {
|
||||
cases.push(vec!["build-script".to_owned()]);
|
||||
}
|
||||
Package::EspPreempt => {
|
||||
cases.push(vec!["esp-alloc".to_owned(), "esp-hal/unstable".to_owned()])
|
||||
}
|
||||
_ => {}
|
||||
} else {
|
||||
// Nothing specified, just test no features
|
||||
cases.push(vec![]);
|
||||
}
|
||||
|
||||
log::debug!("Lint feature cases for package '{}': {:?}", self, cases);
|
||||
log::debug!("Check features for package '{}': {:?}", self, cases);
|
||||
cases
|
||||
}
|
||||
|
||||
/// Additional feature rules to test subsets of features for a package.
|
||||
pub fn lint_feature_rules(&self, config: &Config) -> Vec<Vec<String>> {
|
||||
let mut cases = Vec::new();
|
||||
let mut cases = vec![];
|
||||
|
||||
// For now we run a lot of clippy checks, but that will change.
|
||||
cases.push(self.feature_rules(config));
|
||||
let toml = self.toml();
|
||||
if let Some(metadata) = toml.espressif_metadata()
|
||||
&& let Some(config_meta) = metadata.get("clippy-configs")
|
||||
{
|
||||
let Item::Value(Value::Array(tables)) = config_meta else {
|
||||
panic!(
|
||||
"clippy-configs must be an array of tables. {:?}",
|
||||
config_meta
|
||||
);
|
||||
};
|
||||
|
||||
match self {
|
||||
Package::EspHal => {
|
||||
// This checks if the `esp-hal` crate compiles with the no features (other than the
|
||||
// chip selection)
|
||||
|
||||
// This tests that disabling the `rt` feature works
|
||||
cases.push(vec![]);
|
||||
// This checks if the `esp-hal` crate compiles _without_ the `unstable` feature
|
||||
// enabled
|
||||
cases.push(vec!["rt".to_owned()]);
|
||||
}
|
||||
Package::EspRadio => {
|
||||
// Minimal set of features that when enabled _should_ still compile:
|
||||
cases.push(vec!["esp-hal/rt".to_owned(), "esp-hal/unstable".to_owned()]);
|
||||
if config.contains("wifi") {
|
||||
// This tests if `wifi` feature works without `esp-radio/unstable`
|
||||
cases.push(vec![
|
||||
"esp-hal/rt".to_owned(),
|
||||
"esp-hal/unstable".to_owned(),
|
||||
"wifi".to_owned(),
|
||||
]);
|
||||
// This tests `wifi-eap` feature
|
||||
cases.push(vec![
|
||||
"esp-hal/rt".to_owned(),
|
||||
"esp-hal/unstable".to_owned(),
|
||||
"wifi-eap".to_owned(),
|
||||
"unstable".to_owned(),
|
||||
]);
|
||||
for table in tables {
|
||||
let Value::InlineTable(table) = table else {
|
||||
panic!("clippy-configs items must be inline tables.");
|
||||
};
|
||||
if let Some(features) = Self::parse_feature_set(table, config) {
|
||||
cases.push(features);
|
||||
}
|
||||
}
|
||||
Package::EspMetadataGenerated => {
|
||||
cases.push(vec!["build-script".to_owned()]);
|
||||
}
|
||||
Package::EspPreempt => {
|
||||
cases.push(vec!["esp-alloc".to_owned(), "esp-hal/unstable".to_owned()])
|
||||
}
|
||||
Package::EspStorage => {
|
||||
// TODO: https://github.com/esp-rs/esp-hal/issues/4136
|
||||
if config.name() == "esp32c2"
|
||||
|| config.name() == "esp32c3"
|
||||
|| config.name() == "esp32s2"
|
||||
{
|
||||
// println!("kokot usho");
|
||||
cases.push(vec![
|
||||
"defmt".to_owned(),
|
||||
"portable-atomic/unsafe-assume-single-core".to_owned(),
|
||||
]);
|
||||
} else {
|
||||
cases.push(vec!["defmt".to_owned()]);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
log::debug!("Lint feature cases for package '{}': {:?}", self, cases);
|
||||
log::debug!("Check features for package '{}': {:?}", self, cases);
|
||||
cases
|
||||
}
|
||||
|
||||
fn toml(&self) -> MappedMutexGuard<'_, CargoToml> {
|
||||
static TOML: Mutex<Option<HashMap<Package, CargoToml>>> = Mutex::new(None);
|
||||
|
||||
let tomls = TOML.lock();
|
||||
|
||||
MutexGuard::map(tomls, |tomls| {
|
||||
let tomls = tomls.get_or_insert_default();
|
||||
|
||||
tomls.entry(*self).or_insert_with(|| {
|
||||
CargoToml::new(&std::env::current_dir().unwrap(), *self)
|
||||
.expect("Failed to parse Cargo.toml")
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fn targets_lp_core(&self) -> bool {
|
||||
if *self == Package::Examples {
|
||||
return false;
|
||||
}
|
||||
|
||||
let toml = self.toml();
|
||||
let Some(metadata) = toml.espressif_metadata() else {
|
||||
return false;
|
||||
};
|
||||
|
||||
let Some(Item::Value(targets_lp_core)) = metadata.get("targets_lp_core") else {
|
||||
return false;
|
||||
};
|
||||
|
||||
targets_lp_core
|
||||
.as_bool()
|
||||
.expect("targets_lp_core must be a boolean")
|
||||
}
|
||||
|
||||
/// Return the target triple for a given package/chip pair.
|
||||
pub fn target_triple(&self, chip: &Chip) -> Result<String> {
|
||||
if *self == Package::EspLpHal {
|
||||
if self.targets_lp_core() {
|
||||
chip.lp_target().map(ToString::to_string)
|
||||
} else {
|
||||
Ok(chip.target())
|
||||
@ -428,24 +400,29 @@ impl Package {
|
||||
|
||||
/// Validate that the specified chip is valid for the specified package.
|
||||
pub fn validate_package_chip(&self, chip: &Chip) -> Result<()> {
|
||||
let check = match self {
|
||||
Package::EspLpHal => chip.has_lp_core(),
|
||||
Package::XtensaLx | Package::XtensaLxRt | Package::XtensaLxRtProcMacros => {
|
||||
chip.is_xtensa()
|
||||
}
|
||||
Package::EspRiscvRt => chip.is_riscv(),
|
||||
_ => true,
|
||||
};
|
||||
|
||||
if check {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(anyhow!(
|
||||
"Invalid chip provided for package '{}': '{}'",
|
||||
self,
|
||||
chip
|
||||
))
|
||||
if *self == Package::Examples {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if self.targets_lp_core() && !chip.has_lp_core() {
|
||||
return Err(anyhow!(
|
||||
"Package '{self}' requires an LP core, but '{chip}' does not have one",
|
||||
));
|
||||
}
|
||||
|
||||
let toml = self.toml();
|
||||
|
||||
if let Some(metadata) = toml.espressif_metadata()
|
||||
&& let Some(Item::Value(Value::Array(targets))) = metadata.get("requires_target")
|
||||
&& !targets.iter().any(|t| t.as_str() == Some(&chip.target()))
|
||||
{
|
||||
return Err(anyhow!(
|
||||
"Package '{self}' is not compatible with {chip_target} chips",
|
||||
chip_target = chip.target()
|
||||
));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Creates a tag string for this [`Package`] combined with a semantic version.
|
||||
@ -460,7 +437,18 @@ impl Package {
|
||||
|
||||
#[cfg(feature = "release")]
|
||||
fn is_semver_checked(&self) -> bool {
|
||||
[Self::EspHal].contains(self)
|
||||
let toml = self.toml();
|
||||
let Some(metadata) = toml.espressif_metadata() else {
|
||||
return false;
|
||||
};
|
||||
|
||||
let Some(Item::Value(semver_checked)) = metadata.get("semver_checked") else {
|
||||
return false;
|
||||
};
|
||||
|
||||
semver_checked
|
||||
.as_bool()
|
||||
.expect("semver_checked must be a boolean")
|
||||
}
|
||||
}
|
||||
|
||||
@ -670,8 +658,8 @@ pub fn package_paths(workspace: &Path) -> Result<Vec<PathBuf>> {
|
||||
}
|
||||
|
||||
/// Parse the version from the specified package's Cargo manifest.
|
||||
pub fn package_version(workspace: &Path, package: Package) -> Result<semver::Version> {
|
||||
CargoToml::new(workspace, package).map(|toml| toml.package_version())
|
||||
pub fn package_version(_workspace: &Path, package: Package) -> Result<semver::Version> {
|
||||
Ok(package.toml().package_version())
|
||||
}
|
||||
|
||||
/// Make the path "Windows"-safe
|
||||
|
@ -258,7 +258,7 @@ fn check_packages(workspace: &Path, args: CheckPackagesArgs) -> Result<()> {
|
||||
|
||||
let mut commands = CargoCommandBatcher::new();
|
||||
|
||||
for package in packages.iter().filter(|p| p.is_published(workspace)) {
|
||||
for package in packages.iter().filter(|p| p.is_published()) {
|
||||
// Unfortunately each package has its own unique requirements for
|
||||
// building, so we need to handle each individually (though there
|
||||
// is *some* overlap)
|
||||
@ -266,7 +266,8 @@ fn check_packages(workspace: &Path, args: CheckPackagesArgs) -> Result<()> {
|
||||
log::debug!(" for chip: {}", chip);
|
||||
let device = Config::for_chip(chip);
|
||||
|
||||
if package.validate_package_chip(chip).is_err() {
|
||||
if let Err(e) = package.validate_package_chip(chip) {
|
||||
log::warn!("{e}. Skipping");
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -353,7 +354,7 @@ fn lint_packages(workspace: &Path, args: LintPackagesArgs) -> Result<()> {
|
||||
let mut packages = args.packages;
|
||||
packages.sort();
|
||||
|
||||
for package in packages.iter().filter(|p| p.is_published(workspace)) {
|
||||
for package in packages.iter().filter(|p| p.is_published()) {
|
||||
// Unfortunately each package has its own unique requirements for
|
||||
// building, so we need to handle each individually (though there
|
||||
// is *some* overlap)
|
||||
@ -361,7 +362,8 @@ fn lint_packages(workspace: &Path, args: LintPackagesArgs) -> Result<()> {
|
||||
log::debug!(" for chip: {}", chip);
|
||||
let device = Config::for_chip(chip);
|
||||
|
||||
if package.validate_package_chip(chip).is_err() {
|
||||
if let Err(e) = package.validate_package_chip(chip) {
|
||||
log::warn!("{e}. Skipping");
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -510,24 +512,11 @@ fn run_ci_checks(workspace: &Path, args: CiArgs) -> Result<()> {
|
||||
std::env::set_var("CI", "true");
|
||||
}
|
||||
|
||||
// TODO: enable checking all crates once cargo-batch has check support
|
||||
// runner.run("Check crates", || {
|
||||
// check_packages(
|
||||
// workspace,
|
||||
// LintPackagesArgs {
|
||||
// packages: Package::iter().collect(),
|
||||
// chips: vec![args.chip],
|
||||
// fix: false,
|
||||
// toolchain: args.toolchain.clone(),
|
||||
// },
|
||||
// )
|
||||
// });
|
||||
|
||||
runner.run("Check esp-hal", || {
|
||||
runner.run("Check crates", || {
|
||||
check_packages(
|
||||
workspace,
|
||||
CheckPackagesArgs {
|
||||
packages: vec![Package::EspHal],
|
||||
packages: Package::iter().collect(),
|
||||
chips: vec![args.chip],
|
||||
toolchain: args.toolchain.clone(),
|
||||
},
|
||||
|
@ -10,6 +10,9 @@ license = "MIT OR Apache-2.0"
|
||||
keywords = ["esp32", "xtensa-lx-rt", "runtime", "startup"]
|
||||
categories = ["embedded", "no-std"]
|
||||
|
||||
[package.metadata.espressif]
|
||||
requires_target = ["xtensa-esp32-none-elf", "xtensa-esp32s2-none-elf", "xtensa-esp32s3-none-elf"]
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
|
@ -11,6 +11,9 @@ keywords = ["lx", "peripheral", "register", "xtensa"]
|
||||
categories = ["embedded", "hardware-support", "no-std"]
|
||||
links = "xtensa-lx-rt"
|
||||
|
||||
[package.metadata.espressif]
|
||||
requires_target = ["xtensa-esp32-none-elf", "xtensa-esp32s2-none-elf", "xtensa-esp32s3-none-elf"]
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
test = false
|
||||
|
@ -10,6 +10,9 @@ license = "MIT OR Apache-2.0"
|
||||
categories = ["embedded", "hardware-support", "no-std"]
|
||||
keywords = ["lx", "peripheral", "register", "xtensa"]
|
||||
|
||||
[package.metadata.espressif]
|
||||
requires_target = ["xtensa-esp32-none-elf", "xtensa-esp32s2-none-elf", "xtensa-esp32s3-none-elf"]
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
test = false
|
||||
|
Loading…
x
Reference in New Issue
Block a user