mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-27 04:10:28 +00:00
Build examples in debug mode (#2078)
* Build examples in debug mode * Allow building psram examples in debug mode in CI * Don't rebuild tests, try to avoid rebuilding dependencies
This commit is contained in:
parent
42a0417fba
commit
5370afb1eb
4
.github/actions/check-esp-hal/action.yml
vendored
4
.github/actions/check-esp-hal/action.yml
vendored
@ -57,5 +57,7 @@ runs:
|
||||
--target=${{ inputs.target }} \
|
||||
esp-hal
|
||||
- name: Build (examples)
|
||||
env:
|
||||
CI: 1
|
||||
shell: bash
|
||||
run: cargo +${{ inputs.toolchain }} xtask build-examples esp-hal ${{ inputs.device }}
|
||||
run: cargo +${{ inputs.toolchain }} xtask build-examples esp-hal ${{ inputs.device }} --debug
|
||||
|
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@ -140,7 +140,7 @@ jobs:
|
||||
cargo xtask build-package --features=esp32c3,wifi,ble,async --target=riscv32imc-unknown-none-elf esp-wifi
|
||||
cargo xtask build-package --features=esp32c6,wifi,ble,async --target=riscv32imac-unknown-none-elf esp-wifi
|
||||
cargo xtask build-package --features=esp32h2,ble,async --target=riscv32imac-unknown-none-elf esp-wifi
|
||||
|
||||
|
||||
# Verify the MSRV for all Xtensa chips:
|
||||
- name: msrv Xtensa (esp-hal)
|
||||
run: |
|
||||
|
@ -6,14 +6,14 @@ fn main() -> Result<(), String> {
|
||||
|
||||
if cfg!(feature = "esp32") {
|
||||
match std::env::var("OPT_LEVEL") {
|
||||
Ok(level) => {
|
||||
Ok(level) if std::env::var("CI").is_err() => {
|
||||
if level != "2" && level != "3" {
|
||||
Err(format!("Building esp-storage for ESP32 needs optimization level 2 or 3 - yours is {}. See https://github.com/esp-rs/esp-storage", level))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Err(_err) => Ok(()),
|
||||
_ => Ok(()),
|
||||
}
|
||||
} else {
|
||||
Ok(())
|
||||
|
@ -8,4 +8,12 @@ fn main() {
|
||||
if cfg!(feature = "esp-wifi") {
|
||||
println!("cargo::rustc-link-arg=-Trom_functions.x");
|
||||
}
|
||||
|
||||
// Allow building examples in CI in debug mode
|
||||
println!("cargo:rustc-check-cfg=cfg(is_not_release)");
|
||||
println!("cargo:rerun-if-env-changed=CI");
|
||||
#[cfg(debug_assertions)]
|
||||
if std::env::var("CI").is_err() {
|
||||
println!("cargo::rustc-cfg=is_not_release");
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ use esp_println::{print, println};
|
||||
|
||||
const WIDTH: usize = 80;
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
#[cfg(is_not_release)]
|
||||
compile_error!("Run this example in release mode");
|
||||
|
||||
#[embassy_executor::task]
|
||||
|
@ -25,11 +25,11 @@ fn init_psram_heap() {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(is_not_release)]
|
||||
compile_error!("PSRAM example must be built in release mode!");
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
#[cfg(debug_assertions)]
|
||||
compile_error!("This example MUST be built in release mode!");
|
||||
|
||||
let peripherals = esp_hal::init(esp_hal::Config::default());
|
||||
|
||||
psram::init_psram(peripherals.PSRAM);
|
||||
|
@ -1,6 +1,6 @@
|
||||
//! This shows how to use PSRAM as heap-memory via esp-alloc
|
||||
//!
|
||||
//! You need an ESP32, ESP32-S2, or ESP32-S3 with at least 2 MB of PSRAM memory.
|
||||
//! You need an ESP32, ESP32-S2 or ESP32-S3 with at least 2 MB of PSRAM memory.
|
||||
|
||||
//% CHIPS: esp32 esp32s2 esp32s3
|
||||
//% FEATURES: psram-2m
|
||||
@ -25,11 +25,11 @@ fn init_psram_heap() {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(is_not_release)]
|
||||
compile_error!("PSRAM example must be built in release mode!");
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
#[cfg(debug_assertions)]
|
||||
compile_error!("PSRAM example must be built in release mode!");
|
||||
|
||||
let peripherals = esp_hal::init(esp_hal::Config::default());
|
||||
|
||||
psram::init_psram(peripherals.PSRAM);
|
||||
|
@ -113,6 +113,14 @@ impl CargoArgsBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_arg<S>(&mut self, arg: S) -> &mut Self
|
||||
where
|
||||
S: Into<String>,
|
||||
{
|
||||
self.args.push(arg.into());
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn build(self) -> Vec<String> {
|
||||
let mut args = vec![];
|
||||
|
@ -57,11 +57,11 @@ pub enum Package {
|
||||
pub struct Metadata {
|
||||
example_path: PathBuf,
|
||||
chips: Vec<Chip>,
|
||||
feature_sets: Vec<Vec<String>>,
|
||||
feature_set: Vec<String>,
|
||||
}
|
||||
|
||||
impl Metadata {
|
||||
pub fn new(example_path: &Path, chips: Vec<Chip>, feature_sets: Vec<Vec<String>>) -> Self {
|
||||
pub fn new(example_path: &Path, chips: Vec<Chip>, feature_set: Vec<String>) -> Self {
|
||||
let chips = if chips.is_empty() {
|
||||
Chip::iter().collect()
|
||||
} else {
|
||||
@ -71,7 +71,7 @@ impl Metadata {
|
||||
Self {
|
||||
example_path: example_path.to_path_buf(),
|
||||
chips,
|
||||
feature_sets,
|
||||
feature_set,
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,9 +89,9 @@ impl Metadata {
|
||||
.replace(".rs", "")
|
||||
}
|
||||
|
||||
/// A list of all features required for building a given examples.
|
||||
pub fn feature_sets(&self) -> &[Vec<String>] {
|
||||
&self.feature_sets
|
||||
/// A list of all features required for building a given example.
|
||||
pub fn feature_set(&self) -> &[String] {
|
||||
&self.feature_set
|
||||
}
|
||||
|
||||
/// If the specified chip is in the list of chips, then it is supported.
|
||||
@ -154,7 +154,7 @@ pub fn build_documentation(
|
||||
}
|
||||
|
||||
/// Load all examples at the given path, and parse their metadata.
|
||||
pub fn load_examples(path: &Path) -> Result<Vec<Metadata>> {
|
||||
pub fn load_examples(path: &Path, action: CargoAction) -> Result<Vec<Metadata>> {
|
||||
let mut examples = Vec::new();
|
||||
|
||||
for entry in fs::read_dir(path)? {
|
||||
@ -172,7 +172,7 @@ pub fn load_examples(path: &Path) -> Result<Vec<Metadata>> {
|
||||
.trim()
|
||||
.split_ascii_whitespace()
|
||||
.map(|s| s.to_string())
|
||||
.collect::<VecDeque<_>>();
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if split.len() < 2 {
|
||||
bail!(
|
||||
@ -182,7 +182,7 @@ pub fn load_examples(path: &Path) -> Result<Vec<Metadata>> {
|
||||
}
|
||||
|
||||
// The trailing ':' on metadata keys is optional :)
|
||||
let key = split.pop_front().unwrap();
|
||||
let key = split.swap_remove(0);
|
||||
let key = key.trim_end_matches(':');
|
||||
|
||||
if key == "CHIPS" {
|
||||
@ -191,15 +191,31 @@ pub fn load_examples(path: &Path) -> Result<Vec<Metadata>> {
|
||||
.map(|s| Chip::from_str(s, false).unwrap())
|
||||
.collect::<Vec<_>>();
|
||||
} else if key == "FEATURES" {
|
||||
feature_sets.push(split.into());
|
||||
// Sort the features so they are in a deterministic order:
|
||||
split.sort();
|
||||
feature_sets.push(split);
|
||||
} else {
|
||||
log::warn!("Unrecognized metadata key '{key}', ignoring");
|
||||
}
|
||||
}
|
||||
|
||||
examples.push(Metadata::new(&path, chips, feature_sets));
|
||||
if feature_sets.is_empty() {
|
||||
feature_sets.push(Vec::new());
|
||||
}
|
||||
if action == CargoAction::Build {
|
||||
// Only build the first feature set for each example.
|
||||
// Rebuilding with a different feature set just wastes time because the latter
|
||||
// one will overwrite the former one(s).
|
||||
feature_sets.truncate(1);
|
||||
}
|
||||
for feature_set in feature_sets {
|
||||
examples.push(Metadata::new(&path, chips.clone(), feature_set));
|
||||
}
|
||||
}
|
||||
|
||||
// Sort by feature set, to prevent rebuilding packages if not necessary.
|
||||
examples.sort_by_key(|e| e.feature_set().join(","));
|
||||
|
||||
Ok(examples)
|
||||
}
|
||||
|
||||
@ -210,7 +226,8 @@ pub fn execute_app(
|
||||
target: &str,
|
||||
app: &Metadata,
|
||||
action: CargoAction,
|
||||
repeat: usize,
|
||||
mut repeat: usize,
|
||||
debug: bool,
|
||||
) -> Result<()> {
|
||||
log::info!(
|
||||
"Building example '{}' for '{}'",
|
||||
@ -218,30 +235,7 @@ pub fn execute_app(
|
||||
chip
|
||||
);
|
||||
|
||||
let feature_sets = if app.feature_sets().is_empty() {
|
||||
vec![vec![]]
|
||||
} else {
|
||||
app.feature_sets().to_vec()
|
||||
};
|
||||
|
||||
for features in feature_sets {
|
||||
execute_app_with_features(package_path, chip, target, app, action, repeat, features)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Run or build the specified test or example for the specified chip, with the
|
||||
/// specified features enabled.
|
||||
pub fn execute_app_with_features(
|
||||
package_path: &Path,
|
||||
chip: Chip,
|
||||
target: &str,
|
||||
app: &Metadata,
|
||||
action: CargoAction,
|
||||
mut repeat: usize,
|
||||
mut features: Vec<String>,
|
||||
) -> Result<()> {
|
||||
let mut features = app.feature_set().to_vec();
|
||||
if !features.is_empty() {
|
||||
log::info!("Features: {}", features.join(","));
|
||||
}
|
||||
@ -269,19 +263,22 @@ pub fn execute_app_with_features(
|
||||
|
||||
let mut builder = CargoArgsBuilder::default()
|
||||
.subcommand(subcommand)
|
||||
.arg("--release")
|
||||
.target(target)
|
||||
.features(&features)
|
||||
.arg(bin);
|
||||
|
||||
if !debug {
|
||||
builder.add_arg("--release");
|
||||
}
|
||||
|
||||
if subcommand == "test" && chip == Chip::Esp32c2 {
|
||||
builder = builder.arg("--").arg("--speed").arg("15000");
|
||||
builder.add_arg("--").add_arg("--speed").add_arg("15000");
|
||||
}
|
||||
|
||||
// If targeting an Xtensa device, we must use the '+esp' toolchain modifier:
|
||||
if target.starts_with("xtensa") {
|
||||
builder = builder.toolchain("esp");
|
||||
builder = builder.arg("-Zbuild-std=core,alloc")
|
||||
builder.add_arg("-Zbuild-std=core,alloc");
|
||||
}
|
||||
|
||||
let args = builder.build();
|
||||
|
@ -58,6 +58,9 @@ struct ExampleArgs {
|
||||
chip: Chip,
|
||||
/// Optional example to act on (all examples used if omitted)
|
||||
example: Option<String>,
|
||||
/// Build examples in debug mode only
|
||||
#[arg(long)]
|
||||
debug: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
@ -202,7 +205,7 @@ fn examples(workspace: &Path, mut args: ExampleArgs, action: CargoAction) -> Res
|
||||
};
|
||||
|
||||
// Load all examples which support the specified chip and parse their metadata:
|
||||
let mut examples = xtask::load_examples(&example_path)?
|
||||
let mut examples = xtask::load_examples(&example_path, action)?
|
||||
.iter()
|
||||
.filter_map(|example| {
|
||||
if example.supports_chip(args.chip) {
|
||||
@ -227,16 +230,24 @@ fn build_examples(args: ExampleArgs, examples: Vec<Metadata>, package_path: &Pat
|
||||
// Determine the appropriate build target for the given package and chip:
|
||||
let target = target_triple(args.package, &args.chip)?;
|
||||
|
||||
if let Some(example) = examples.iter().find(|ex| Some(ex.name()) == args.example) {
|
||||
if examples
|
||||
.iter()
|
||||
.find(|ex| Some(ex.name()) == args.example)
|
||||
.is_some()
|
||||
{
|
||||
// Attempt to build only the specified example:
|
||||
xtask::execute_app(
|
||||
package_path,
|
||||
args.chip,
|
||||
target,
|
||||
example,
|
||||
CargoAction::Build,
|
||||
1,
|
||||
)
|
||||
for example in examples.iter().filter(|ex| Some(ex.name()) == args.example) {
|
||||
xtask::execute_app(
|
||||
package_path,
|
||||
args.chip,
|
||||
target,
|
||||
example,
|
||||
CargoAction::Build,
|
||||
1,
|
||||
args.debug,
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
} else if args.example.is_some() {
|
||||
// An invalid argument was provided:
|
||||
bail!("Example not found or unsupported for the given chip")
|
||||
@ -250,6 +261,7 @@ fn build_examples(args: ExampleArgs, examples: Vec<Metadata>, package_path: &Pat
|
||||
example,
|
||||
CargoAction::Build,
|
||||
1,
|
||||
args.debug,
|
||||
)
|
||||
})
|
||||
}
|
||||
@ -261,7 +273,9 @@ fn run_example(args: ExampleArgs, examples: Vec<Metadata>, package_path: &Path)
|
||||
|
||||
// Filter the examples down to only the binary we're interested in, assuming it
|
||||
// actually supports the specified chip:
|
||||
if let Some(example) = examples.iter().find(|ex| Some(ex.name()) == args.example) {
|
||||
let mut found_one = false;
|
||||
for example in examples.iter().filter(|ex| Some(ex.name()) == args.example) {
|
||||
found_one = true;
|
||||
xtask::execute_app(
|
||||
package_path,
|
||||
args.chip,
|
||||
@ -269,10 +283,17 @@ fn run_example(args: ExampleArgs, examples: Vec<Metadata>, package_path: &Path)
|
||||
example,
|
||||
CargoAction::Run,
|
||||
1,
|
||||
)
|
||||
} else {
|
||||
bail!("Example not found or unsupported for the given chip")
|
||||
args.debug,
|
||||
)?;
|
||||
}
|
||||
|
||||
ensure!(
|
||||
found_one,
|
||||
"Example not found or unsupported for {}",
|
||||
args.chip
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn tests(workspace: &Path, args: TestArgs, action: CargoAction) -> Result<()> {
|
||||
@ -283,7 +304,7 @@ fn tests(workspace: &Path, args: TestArgs, action: CargoAction) -> Result<()> {
|
||||
let target = target_triple(Package::HilTest, &args.chip)?;
|
||||
|
||||
// Load all tests which support the specified chip and parse their metadata:
|
||||
let mut tests = xtask::load_examples(&package_path.join("tests"))?
|
||||
let mut tests = xtask::load_examples(&package_path.join("tests"), action)?
|
||||
.into_iter()
|
||||
.filter(|example| example.supports_chip(args.chip))
|
||||
.collect::<Vec<_>>();
|
||||
@ -292,15 +313,23 @@ fn tests(workspace: &Path, args: TestArgs, action: CargoAction) -> Result<()> {
|
||||
tests.sort_by_key(|a| a.name());
|
||||
|
||||
// Execute the specified action:
|
||||
if let Some(test) = tests.iter().find(|test| Some(test.name()) == args.test) {
|
||||
xtask::execute_app(
|
||||
&package_path,
|
||||
args.chip,
|
||||
target,
|
||||
test,
|
||||
action,
|
||||
args.repeat.unwrap_or(1),
|
||||
)
|
||||
if tests
|
||||
.iter()
|
||||
.find(|test| Some(test.name()) == args.test)
|
||||
.is_some()
|
||||
{
|
||||
for test in tests.iter().filter(|test| Some(test.name()) == args.test) {
|
||||
xtask::execute_app(
|
||||
&package_path,
|
||||
args.chip,
|
||||
target,
|
||||
test,
|
||||
action,
|
||||
args.repeat.unwrap_or(1),
|
||||
false,
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
} else if args.test.is_some() {
|
||||
bail!("Test not found or unsupported for the given chip")
|
||||
} else {
|
||||
@ -313,6 +342,7 @@ fn tests(workspace: &Path, args: TestArgs, action: CargoAction) -> Result<()> {
|
||||
&test,
|
||||
action,
|
||||
args.repeat.unwrap_or(1),
|
||||
false,
|
||||
)
|
||||
.is_err()
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user