1use crate::domain::{ElfMagicError, SolanaProgram};
2use std::fs;
3use std::path::{Path, PathBuf};
4use std::process::{Command, Stdio};
5
6pub fn build_programs(
10 cargo_target_dir: &Path,
11 programs: &[SolanaProgram],
12) -> Result<Vec<PathBuf>, ElfMagicError> {
13 programs
14 .iter()
15 .map(|program| build_program(cargo_target_dir, program))
16 .collect()
17}
18
19pub fn build_program(
24 cargo_target_dir: &Path,
25 program: &SolanaProgram,
26) -> Result<PathBuf, ElfMagicError> {
27 let sbf_out_dir = cargo_target_dir.join("elf-magic-bin");
29
30 let program_so_path = sbf_out_dir.join(format!("{}.so", program.name));
32
33 if program_so_path.exists() {
35 fs::remove_file(&program_so_path).map_err(|e| ElfMagicError::ProgramBuild {
36 program: program.name.clone(),
37 error: format!("Failed to remove existing .so file: {}", e),
38 })?;
39 }
40
41 let status = Command::new("cargo")
43 .args([
44 "build-sbf",
45 "--manifest-path",
46 &program.manifest_path.to_string_lossy(),
47 "--sbf-out-dir",
48 &sbf_out_dir.to_string_lossy(),
49 ])
50 .env(
51 "CARGO_TARGET_DIR", cargo_target_dir.to_string_lossy().into_owned(),
53 )
54 .stdout(Stdio::inherit())
55 .stderr(Stdio::inherit())
56 .status()
57 .map_err(|e| ElfMagicError::ProgramBuild {
58 program: program.name.clone(),
59 error: format!(
60 "Failed to execute cargo build-sbf: {}\nMake sure solana CLI tools are installed",
61 e
62 ),
63 })?;
64
65 if !status.success() {
66 return Err(ElfMagicError::ProgramBuild {
67 program: program.name.clone(),
68 error: format!("cargo build-sbf failed with exit code: {:?}", status.code()),
69 });
70 }
71
72 if !program_so_path.exists() {
74 return Err(ElfMagicError::ProgramBuild {
75 program: program.name.clone(),
76 error: format!(
77 "Expected .so file not found at: {}",
78 program_so_path.display()
79 ),
80 });
81 }
82
83 println!(
85 "cargo:rustc-env={}={}",
86 program.env_var_name(),
87 program_so_path.display()
88 );
89
90 Ok(program_so_path)
91}