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
16pub 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) .unwrap_or_else(|_| env::temp_dir().join("elf-magic-target"));
28
29 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 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
67fn 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}