diff --git a/barretenberg/rust/barretenberg-rs/build.rs b/barretenberg/rust/barretenberg-rs/build.rs index de21724c68be..fdedb61d7977 100644 --- a/barretenberg/rust/barretenberg-rs/build.rs +++ b/barretenberg/rust/barretenberg-rs/build.rs @@ -1,14 +1,10 @@ +use std::path::PathBuf; + fn main() { - // Only for ffi feature - link libbb-external from cpp build + // Only for ffi feature - link libbb-external #[cfg(feature = "ffi")] { - // Find the cpp build lib directory relative to this crate - let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); - let lib_dir = std::path::Path::new(&manifest_dir) - .join("../../cpp/build/lib") - .canonicalize() - .expect("Failed to find cpp/build/lib - run barretenberg/cpp/bootstrap.sh first"); - + let lib_dir = get_lib_dir(); println!("cargo:rustc-link-search=native={}", lib_dir.display()); // libbb-external.a contains everything needed: barretenberg + env + vm2_stub @@ -16,3 +12,97 @@ fn main() { println!("cargo:rustc-link-lib=dylib=stdc++"); } } + +#[cfg(feature = "ffi")] +fn get_lib_dir() -> PathBuf { + // Check if user provided a custom library path + if let Ok(lib_dir) = std::env::var("BB_LIB_DIR") { + let lib_dir = PathBuf::from(&lib_dir); + if lib_dir.join("libbb-external.a").exists() { + return lib_dir.canonicalize().unwrap(); + } + panic!( + "BB_LIB_DIR is set to {:?} but libbb-external.a not found there. \ + Build barretenberg locally: cd barretenberg/cpp && ./bootstrap.sh", + lib_dir + ); + } + + // Download from GitHub releases + let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap()); + let lib_path = out_dir.join("libbb-external.a"); + + if !lib_path.exists() { + download_lib(&out_dir); + } + + out_dir +} + +#[cfg(feature = "ffi")] +fn download_lib(out_dir: &PathBuf) { + let target = std::env::var("TARGET").unwrap(); + let arch = match target.as_str() { + t if t.contains("x86_64") && t.contains("linux") => "amd64-linux", + t if t.contains("aarch64") && t.contains("linux") => "arm64-linux", + _ => panic!( + "Unsupported target for FFI backend: {}. Supported: x86_64-linux, aarch64-linux", + target + ), + }; + + // Use BARRETENBERG_VERSION env var, or fall back to crate version + let version = std::env::var("BARRETENBERG_VERSION") + .unwrap_or_else(|_| env!("CARGO_PKG_VERSION").to_string()); + + // Skip download for development versions (0.x.x without BARRETENBERG_VERSION override) + // Real releases use the aztec-packages version (e.g., 4.0.0) set via BARRETENBERG_VERSION + if version.starts_with("0.") && std::env::var("BARRETENBERG_VERSION").is_err() { + panic!( + "Cannot download pre-built library for development version {}. \ + Either set BARRETENBERG_VERSION to a released version, or \ + set BB_LIB_DIR to point to a local build: cd barretenberg/cpp && ./bootstrap.sh", + version + ); + } + + let url = format!( + "https://github.com/AztecProtocol/aztec-packages/releases/download/v{}/barretenberg-static-{}.tar.gz", + version, arch + ); + + println!("cargo:warning=Downloading barretenberg static library from {}", url); + + // Download and extract + let tar_gz_path = out_dir.join("barretenberg-static.tar.gz"); + + let status = std::process::Command::new("curl") + .args(["-L", "-f", "-o"]) + .arg(&tar_gz_path) + .arg(&url) + .status() + .expect("Failed to run curl"); + + if !status.success() { + panic!( + "Failed to download barretenberg static library from {}. \ + Make sure version v{} exists as a GitHub release.", + url, version + ); + } + + let status = std::process::Command::new("tar") + .args(["-xzf"]) + .arg(&tar_gz_path) + .arg("-C") + .arg(out_dir) + .status() + .expect("Failed to run tar"); + + if !status.success() { + panic!("Failed to extract barretenberg static library"); + } + + // Clean up tar.gz + std::fs::remove_file(&tar_gz_path).ok(); +} diff --git a/barretenberg/rust/bootstrap.sh b/barretenberg/rust/bootstrap.sh index 4d11c656c172..7b632ad0a8f6 100755 --- a/barretenberg/rust/bootstrap.sh +++ b/barretenberg/rust/bootstrap.sh @@ -13,7 +13,9 @@ function build { (cd ../ts && yarn generate) # Build all targets - denoise "cargo build --release" + # BB_LIB_DIR tells build.rs to use local lib instead of downloading (ffi feature is on by default) + # Must use absolute path since build.rs runs from a different directory + BB_LIB_DIR="$(cd ../cpp/build/lib && pwd)" denoise "cargo build --release" # Upload build artifacts and generated source files to cache cache_upload barretenberg-rs-$hash.tar.gz target/release barretenberg-rs/src/generated_types.rs barretenberg-rs/src/api.rs @@ -38,7 +40,63 @@ function test { denoise "cargo test --release" # Run FFI backend tests (requires libbb-external.a from cpp build) - RUSTFLAGS="-C link-arg=-Wl,--allow-multiple-definition" denoise "cargo test --release --features ffi" + # BB_LIB_DIR tells build.rs to use local lib instead of downloading + # Must use absolute path since build.rs runs from a different directory + BB_LIB_DIR="$(cd ../cpp/build/lib && pwd)" RUSTFLAGS="-C link-arg=-Wl,--allow-multiple-definition" denoise "cargo test --release --features ffi" +} + +function test_download { + echo_header "barretenberg-rs download test" + + # Ensure Cargo is in PATH + if [ -f "$HOME/.cargo/env" ]; then + source "$HOME/.cargo/env" + fi + + # Test that build.rs can download pre-built libraries from GitHub releases + # Hide the local library to force download path + local lib_path="../cpp/build/lib/libbb-external.a" + if [ -f "$lib_path" ]; then + mv "$lib_path" "$lib_path.bak" + trap "mv '$lib_path.bak' '$lib_path' 2>/dev/null" EXIT + fi + + # Clean cargo cache to force rebuild + cargo clean -p barretenberg-rs 2>/dev/null || true + + # Build with a known release version + local version=${BARRETENBERG_VERSION:-$(gh release list --repo AztecProtocol/aztec-packages --limit 1 --json tagName --jq '.[0].tagName' | sed 's/^v//')} + echo "Testing download with version: $version" + + # Retry logic for network flakiness (GitHub releases can be flaky) + local max_retries=3 + local retry=0 + local success=false + while [ $retry -lt $max_retries ]; do + if BARRETENBERG_VERSION=$version RUSTFLAGS="-C link-arg=-Wl,--allow-multiple-definition" \ + cargo test --release --features ffi -p barretenberg-rs 2>&1; then + success=true + break + fi + retry=$((retry + 1)) + if [ $retry -lt $max_retries ]; then + echo "Attempt $retry failed, retrying in 5 seconds..." + sleep 5 + # Clean to force re-download + cargo clean -p barretenberg-rs 2>/dev/null || true + fi + done + + if [ "$success" = false ]; then + echo "Download test failed after $max_retries attempts" + exit 1 + fi + + # Restore the local library (trap handles this, but be explicit) + if [ -f "$lib_path.bak" ]; then + mv "$lib_path.bak" "$lib_path" + trap - EXIT + fi } case "$cmd" in @@ -58,7 +116,7 @@ case "$cmd" in bench|bench_cmds) # Empty handling just to make this command valid. ;; - test|test_cmds) + test|test_cmds|test_download) $cmd ;; *)