makepad/platform/build_gen.rs
Admin 0e52b1225f makepad run / Relax: half the memory on macOS, less cold-start work
- after the zone swap the cache file mappings are mapped again (device/inode
  checked), so clean file pages leave the resident set: Stage 2.3 GB -> 1.07 GB
  resident (peak 3.7 -> 1.8 GB), Calculator 600 -> 273 MB
- the platform build script is answered natively from one shared generator
  (platform/build_gen.rs, byte-identical to build.rs): 230-430 ms -> 0.2 ms
- crate records and the front graph are written after the first present and
  flushed on quit; the host window is joined after the load
- cold Calculator at 4 cores: CPU to present -7.5%, instructions -12%

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 10:32:15 +02:00

105 lines
4.5 KiB
Rust

//! What makepad-platform's build script generates, in one place: `platform/build.rs` (cargo) includes
//! this file with `#[path]`, and `makepad run` (libs/relax/front/src/unitgraph.rs) includes the same file
//! and answers the script natively, without booting a second Relax process for it. Plain std code, no
//! cargo calls: the two callers cannot drift (a test in relax-front runs the real build.rs against it).
#![allow(dead_code)]
use std::path::{Path, PathBuf};
/// Default bundle name when MAKEPAD_BUNDLE_NAME isn't set. Cargo doesn't expose the consuming
/// binary's package name to a dependency's build script (`CARGO_PKG_NAME` here is
/// "makepad-platform"), so walk up from `OUT_DIR` (always
/// `<root>/target/<profile>/build/<crate>-<hash>/out`) to the directory that contains `target/`
/// and use that directory's name, first letter capitalised. None if the path doesn't have the
/// expected shape or the directory name isn't valid UTF-8.
pub fn detect_app_name(out_dir: &Path) -> Option<String> {
let workspace_root = out_dir.ancestors().nth(5)?;
let dir_name = workspace_root.file_name()?.to_str()?;
if dir_name.is_empty() {
return None;
}
let mut chars = dir_name.chars();
let first = chars.next()?;
Some(first.to_uppercase().collect::<String>() + chars.as_str())
}
/// (bundle name, bundle identifier) of the build.
pub fn bundle(out_dir: &Path) -> (String, String) {
let name = detect_app_name(out_dir).unwrap_or_else(|| "Makepad App".to_string());
let id = format!("dev.makepad.{}", name.to_lowercase().replace(' ', "-"));
(name, id)
}
/// The text of OUT_DIR/app_meta_gen.rs.
pub fn app_meta_gen(out_dir: &Path) -> String {
let (bundle_name, bundle_id) = bundle(out_dir);
format!(
"/// The bundle name when the app's build sets no MAKEPAD_BUNDLE_NAME.\n\
pub const DEFAULT_BUNDLE_NAME: &str = {bundle_name:?};\n\
/// The identifier that goes with [`DEFAULT_BUNDLE_NAME`].\n\
pub const DEFAULT_BUNDLE_IDENTIFIER: &str = {bundle_id:?};\n"
)
}
/// Window icons auto-discovered in `<workspace_root>/resources/` (the dir containing `target/`,
/// 5 ancestors up from OUT_DIR, as in `detect_app_name`). An app's own icons (MAKEPAD_APP_ICON_*)
/// are read by `app_main!` in the app crate instead (src/app_meta.rs).
pub struct Icons {
/// the text of OUT_DIR/app_icon_gen.rs
pub source: String,
/// the icon files it includes
pub files: Vec<PathBuf>,
/// `<root>/resources` when it is a directory (cargo watches it)
pub dir: Option<PathBuf>,
}
pub fn app_icon_gen(out_dir: &Path) -> Icons {
let icons: &[(&str, &str)] = &[
("icon_32.png", "CUSTOM_ICON_PNG_32"),
("icon_64.png", "CUSTOM_ICON_PNG_64"),
("icon_128.png", "CUSTOM_ICON_PNG_128"),
("icon_256.png", "CUSTOM_ICON_PNG_256"),
("icon_512.png", "CUSTOM_ICON_PNG_512"),
("icon_1024.png", "CUSTOM_ICON_PNG_1024"),
("icon.ico", "CUSTOM_ICON_ICO"),
];
let resources_dir = out_dir.ancestors().nth(5).map(|r| r.join("resources"));
let mut source = String::new();
let mut files = Vec::new();
for &(filename, const_name) in icons {
let path = resources_dir.as_ref().and_then(|dir| {
let p = dir.join(filename);
p.is_file().then_some(p)
});
let value = match &path {
Some(p) => {
files.push(p.clone());
format!("include_bytes!(r#\"{}\"#)", p.to_string_lossy())
}
None => "&[]".to_string(),
};
source.push_str(&format!("#[allow(dead_code)] pub static {const_name}: &'static [u8] = {value};\n"));
}
Icons { source, files, dir: resources_dir.filter(|d| d.is_dir()) }
}
/// The `cargo:rustc-cfg=` words: the `lines` / `apple_bundle` words of MAKEPAD_BUILD (split on
/// `+` and `,`) and `apple_sim` for the iOS / tvOS simulator targets.
pub fn cfgs(makepad_build: Option<&str>, target_os: &str, target: &str) -> Vec<&'static str> {
let mut out = Vec::new();
if let Some(configs) = makepad_build {
for config in configs.split(['+', ',']) {
match config {
"lines" => out.push("lines"),
"apple_bundle" => out.push("apple_bundle"),
_ => {}
}
}
}
match target_os {
"ios" if target == "aarch64-apple-ios-sim" => out.push("apple_sim"),
"tvos" if target == "aarch64-apple-tvos-sim" => out.push("apple_sim"),
_ => {}
}
out
}