use std::collections::HashMap;
use std::path::PathBuf;
use consortium_cfg::components::dbg::ElfLocation;
use consortium_cfg_common::config::{VisibleCore, Workspace};
use super::PipelineError;
use crate::compile::env::CstiWorkspace;
pub fn resolve_dbg_elf_paths(
firmware_outputs: &HashMap<VisibleCore, PathBuf>,
dbg_cores: impl Iterator<Item = VisibleCore>,
) -> Result<HashMap<VisibleCore, PathBuf>, PipelineError> {
let mut resolved = HashMap::new();
for core in dbg_cores {
let path = firmware_outputs
.get(&core)
.ok_or_else(|| PipelineError::DbgCoreNotBuilt(core.to_string()))?;
let absolute = std::path::absolute(path).unwrap_or_else(|_| path.clone());
resolved.insert(core, absolute);
}
Ok(resolved)
}
pub fn embed_locations(
dbg_elfs: &HashMap<VisibleCore, PathBuf>,
workspace: &CstiWorkspace,
) -> HashMap<VisibleCore, ElfLocation> {
let base = match workspace.layout {
Workspace::Unified => Some(workspace.manifest_dir.as_path()),
Workspace::Nested => workspace.mcu_dir.as_deref(),
};
let env = workspace.layout.firmware_target_base_env();
dbg_elfs
.iter()
.map(|(core, path)| {
let location = match base.and_then(|base| path.strip_prefix(base).ok()) {
Some(relative) => ElfLocation::relative_to(env, relative),
None => ElfLocation::verbatim(path.clone()),
};
(*core, location)
})
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
use std::path::Path;
fn cm33() -> VisibleCore {
VisibleCore::Mcore("cm33".parse().unwrap())
}
fn cm0p() -> VisibleCore {
VisibleCore::Mcore("cm0p".parse().unwrap())
}
#[test]
fn resolves_paths_for_built_cores() {
let outputs = HashMap::from([(cm33(), PathBuf::from("/build/cm33.elf"))]);
let resolved =
resolve_dbg_elf_paths(&outputs, [cm33()].into_iter()).expect("cm33 was built");
assert_eq!(resolved[&cm33()], PathBuf::from("/build/cm33.elf"));
}
fn workspace(layout: Workspace, mcu_dir: Option<&str>) -> CstiWorkspace {
CstiWorkspace {
layout,
manifest_dir: PathBuf::from("/proj"),
mcu_dir: mcu_dir.map(PathBuf::from),
}
}
#[test]
fn nested_embeds_relative_to_mcu_path() {
let elfs = HashMap::from([(
cm33(),
PathBuf::from("/proj/mcu/target/thumbv8m.main-none-eabihf/debug/fw_original.elf"),
)]);
let located = embed_locations(&elfs, &workspace(Workspace::Nested, Some("/proj/mcu")));
assert_eq!(
located[&cm33()],
ElfLocation::relative_to(
"CSTI_MCU_PATH",
Path::new("target/thumbv8m.main-none-eabihf/debug/fw_original.elf"),
)
);
}
#[test]
fn unified_embeds_relative_to_manifest_path() {
let elfs = HashMap::from([(
cm33(),
PathBuf::from("/proj/target/thumbv8m.main-none-eabihf/debug/fw_original.elf"),
)]);
let located = embed_locations(&elfs, &workspace(Workspace::Unified, Some("/proj/mcu")));
assert_eq!(
located[&cm33()],
ElfLocation::relative_to(
"CSTI_MANIFEST_PATH",
Path::new("target/thumbv8m.main-none-eabihf/debug/fw_original.elf"),
)
);
}
#[test]
fn nested_without_a_single_mcu_falls_back_to_absolute() {
let elf = PathBuf::from("/proj/mcu/target/thumbv8m.main-none-eabihf/debug/fw_original.elf");
let elfs = HashMap::from([(cm33(), elf.clone())]);
let located = embed_locations(&elfs, &workspace(Workspace::Nested, None));
assert_eq!(located[&cm33()], ElfLocation::verbatim(elf));
}
#[test]
fn errors_when_dbg_core_was_not_built() {
let outputs = HashMap::from([(cm33(), PathBuf::from("/build/cm33.elf"))]);
let err = resolve_dbg_elf_paths(&outputs, [cm0p()].into_iter())
.expect_err("cm0p has no firmware output");
assert!(matches!(err, PipelineError::DbgCoreNotBuilt(core) if core == "cm0p"));
}
}