Skip to content

Commit 2efa7c6

Browse files
avi-starkwareclaude
andcommitted
apollo_compilation_utils: add verify_compiler_binary
New function that checks a compiler binary's version at runtime and panics with installation instructions if missing or wrong version. Added alongside the existing install_compiler_binary — no callers yet. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 3317ff4 commit 2efa7c6

1 file changed

Lines changed: 43 additions & 0 deletions

File tree

crates/apollo_compilation_utils/src/build_utils.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::path::Path;
12
use std::process::Command;
23

34
use tempfile::TempDir;
@@ -64,3 +65,45 @@ pub fn install_compiler_binary(
6465

6566
println!("Successfully set executable file: {:?}", binary_path.display());
6667
}
68+
69+
/// Verifies that a compiler binary is installed and has the required version.
70+
/// Panics with installation instructions if the binary is missing or has the wrong version.
71+
///
72+
/// Expects `--version` output in the form `<binary-name> <version>` (with optional
73+
/// trailing tokens). The match is anchored to the binary's own file name so that
74+
/// a misbehaving or substituted binary printing a stray dotted token elsewhere in
75+
/// its output cannot satisfy the check.
76+
pub fn verify_compiler_binary(binary_path: &Path, required_version: &str) {
77+
let binary_name = binary_path.display();
78+
let expected_prefix = binary_path
79+
.file_name()
80+
.and_then(|name| name.to_str())
81+
.unwrap_or_else(|| panic!("{binary_name} has no UTF-8 file name."));
82+
let install_instructions =
83+
"Run 'scripts/install_compiler_binaries.sh' to install the correct version.";
84+
match Command::new(binary_path).arg("--version").output() {
85+
Ok(output) => {
86+
let version_output = String::from_utf8_lossy(&output.stdout);
87+
// Expect "<binary-name> <version>" on the first non-empty line. Anchoring
88+
// to <binary-name> avoids both substring false-positives ("1.0.1" vs
89+
// "1.0.10") and adversarial padding (e.g. a banner that includes the
90+
// required version elsewhere in stdout).
91+
let first_line = version_output.lines().find(|line| !line.trim().is_empty());
92+
let installed_version = first_line
93+
.and_then(|line| line.strip_prefix(expected_prefix))
94+
.map(|rest| rest.trim_start())
95+
.and_then(|rest| rest.split_whitespace().next())
96+
.unwrap_or("");
97+
if installed_version != required_version {
98+
panic!(
99+
"{binary_name} version {required_version} is required, but found: \
100+
{installed_version:?} (raw output: {version_output:?}). \
101+
{install_instructions}"
102+
);
103+
}
104+
}
105+
Err(_) => {
106+
panic!("{binary_name} not found. {install_instructions}");
107+
}
108+
}
109+
}

0 commit comments

Comments
 (0)