anaxa_builder/
build_rs.rs1use crate::{codegen, config_io, parser};
2use anyhow::{Context, Result};
3use std::env;
4use std::fs;
5use std::path::{Path, PathBuf};
6
7pub struct BuildHelper {
9 kconfig_dir: PathBuf,
10 config_file: PathBuf,
11 out_dir: PathBuf,
12}
13
14impl BuildHelper {
15 pub fn new() -> Result<Self> {
16 let out_dir = env::var_os("OUT_DIR").context("OUT_DIR not set")?.into();
17 Ok(Self {
18 kconfig_dir: PathBuf::from("src"),
19 config_file: PathBuf::from(".config"),
20 out_dir,
21 })
22 }
23
24 pub fn with_kconfig_dir<P: Into<PathBuf>>(mut self, dir: P) -> Self {
25 self.kconfig_dir = dir.into();
26 self
27 }
28
29 pub fn with_config_file<P: Into<PathBuf>>(mut self, file: P) -> Self {
30 self.config_file = file.into();
31 self
32 }
33
34 pub fn build(self) -> Result<()> {
35 check_version_compatibility()?;
36 let tree = parser::build_config_tree(&self.kconfig_dir)?;
37 let configs = parser::flatten_configs(&tree);
38 parser::validate_configs(&configs)?;
39 let values = config_io::load_config(&self.config_file, &configs)?;
40
41 let out_path = self.out_dir.join("config.rs");
42 let rust_code = codegen::rust::generate_consts(&configs, &values)?;
43 fs::write(&out_path, rust_code)
44 .with_context(|| format!("Failed to write to {:?}", out_path))?;
45
46 println!("cargo:rerun-if-changed={}", self.config_file.display());
47 emit_rerun_if_changed(&self.kconfig_dir)?;
48
49 for item in &configs {
50 if let Some(val) = values.get(&item.name) {
51 if val.as_bool() == Some(true) {
52 println!("cargo:rustc-cfg={}", item.name);
53 } else if val.as_bool() == None {
54 continue;
55 }
56 println!("cargo::rustc-check-cfg=cfg({})", item.name);
57 }
58 }
59
60 for (k, v) in values {
61 let v_str = match v {
62 toml::Value::String(s) => s,
63 toml::Value::Integer(i) => i.to_string(),
64 toml::Value::Float(f) => f.to_string(),
65 toml::Value::Boolean(b) => b.to_string(),
66 _ => continue,
67 };
68 println!("cargo:rustc-env=ANAXA_{}={}", k.to_uppercase(), v_str);
69 }
70
71 Ok(())
72 }
73}
74
75pub fn emit_cargo_instructions<P1, P2>(kconfig_dir: P1, config_file: P2) -> Result<()>
84where
85 P1: AsRef<Path>,
86 P2: AsRef<Path>,
87{
88 check_version_compatibility()?;
89 let kconfig_dir = kconfig_dir.as_ref();
90 let config_file = config_file.as_ref();
91
92 let tree = parser::build_config_tree(kconfig_dir)?;
93 let configs = parser::flatten_configs(&tree);
94 parser::validate_configs(&configs)?;
95
96 let values = config_io::load_config(config_file, &configs)?;
97
98 let out_dir = env::var_os("OUT_DIR").context("OUT_DIR not set")?;
99 let out_path = PathBuf::from(out_dir).join("config.rs");
100 let rust_code = codegen::rust::generate_consts(&configs, &values)?;
101 fs::write(&out_path, rust_code)
102 .with_context(|| format!("Failed to write to {:?}", out_path))?;
103
104 println!("cargo:rerun-if-changed={}", config_file.display());
105
106 emit_rerun_if_changed(kconfig_dir)?;
107
108 for item in &configs {
109 if let Some(val) = values.get(&item.name) {
110 if val.as_bool() == Some(true) {
111 println!("cargo:rustc-cfg={}", item.name);
112 }
113 }
114 }
115
116 Ok(())
117}
118
119fn emit_rerun_if_changed(dir: &Path) -> Result<()> {
120 use walkdir::WalkDir;
121 for entry in WalkDir::new(dir).into_iter().filter_map(|e| e.ok()) {
122 if entry.file_name() == "Kconfig.toml" {
123 println!("cargo:rerun-if-changed={}", entry.path().display());
124 }
125 }
126 Ok(())
127}
128
129fn check_version_compatibility() -> Result<()> {
130 if let Ok(cli_version) = env::var("ANAXA_CLI_VERSION") {
131 let lib_version = env!("CARGO_PKG_VERSION");
132 if cli_version != lib_version {
133 let cli_parts: Vec<&str> = cli_version.split('.').collect();
135 let lib_parts: Vec<&str> = lib_version.split('.').collect();
136
137 if cli_parts.len() >= 2 && lib_parts.len() >= 2 {
138 if cli_parts[0] != lib_parts[0] || cli_parts[1] != lib_parts[1] {
139 println!(
140 "cargo:warning=Version mismatch: anaxa-builder CLI (v{}) and library (v{}) are not compatible.",
141 cli_version, lib_version
142 );
143 println!(
144 "cargo:warning=Please ensure both CLI and library have the same major.minor version."
145 );
146 }
147 } else if cli_version != lib_version {
148 println!(
149 "cargo:warning=Version mismatch detected: CLI v{}, Lib v{}",
150 cli_version, lib_version
151 );
152 }
153 }
154 }
155 Ok(())
156}