elf_magic/
lib.rs

1mod builder;
2mod codegen;
3mod config;
4mod error;
5mod programs;
6mod workspace;
7
8use std::{env, path::PathBuf};
9
10use crate::{
11    config::Config,
12    error::Error,
13    programs::{GenerationResult, SolanaProgram},
14};
15
16/// Generate Rust bindings for Solana programs
17pub fn generate() -> Result<GenerationResult, Error> {
18    let cargo_manifest_dir = env::var("CARGO_MANIFEST_DIR")
19        .map(PathBuf::from)
20        .map_err(|e| {
21            let message = format!("CARGO_MANIFEST_DIR not set: {}", e);
22            Error::WorkspaceDiscovery(message)
23        })?;
24
25    let cargo_target_dir = env::var("CARGO_TARGET_DIR")
26        .map(PathBuf::from) // important default, DO NOT CHANGE:
27        .unwrap_or_else(|_| env::temp_dir().join("elf-magic-target"));
28
29    // Core pipeline:
30    // 1. load config
31    // 2. load workspaces
32    // 3. discover programs across all workspaces
33    // 4. build included programs across all workspaces
34    // 5. generate code - one lib.rs from all included programs
35    // 6. enable incremental builds for all included programs
36
37    let config = Config::load(&cargo_manifest_dir)?;
38
39    let workspaces = workspace::load_workspaces(&config)?;
40
41    let discovered_programs = workspaces
42        .iter()
43        .map(|w| w.discover_programs())
44        .collect::<Result<Vec<_>, _>>()?;
45
46    // Extract all programs for building and code generation
47    let included_programs: Vec<SolanaProgram> = discovered_programs
48        .iter()
49        .flat_map(|w| w.included.iter().cloned())
50        .collect();
51
52    builder::build_programs(&cargo_target_dir, &included_programs)?;
53
54    let code = codegen::generate(&included_programs)?;
55    codegen::save(&cargo_manifest_dir, &code)?;
56
57    enable_incremental_builds(&included_programs)?;
58
59    let mode = match &config {
60        Config::Magic => "magic".to_string(),
61        Config::Pedantic { .. } => "pedantic".to_string(),
62    };
63
64    Ok(GenerationResult::new(mode, discovered_programs))
65}
66
67/// Enable incremental builds for each program
68fn enable_incremental_builds(programs: &[SolanaProgram]) -> Result<(), Error> {
69    for program in programs {
70        println!("cargo:rerun-if-changed={}", program.manifest_path.display());
71    }
72    Ok(())
73}