|
52 | 52 | #[cfg(feature = "anchor")] |
53 | 53 | pub mod anchor_testing; |
54 | 54 |
|
| 55 | +#[cfg(feature = "cu_bench")] |
| 56 | +pub mod cu_bench; |
| 57 | + |
55 | 58 | #[cfg(feature = "pinocchio")] |
56 | 59 | pub mod pinocchio_testing; |
57 | 60 |
|
@@ -573,3 +576,138 @@ pub fn setup_svm_and_fee_payer() -> (LiteSVM, Keypair) { |
573 | 576 |
|
574 | 577 | (svm, fee_payer) |
575 | 578 | } |
| 579 | + |
| 580 | +/// Private helper function for building Solana programs with isolated temp directories. |
| 581 | +/// |
| 582 | +/// This function handles the common logic for both Anchor and Pinocchio program builds: |
| 583 | +/// - Sets up isolated temp directory to prevent file lock contention |
| 584 | +/// - Runs `cargo build-sbf` with specified features |
| 585 | +/// - Extracts workspace root from OUT_DIR environment variable |
| 586 | +/// - Copies all built .so files to workspace target directory |
| 587 | +/// - Provides aggressive error handling with clear diagnostics |
| 588 | +fn build_solana_program_internal<P: AsRef<std::path::Path>>(program_path: P, features: &[&str]) { |
| 589 | + use std::{fs, process::Command}; |
| 590 | + |
| 591 | + let program_manifest = program_path.as_ref().join("Cargo.toml"); |
| 592 | + let program_src = program_path.as_ref().join("src"); |
| 593 | + |
| 594 | + // Tell cargo to rerun this build script if the program source changes |
| 595 | + println!("cargo:rerun-if-changed={}", program_manifest.display()); |
| 596 | + println!("cargo:rerun-if-changed={}", program_src.display()); |
| 597 | + |
| 598 | + // Extract program name from Cargo.toml path |
| 599 | + let program_name = program_path |
| 600 | + .as_ref() |
| 601 | + .file_name() |
| 602 | + .and_then(|n| n.to_str()) |
| 603 | + .expect("Failed to extract program name from path"); |
| 604 | + |
| 605 | + // Determine target directory - use existing CARGO_TARGET_DIR or create temp |
| 606 | + let base_target_dir = std::env::var("CARGO_TARGET_DIR") |
| 607 | + .map(|p| std::path::PathBuf::from(p)) |
| 608 | + .unwrap_or_else(|_| std::env::temp_dir().join("litesvm-builds")); |
| 609 | + |
| 610 | + let temp_dir = base_target_dir.join(format!("program-{}", program_name)); |
| 611 | + |
| 612 | + if let Err(e) = fs::create_dir_all(&temp_dir) { |
| 613 | + eprintln!("Failed to create build directory: {}", e); |
| 614 | + std::process::exit(1); |
| 615 | + } |
| 616 | + |
| 617 | + // Build the program in isolated directory |
| 618 | + let output = Command::new("cargo") |
| 619 | + .args([ |
| 620 | + "build-sbf", |
| 621 | + "--manifest-path", |
| 622 | + &program_manifest.to_string_lossy(), |
| 623 | + "--features", |
| 624 | + &features.join(","), |
| 625 | + ]) |
| 626 | + .env("CARGO_TARGET_DIR", &temp_dir) |
| 627 | + .output(); |
| 628 | + |
| 629 | + match output { |
| 630 | + Ok(output) => { |
| 631 | + if !output.status.success() { |
| 632 | + eprintln!("Failed to build program:"); |
| 633 | + eprintln!("stdout: {}", String::from_utf8_lossy(&output.stdout)); |
| 634 | + eprintln!("stderr: {}", String::from_utf8_lossy(&output.stderr)); |
| 635 | + std::process::exit(1); |
| 636 | + } |
| 637 | + } |
| 638 | + Err(e) => { |
| 639 | + eprintln!("Failed to execute cargo build-sbf: {}", e); |
| 640 | + eprintln!("Make sure you have the solana CLI tools installed and in your PATH"); |
| 641 | + std::process::exit(1); |
| 642 | + } |
| 643 | + } |
| 644 | + |
| 645 | + // Copy all built .so files to the workspace target directory |
| 646 | + let temp_so_dir = temp_dir.join("sbf-solana-solana/release"); |
| 647 | + |
| 648 | + // Use OUT_DIR to find workspace target directory |
| 649 | + let out_dir = std::env::var("OUT_DIR").expect("OUT_DIR should be set in build scripts"); |
| 650 | + |
| 651 | + // OUT_DIR pattern: /workspace/target/debug/build/crate-hash/out |
| 652 | + // Extract workspace root and construct target path |
| 653 | + let target_pos = out_dir.find("/target/").unwrap_or_else(|| { |
| 654 | + eprintln!("FATAL: Could not find '/target/' in OUT_DIR: {}", out_dir); |
| 655 | + eprintln!("Expected OUT_DIR pattern: /workspace/target/debug/build/crate-hash/out"); |
| 656 | + eprintln!("This indicates a problem with the cargo build environment."); |
| 657 | + std::process::exit(1); |
| 658 | + }); |
| 659 | + |
| 660 | + let workspace_root = &out_dir[..target_pos]; |
| 661 | + let workspace_target = std::path::PathBuf::from(format!( |
| 662 | + "{}/target/sbf-solana-solana/release", |
| 663 | + workspace_root |
| 664 | + )); |
| 665 | + |
| 666 | + if let Err(e) = fs::create_dir_all(&workspace_target) { |
| 667 | + eprintln!("Failed to create workspace target directory: {}", e); |
| 668 | + std::process::exit(1); |
| 669 | + } |
| 670 | + |
| 671 | + // Find and copy all .so files |
| 672 | + let entries = fs::read_dir(&temp_so_dir).unwrap_or_else(|e| { |
| 673 | + eprintln!( |
| 674 | + "FATAL: Could not read temp build directory: {}", |
| 675 | + temp_so_dir.display() |
| 676 | + ); |
| 677 | + eprintln!("Error: {}", e); |
| 678 | + eprintln!("This suggests the build failed or produced no output."); |
| 679 | + std::process::exit(1); |
| 680 | + }); |
| 681 | + |
| 682 | + let mut copied_files = 0; |
| 683 | + for entry in entries.flatten() { |
| 684 | + let path = entry.path(); |
| 685 | + if path.extension().map_or(false, |ext| ext == "so") { |
| 686 | + let filename = path.file_name().expect("File should have a name"); |
| 687 | + let target_path = workspace_target.join(filename); |
| 688 | + |
| 689 | + if let Err(e) = fs::copy(&path, &target_path) { |
| 690 | + eprintln!( |
| 691 | + "FATAL: Failed to copy .so file from {} to {}: {}", |
| 692 | + path.display(), |
| 693 | + target_path.display(), |
| 694 | + e |
| 695 | + ); |
| 696 | + std::process::exit(1); |
| 697 | + } |
| 698 | + |
| 699 | + println!("Successfully built and copied: {}", target_path.display()); |
| 700 | + copied_files += 1; |
| 701 | + } |
| 702 | + } |
| 703 | + |
| 704 | + if copied_files == 0 { |
| 705 | + eprintln!( |
| 706 | + "FATAL: No .so files found in build output directory: {}", |
| 707 | + temp_so_dir.display() |
| 708 | + ); |
| 709 | + eprintln!("The program compilation succeeded but produced no deployable artifacts."); |
| 710 | + eprintln!("Check that the program builds correctly with 'cargo build-sbf'."); |
| 711 | + std::process::exit(1); |
| 712 | + } |
| 713 | +} |
0 commit comments