use crate::domain::{ElfMagicError, SolanaProgram};
use std::fs;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
pub fn build_programs(
cargo_target_dir: &Path,
programs: &[SolanaProgram],
) -> Result<Vec<PathBuf>, ElfMagicError> {
programs
.iter()
.map(|program| build_program(cargo_target_dir, program))
.collect()
}
pub fn build_program(
cargo_target_dir: &Path,
program: &SolanaProgram,
) -> Result<PathBuf, ElfMagicError> {
let sbf_out_dir = cargo_target_dir.join("elf-magic-bin");
let program_so_path = sbf_out_dir.join(format!("{}.so", program.name));
if program_so_path.exists() {
fs::remove_file(&program_so_path).map_err(|e| ElfMagicError::ProgramBuild {
program: program.name.clone(),
error: format!("Failed to remove existing .so file: {}", e),
})?;
}
let status = Command::new("cargo")
.args([
"build-sbf",
"--manifest-path",
&program.manifest_path.to_string_lossy(),
"--sbf-out-dir",
&sbf_out_dir.to_string_lossy(),
])
.env(
"CARGO_TARGET_DIR", cargo_target_dir.to_string_lossy().into_owned(),
)
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.status()
.map_err(|e| ElfMagicError::ProgramBuild {
program: program.name.clone(),
error: format!(
"Failed to execute cargo build-sbf: {}\nMake sure solana CLI tools are installed",
e
),
})?;
if !status.success() {
return Err(ElfMagicError::ProgramBuild {
program: program.name.clone(),
error: format!("cargo build-sbf failed with exit code: {:?}", status.code()),
});
}
if !program_so_path.exists() {
return Err(ElfMagicError::ProgramBuild {
program: program.name.clone(),
error: format!(
"Expected .so file not found at: {}",
program_so_path.display()
),
});
}
println!(
"cargo:rustc-env={}={}",
program.env_var_name(),
program_so_path.display()
);
Ok(program_so_path)
}