Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions crates/shell/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6375,8 +6375,9 @@ impl MatchEvent for App {
log!("octosense: background app prewarming disabled");
}
// A checkout run builds its catalog apps in the background, so their
// first open needn't wait for cargo (prebuild.rs).
prebuild::start(&cx.thread_spawner());
// first open needn't wait for cargo (prebuild.rs): those that open as
// a process, by the same rule `launch_app_with_args` applies.
prebuild::start(&cx.thread_spawner(), |id| self.apps.hosting(id) == Hosting::Module && self.apps.module(id).is_some());

// `--gallery`: the shell surfaces with fixture data instead of a
// desktop, so the port is verifiable over --remote (shell/gallery.rs).
Expand Down
33 changes: 27 additions & 6 deletions crates/shell/src/prebuild.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
//! builds once in the background, shortly after the shell starts, so a
//! later open finds its binary built and starts at once.
//!
//! - Only apps that open as a process: a linked module the shell hosts
//! in-process (Calculator, Clock, Notes, Reminders and Weather on macOS)
//! never runs its process build, so the prebuild leaves it out.
//! - One build at a time, in catalog order, each the exact command a launch
//! would run ([`clients::build_command`]), at background priority
//! (darwinbg on macOS, nice 19 elsewhere): it never competes with the
Expand Down Expand Up @@ -80,9 +83,13 @@ pub fn enabled(no_prebuild: Option<&str>) -> bool {

/// The builds to run: the launch build of every listed catalog app that has
/// one, each identical build once, in catalog order. Empty for an installed
/// shell (no checkout, so no app has a build).
pub fn plan(apps: &[AppDef], root: Option<&Path>) -> Vec<(String, BuildStep)> {
plan_listed(apps, root, crate::apps::listed)
/// shell (no checkout, so no app has a build). An app this shell opens
/// in-process (`in_process`: a linked module it hosts, such as Calculator,
/// Clock, Notes, Reminders and Weather on macOS) never runs that build, so
/// it is left out: on a fresh checkout those were five release builds
/// nothing would start.
pub fn plan(apps: &[AppDef], root: Option<&Path>, in_process: impl Fn(&str) -> bool) -> Vec<(String, BuildStep)> {
plan_listed(apps, root, |id| crate::apps::listed(id) && !in_process(id))
}

fn plan_listed(apps: &[AppDef], root: Option<&Path>, listed: impl Fn(&str) -> bool) -> Vec<(String, BuildStep)> {
Expand All @@ -103,12 +110,13 @@ fn plan_listed(apps: &[AppDef], root: Option<&Path>, listed: impl Fn(&str) -> bo
}

/// Start the prebuild on a worker of its own, when this shell runs from a
/// checkout and nothing turned it off.
pub fn start(spawner: &ThreadSpawner) {
/// checkout and nothing turned it off. `in_process`: whether a launch of an
/// app id would open it in-process, as the WM decides it at launch.
pub fn start(spawner: &ThreadSpawner, in_process: impl Fn(&str) -> bool) {
if !crate::host::processes_available() || !enabled(std::env::var("MAKEPAD_WM_NO_PREBUILD").ok().as_deref()) {
return;
}
let steps = plan(&clients::available_apps(), clients::repo_root().as_deref());
let steps = plan(&clients::available_apps(), clients::repo_root().as_deref(), in_process);
if steps.is_empty() {
return;
}
Expand Down Expand Up @@ -275,4 +283,17 @@ mod tests {
let steps = plan_listed(&[files()], Some(Path::new("/checkout")), |id| id != "files");
assert!(steps.is_empty(), "{steps:?}");
}

/// Calculator, Clock, Notes, Reminders and Weather open in-process on
/// macOS: their process build would never start, so it never runs.
#[test]
fn an_app_hosted_in_process_is_not_prebuilt() {
let clock = || AppDef::app("clock", "Clock", "makepad-clock", "", "clock", clients::LaunchPolicy::OrFocus);
let root = Path::new("/checkout");
assert_eq!(plan_listed(&[files(), clock()], Some(root), |_| true).len(), 2, "both have a launch build");
let steps: Vec<_> = plan_listed(&[files(), clock()], Some(root), |id| id != "clock");
assert_eq!(steps.iter().map(|(id, _)| id.as_str()).collect::<Vec<_>>(), ["files"]);
assert_eq!(plan(&[clock()], Some(root), |_| false).len(), 1, "as a process it is prebuilt");
assert!(plan(&[clock()], Some(root), |id| id == "clock").is_empty(), "in-process it is left out");
}
}
Loading