@@ -1094,6 +1094,16 @@ fn run_introspect(config: &IntrospectConfig) -> Result<ObservedProgram, String> |
| 1094 | }) | 1094 | }) |
| 1095 | } | 1095 | } |
| 1096 | | 1096 | |
| | 1097 | +fn requested_linked_armfortas_artifacts(requested: &BTreeSet<ArtifactKey>) -> Vec<String> { |
| | 1098 | + requested |
| | 1099 | + .iter() |
| | 1100 | + .filter_map(|artifact| match artifact { |
| | 1101 | + ArtifactKey::Extra(name) if name.starts_with("armfortas.") => Some(name.clone()), |
| | 1102 | + _ => None, |
| | 1103 | + }) |
| | 1104 | + .collect() |
| | 1105 | +} |
| | 1106 | + |
| 1097 | fn observe_compiler( | 1107 | fn observe_compiler( |
| 1098 | spec: &CompilerSpec, | 1108 | spec: &CompilerSpec, |
| 1099 | program: &Path, | 1109 | program: &Path, |
@@ -1143,6 +1153,33 @@ fn observe_armfortas( |
| 1143 | tools: &ToolchainConfig, | 1153 | tools: &ToolchainConfig, |
| 1144 | ) -> Result<CompilerObservation, String> { | 1154 | ) -> Result<CompilerObservation, String> { |
| 1145 | let stages = armfortas_requested_stages(requested)?; | 1155 | let stages = armfortas_requested_stages(requested)?; |
| | 1156 | + let linked_only_artifacts = requested_linked_armfortas_artifacts(requested); |
| | 1157 | + let linked_backend = tools.armfortas_adapters(); |
| | 1158 | + if !linked_only_artifacts.is_empty() && linked_backend.capture_mode_name() == "unavailable" { |
| | 1159 | + let detail = format!( |
| | 1160 | + "linked armfortas capture is unavailable in this build; requested {}; use scripts/bootstrap-linked-armfortas.sh or request only asm/obj/run from an external armfortas binary", |
| | 1161 | + linked_only_artifacts.join(", ") |
| | 1162 | + ); |
| | 1163 | + return Ok(CompilerObservation { |
| | 1164 | + compiler: CompilerSpec::Named(NamedCompiler::Armfortas), |
| | 1165 | + program: program.to_path_buf(), |
| | 1166 | + opt_level, |
| | 1167 | + compile_exit_code: 1, |
| | 1168 | + artifacts: BTreeMap::from([( |
| | 1169 | + ArtifactKey::Diagnostics, |
| | 1170 | + ArtifactValue::Text(detail.clone()), |
| | 1171 | + )]), |
| | 1172 | + provenance: ObservationProvenance { |
| | 1173 | + compiler_identity: "armfortas".into(), |
| | 1174 | + adapter_kind: "named".into(), |
| | 1175 | + backend_mode: linked_backend.capture_mode_name().into(), |
| | 1176 | + backend_detail: linked_backend.capture_description().into(), |
| | 1177 | + artifacts_captured: vec!["diagnostics".into()], |
| | 1178 | + comparison_basis: None, |
| | 1179 | + failure_stage: None, |
| | 1180 | + }, |
| | 1181 | + }); |
| | 1182 | + } |
| 1146 | let cli_observable_only = requested.iter().all(|artifact| { | 1183 | let cli_observable_only = requested.iter().all(|artifact| { |
| 1147 | matches!( | 1184 | matches!( |
| 1148 | artifact, | 1185 | artifact, |
@@ -1169,7 +1206,7 @@ fn observe_armfortas( |
| 1169 | }; | 1206 | }; |
| 1170 | (mode, detail, backend.capture(&request)) | 1207 | (mode, detail, backend.capture(&request)) |
| 1171 | } else { | 1208 | } else { |
| 1172 | - let backend = tools.armfortas_adapters(); | 1209 | + let backend = linked_backend; |
| 1173 | let detail = backend.capture_description().to_string(); | 1210 | let detail = backend.capture_description().to_string(); |
| 1174 | let mode = backend.capture_mode_name().to_string(); | 1211 | let mode = backend.capture_mode_name().to_string(); |
| 1175 | let request = CaptureRequest { | 1212 | let request = CaptureRequest { |
@@ -5485,6 +5522,18 @@ fn compose_armfortas_failure_detail(artifacts: &ExecutionArtifacts) -> String { |
| 5485 | } | 5522 | } |
| 5486 | | 5523 | |
| 5487 | fn compose_observation_failure_detail(observation: &CompilerObservation) -> String { | 5524 | fn compose_observation_failure_detail(observation: &CompilerObservation) -> String { |
| | 5525 | + if observation.provenance.backend_mode == "unavailable" { |
| | 5526 | + let mut detail = format!( |
| | 5527 | + "{} unavailable for requested artifacts in this build", |
| | 5528 | + observation.compiler.display_name() |
| | 5529 | + ); |
| | 5530 | + if let Some(diagnostics) = observation_diagnostics_text(observation) { |
| | 5531 | + detail.push('\n'); |
| | 5532 | + detail.push_str(diagnostics); |
| | 5533 | + } |
| | 5534 | + return detail; |
| | 5535 | + } |
| | 5536 | + |
| 5488 | let mut detail = String::new(); | 5537 | let mut detail = String::new(); |
| 5489 | detail.push_str(&format!("{} failed", observation.compiler.display_name())); | 5538 | detail.push_str(&format!("{} failed", observation.compiler.display_name())); |
| 5490 | if let Some(stage) = &observation.provenance.failure_stage { | 5539 | if let Some(stage) = &observation.provenance.failure_stage { |
@@ -10742,6 +10791,35 @@ mod tests { |
| 10742 | assert!(rendered.contains("failure_stage: none")); | 10791 | assert!(rendered.contains("failure_stage: none")); |
| 10743 | } | 10792 | } |
| 10744 | | 10793 | |
| | 10794 | + #[test] |
| | 10795 | + fn compose_observation_failure_detail_uses_unavailable_wording() { |
| | 10796 | + let observation = CompilerObservation { |
| | 10797 | + compiler: CompilerSpec::Named(NamedCompiler::Armfortas), |
| | 10798 | + program: PathBuf::from("demo.f90"), |
| | 10799 | + opt_level: OptLevel::O0, |
| | 10800 | + compile_exit_code: 1, |
| | 10801 | + artifacts: BTreeMap::from([( |
| | 10802 | + ArtifactKey::Diagnostics, |
| | 10803 | + ArtifactValue::Text( |
| | 10804 | + "linked armfortas capture is unavailable in this build".into(), |
| | 10805 | + ), |
| | 10806 | + )]), |
| | 10807 | + provenance: ObservationProvenance { |
| | 10808 | + compiler_identity: "armfortas".into(), |
| | 10809 | + adapter_kind: "named".into(), |
| | 10810 | + backend_mode: "unavailable".into(), |
| | 10811 | + backend_detail: "unavailable without linked-armfortas feature".into(), |
| | 10812 | + artifacts_captured: vec!["diagnostics".into()], |
| | 10813 | + comparison_basis: None, |
| | 10814 | + failure_stage: None, |
| | 10815 | + }, |
| | 10816 | + }; |
| | 10817 | + |
| | 10818 | + let detail = compose_observation_failure_detail(&observation); |
| | 10819 | + assert!(detail.contains("armfortas unavailable for requested artifacts in this build")); |
| | 10820 | + assert!(!detail.contains("failed in")); |
| | 10821 | + } |
| | 10822 | + |
| 10745 | #[cfg(unix)] | 10823 | #[cfg(unix)] |
| 10746 | #[test] | 10824 | #[test] |
| 10747 | fn execute_generic_suite_case_uses_introspect_engine() { | 10825 | fn execute_generic_suite_case_uses_introspect_engine() { |