use std::collections::HashMap;
use std::path::{Path, PathBuf};
use consortium_cfg::Session;
use consortium_cfg_common::config::{AcoreName, Party, VisibleCore};
use super::{PipelineError, ipc_config_for};
use crate::compile::application::ApplicationConfiguration;
use crate::compile::env::HmiConfig;
pub struct ApplicationBuildPlan {
pub config: ApplicationConfiguration,
pub generated: String,
}
pub fn plan_application_build(
session: &Session,
manifest_dir: &Path,
hmi_dist: Option<&Path>,
resolved_dbg_elfs: &HashMap<VisibleCore, PathBuf>,
release: bool,
ty_crate: &syn::Path,
) -> Result<ApplicationBuildPlan, PipelineError> {
let root = session
.config
.endpoints
.get(&Party::AcoreNonSecure)
.ok_or_else(|| PipelineError::MissingEndpoint(Party::AcoreNonSecure.to_string()))?;
let path = manifest_dir.join(root);
let target = acore_linux_triple(&session.database.ap)?;
let hmi = match (&session.config.hmi, hmi_dist) {
(Some(hmi), Some(_)) => Some(HmiConfig::from_hmi(
hmi,
&session.config.profile.deploy_root,
)),
_ => None,
};
let ipc = ipc_config_for(&session.lower()?, VisibleCore::Ap);
let sysroot = session
.config
.profile
.sysroot
.as_ref()
.map(|s| manifest_dir.join(s));
let mut ir = session.lower()?;
ir.dbg = std::mem::take(&mut ir.dbg).with_resolved_elf_paths(resolved_dbg_elfs);
consortium_log::trace!("rendering AP init module for target {}", target);
let generated =
consortium_cfg::render(ir.initialize(VisibleCore::Ap, ty_crate)).map_err(|e| {
consortium_log::trace!("AP init codegen render failed: {}", e);
PipelineError::Codegen(e.to_string())
})?;
Ok(ApplicationBuildPlan {
config: ApplicationConfiguration {
path,
target,
release,
hmi,
ipc,
dbg: None,
sysroot,
},
generated,
})
}
fn acore_linux_triple(ap: &str) -> Result<String, PipelineError> {
let name: AcoreName = ap
.parse()
.map_err(|_| PipelineError::UnknownCore(ap.to_string()))?;
Ok(if name.is_64_bit() {
"aarch64-unknown-linux-gnu".to_string()
} else {
"armv7-unknown-linux-gnueabihf".to_string()
})
}
#[cfg(test)]
mod tests {
use super::*;
const STM32: &str = include_str!("../../../consortium-cfg/Consortium.example.stm32mp257.toml");
fn cm33() -> VisibleCore {
VisibleCore::Mcore("cm33".parse().unwrap())
}
#[test]
fn acore_triple_tracks_bitness() {
assert_eq!(
acore_linux_triple("ca35").unwrap(),
"aarch64-unknown-linux-gnu"
);
assert_eq!(
acore_linux_triple("ca7").unwrap(),
"armv7-unknown-linux-gnueabihf"
);
assert!(acore_linux_triple("bogus").is_err());
}
#[test]
fn plans_application_with_hmi_and_embedded_dbg() {
let session = Session::from_toml(STM32).expect("manifest loads");
let ty_crate: syn::Path = syn::parse_str("::shared").unwrap();
let resolved = HashMap::from([(cm33(), PathBuf::from("/build/cm33.elf"))]);
let plan = plan_application_build(
&session,
Path::new("/proj"),
Some(Path::new("/build/website/dist")),
&resolved,
true,
&ty_crate,
)
.expect("plan succeeds");
assert_eq!(plan.config.path, Path::new("/proj/app"));
assert_eq!(plan.config.target, "aarch64-unknown-linux-gnu");
assert!(plan.config.release);
let hmi = plan.config.hmi.expect("hmi injected");
assert_eq!(
hmi,
HmiConfig::Cog {
dist: "/opt/consortium/www".to_string(),
debug_url: Some("http://127.0.0.1:5173/".to_string()),
}
);
assert!(
plan.generated
.contains("include_bytes!(\"/build/cm33.elf\")")
);
assert!(plan.config.dbg.is_none());
assert!(plan.config.sysroot.is_none());
}
#[test]
fn relative_profile_sysroot_anchors_at_manifest_dir() {
let toml = STM32.replace(
"deploy_root = \"/opt/consortium\"",
"deploy_root = \"/opt/consortium\"\nsysroot = \"sdk/sysroot\"",
);
let session = Session::from_toml(&toml).expect("manifest loads");
let ty_crate: syn::Path = syn::parse_str("::shared").unwrap();
let plan = plan_application_build(
&session,
Path::new("/proj"),
None,
&HashMap::from([(cm33(), PathBuf::from("/build/cm33.elf"))]),
false,
&ty_crate,
)
.expect("plan succeeds");
assert_eq!(
plan.config.sysroot.as_deref(),
Some(Path::new("/proj/sdk/sysroot"))
);
}
#[test]
fn absolute_profile_sysroot_used_verbatim() {
let toml = STM32.replace(
"deploy_root = \"/opt/consortium\"",
"deploy_root = \"/opt/consortium\"\nsysroot = \"/sdk/target/sysroot\"",
);
let session = Session::from_toml(&toml).expect("manifest loads");
let ty_crate: syn::Path = syn::parse_str("::shared").unwrap();
let plan = plan_application_build(
&session,
Path::new("/proj"),
None,
&HashMap::from([(cm33(), PathBuf::from("/build/cm33.elf"))]),
false,
&ty_crate,
)
.expect("plan succeeds");
assert_eq!(
plan.config.sysroot.as_deref(),
Some(Path::new("/sdk/target/sysroot"))
);
}
#[test]
fn omits_hmi_when_frontend_not_built() {
let session = Session::from_toml(STM32).expect("manifest loads");
let ty_crate: syn::Path = syn::parse_str("::shared").unwrap();
let plan = plan_application_build(
&session,
Path::new("/proj"),
None,
&HashMap::from([(cm33(), PathBuf::from("/build/cm33.elf"))]),
false,
&ty_crate,
)
.expect("plan succeeds");
assert!(plan.config.hmi.is_none());
}
}