use std::fs;
use std::path::{Path, PathBuf};
fn main() {
generate_embedded_stdlib_sources();
}
fn generate_embedded_stdlib_sources() {
let out_dir = std::env::var("OUT_DIR").expect("OUT_DIR should be set");
let dest_path = Path::new(&out_dir).join("embedded_stdlib_modules.rs");
let stdlib_root = locate_stdlib_root();
println!("cargo:rerun-if-changed={}", stdlib_root.display());
emit_rerun_markers(&stdlib_root);
let modules = collect_stdlib_modules(&stdlib_root);
let mut generated = String::new();
generated.push_str("// Auto-generated by shape-runtime/build.rs - DO NOT EDIT\n");
generated.push_str("/// Embedded `std::...` modules (module path, source).\n");
generated.push_str("pub const EMBEDDED_STDLIB_MODULES: &[(&str, &str)] = &[\n");
for (module_path, source) in modules {
generated.push_str(&format!(" ({:?}, {:?}),\n", module_path, source));
}
generated.push_str("];\n");
fs::write(dest_path, generated).expect("failed to write embedded stdlib source map");
}
fn locate_stdlib_root() -> PathBuf {
let workspace_stdlib = Path::new("../shape-core/stdlib");
if workspace_stdlib.is_dir() {
return workspace_stdlib.to_path_buf();
}
let packaged_stdlib = Path::new("stdlib-src");
if packaged_stdlib.is_dir() {
return packaged_stdlib.to_path_buf();
}
panic!(
"shape-runtime build could not find stdlib sources in '{}' or '{}'",
workspace_stdlib.display(),
packaged_stdlib.display()
);
}
fn emit_rerun_markers(dir: &Path) {
let Ok(entries) = fs::read_dir(dir) else {
return;
};
for entry in entries.flatten() {
let path = entry.path();
println!("cargo:rerun-if-changed={}", path.display());
if path.is_dir() {
emit_rerun_markers(&path);
}
}
}
fn collect_stdlib_modules(stdlib_root: &Path) -> Vec<(String, String)> {
let mut files = Vec::new();
collect_shape_files_recursive(stdlib_root, &mut files);
files.sort();
files
.into_iter()
.filter_map(|path| {
let rel = path.strip_prefix(stdlib_root).ok()?;
let rel_no_ext = rel.with_extension("");
let mut module_path = String::from("std");
for segment in rel_no_ext.iter() {
module_path.push_str("::");
module_path.push_str(&segment.to_string_lossy());
}
let source = fs::read_to_string(&path).ok()?;
Some((module_path, source))
})
.collect()
}
fn collect_shape_files_recursive(dir: &Path, out: &mut Vec<PathBuf>) {
let Ok(entries) = fs::read_dir(dir) else {
return;
};
for entry in entries.flatten() {
let path = entry.path();
if path.is_dir() {
collect_shape_files_recursive(&path, out);
continue;
}
if path.extension().and_then(|s| s.to_str()) == Some("shape") {
out.push(path);
}
}
}