From 207f7c007933a27a55566e61c7ae7ffc99ad86cc Mon Sep 17 00:00:00 2001 From: Avi Cohen Date: Thu, 4 Jun 2026 14:43:10 +0300 Subject: [PATCH] apollo_compilation_utils: resolve tools root next to the executable when present Co-Authored-By: Claude Opus 4.8 (1M context) --- crates/apollo_compilation_utils/src/paths.rs | 25 +++++++++++++-- .../src/paths_test.rs | 32 +++++++++++++++++++ 2 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 crates/apollo_compilation_utils/src/paths_test.rs diff --git a/crates/apollo_compilation_utils/src/paths.rs b/crates/apollo_compilation_utils/src/paths.rs index 60220e3395e..a56c1d9c0ec 100644 --- a/crates/apollo_compilation_utils/src/paths.rs +++ b/crates/apollo_compilation_utils/src/paths.rs @@ -2,10 +2,15 @@ // It must not contain functionality that is available in only in one of these modes. Specifically, // it must avoid relying on env variables such as 'CARGO_*' or 'OUT_DIR'. -use std::path::PathBuf; +use std::path::{Path, PathBuf}; + +#[cfg(test)] +#[path = "paths_test.rs"] +pub mod test; /// Returns `/-/bin/`, where -/// `cargo_tools_root` resolves to `$CARGO_TOOLS_ROOT`, else `$CARGO_HOME/tools`, +/// `cargo_tools_root` resolves to `$CARGO_TOOLS_ROOT`, else a `tools` directory +/// next to the running executable (if one exists), else `$CARGO_HOME/tools`, /// else `$HOME/.cargo/tools`. /// /// The path is constructed deterministically; there is no `$PATH` lookup. The @@ -22,8 +27,24 @@ fn cargo_tools_root() -> PathBuf { if let Ok(p) = std::env::var("CARGO_TOOLS_ROOT") { return PathBuf::from(p); } + // A `tools` directory next to the running executable takes precedence over the + // cargo-home default: distributed packages ship the compiler tree alongside the + // binary, so prebuilt binaries work on machines with no cargo installation and + // no environment setup. + if let Some(tools_root) = + std::env::current_exe().ok().and_then(|exe_path| exe_relative_tools_root(&exe_path)) + { + return tools_root; + } let cargo_home = std::env::var("CARGO_HOME").map(PathBuf::from).unwrap_or_else(|_| { PathBuf::from(std::env::var("HOME").expect("HOME must be set")).join(".cargo") }); cargo_home.join("tools") } + +/// Returns the `tools` directory next to `exe_path`, or `None` if there is no such +/// directory (e.g. for executables under `target/`, which have no bundled tools). +fn exe_relative_tools_root(exe_path: &Path) -> Option { + let tools_dir = exe_path.parent()?.join("tools"); + tools_dir.is_dir().then_some(tools_dir) +} diff --git a/crates/apollo_compilation_utils/src/paths_test.rs b/crates/apollo_compilation_utils/src/paths_test.rs new file mode 100644 index 00000000000..706c6933918 --- /dev/null +++ b/crates/apollo_compilation_utils/src/paths_test.rs @@ -0,0 +1,32 @@ +use std::fs; + +use tempfile::TempDir; + +use crate::paths::exe_relative_tools_root; + +#[test] +fn tools_directory_next_to_executable_is_resolved() { + let package_dir = TempDir::new().unwrap(); + let tools_dir = package_dir.path().join("tools"); + fs::create_dir(&tools_dir).unwrap(); + let exe_path = package_dir.path().join("prover_binary"); + + assert_eq!(exe_relative_tools_root(&exe_path), Some(tools_dir)); +} + +#[test] +fn missing_tools_directory_yields_none() { + let package_dir = TempDir::new().unwrap(); + let exe_path = package_dir.path().join("prover_binary"); + + assert_eq!(exe_relative_tools_root(&exe_path), None); +} + +#[test] +fn tools_path_that_is_a_file_yields_none() { + let package_dir = TempDir::new().unwrap(); + fs::write(package_dir.path().join("tools"), "not a directory").unwrap(); + let exe_path = package_dir.path().join("prover_binary"); + + assert_eq!(exe_relative_tools_root(&exe_path), None); +}