diff --git a/buck/prefix-min/BUCK b/buck/prefix-min/BUCK index f8b8cffb2..fbcf16a34 100644 --- a/buck/prefix-min/BUCK +++ b/buck/prefix-min/BUCK @@ -477,6 +477,9 @@ prefix_tree( "libexec/cider/usr/lib/libz.1.dylib": "//vendor/src:z_dylib", "libexec/cider/usr/lib/native/libEGL.dylib": "//src/linux/native:EGL_dylib", "libexec/cider/usr/lib/native/libFreeType.dylib": "//src/linux/native:FreeType_dylib", + "libexec/cider/usr/lib/native/libwayland-client.dylib": "//src/linux/native:wayland-client_dylib", + "libexec/cider/usr/lib/native/libwayland-cursor.dylib": "//src/linux/native:wayland-cursor_dylib", + "libexec/cider/usr/lib/native/libxkbcommon.dylib": "//src/linux/native:xkbcommon_dylib", "libexec/cider/usr/lib/native/libX11.dylib": "//src/linux/native:X11_dylib", "libexec/cider/usr/lib/native/libXRandR.dylib": "//src/linux/native:XRandR_dylib", "libexec/cider/usr/lib/native/libXcursor.dylib": "//src/linux/native:Xcursor_dylib", diff --git a/buck/rules/rust.bzl b/buck/rules/rust.bzl index 649837a5e..278f1ed12 100644 --- a/buck/rules/rust.bzl +++ b/buck/rules/rust.bzl @@ -344,18 +344,23 @@ def _darwin_rust_staticlib_impl(ctx): cmd.add("--cfg", 'feature="%s"' % f) cmd.add(ctx.attrs.rustc_flags) - # NO MULTI FILE CRATES HERE, and the reason is recorded because it is not obvious. + # MULTI FILE CRATES ARE FINE NOW, and the history is kept because the reason was not obvious. # rustc finds a `mod` by following it from the crate root, so module files are HIDDEN inputs # that never appear in the argv, and `buck2 aquery` reports NO INPUT LIST AT ALL: the # attributes of an action are kind, category, identifier, cmd and executor knobs. The Nix - # endpoint therefore stages what the argv names and nothing else, and a `mod` file simply is - # not there, which surfaces as 205 compiler errors that say nothing about staging. + # endpoint therefore staged what the argv named and nothing else, and a `mod` file simply was + # not there, which surfaced as 205 compiler errors that said nothing about staging. # # Passing each src as an inert --cfg was tried and does NOT work: the path ends up embedded # inside `cider_module="..."` rather than being an argv token that IS a path. # - # So a guest crate is ONE FILE until the endpoint can be taught about hidden inputs. The hidden - # entry below is still correct for a direct buck2 build, where it drives rebuilds properly. + # WHAT FIXED IT was teaching the endpoint instead, which is where the gap always was: srcset.rs + # stages the whole DIRECTORY of any .rs in a rustc argv, and had done so for the host rule from + # the start; it just matched on the category `rustc` and this rule's category is + # darwin_rust_staticlib. Both are matched now. src/darwin/rustprobe is deliberately two files + # so the limit cannot come back unnoticed. + # + # The hidden entry below is what makes a DIRECT buck2 build rebuild on a module change. cmd.add(cmd_args(hidden = ctx.attrs.srcs)) ctx.actions.run(cmd, category = "darwin_rust_staticlib", identifier = ctx.label.name) return [ diff --git a/nix/ciderBuildInputs.nix b/nix/ciderBuildInputs.nix index 00cb160c0..69402937d 100644 --- a/nix/ciderBuildInputs.nix +++ b/nix/ciderBuildInputs.nix @@ -23,6 +23,11 @@ libXrandr, libXcursor, libxkbfile, + # WAYLAND, for the GUI backend that replaces X11 (task #112). wrapgen dlopens the real .so at + # BUILD time to read its dynamic symbol table, so these have to be present in the build inputs + # and not only at runtime. + wayland, + libxkbcommon, cairo, libglvnd, fontconfig, @@ -101,6 +106,8 @@ let libXrandr libXcursor libxkbfile + wayland + libxkbcommon cairo libglvnd fontconfig diff --git a/src/darwin/rustprobe/BUCK b/src/darwin/rustprobe/BUCK index 1f2cf5778..fc4b4a270 100644 --- a/src/darwin/rustprobe/BUCK +++ b/src/darwin/rustprobe/BUCK @@ -9,9 +9,13 @@ load("//buck/rules:rust.bzl", "darwin_rust_staticlib") # A build that succeeds proves the link, and the link was never the doubtful part. What the run # proves is that std works without Rust's lang_start: env_args must equal argc, which means # std::env::args found _NSGetArgv, format! reached the allocator, and println! reached stdout. +# TWO FILES, WHICH IS THE POINT. srcs is what makes a direct buck2 build rebuild when the module +# changes; the endpoint needs srcset.rs to stage the crate directory, which it now does for this +# rule's category as well as for the host one. darwin_rust_staticlib( name = "rustprobe_lib", crate_root = "probe.rs", + srcs = ["report.rs"], visibility = ["PUBLIC"], ) diff --git a/src/darwin/rustprobe/probe.rs b/src/darwin/rustprobe/probe.rs index c990a8567..80363dfe0 100644 --- a/src/darwin/rustprobe/probe.rs +++ b/src/darwin/rustprobe/probe.rs @@ -9,10 +9,14 @@ // the allocator. A probe that only returned 0 would link and prove nothing. use std::os::raw::{c_char, c_int}; +// SECOND FILE, DELIBERATELY. See report.rs: a `mod` in its own file is the hidden input the +// endpoint could not see, and this crate is now the check that it can. +mod report; + #[unsafe(no_mangle)] pub extern "C" fn main(argc: c_int, _argv: *const *const c_char) -> c_int { let from_env = std::env::args().count(); - let msg = format!("cider-rust-probe argc={argc} env_args={from_env}"); + let msg = report::line(argc, from_env); println!("{msg}"); if from_env as c_int == argc { 0 } else { 1 } } diff --git a/src/darwin/rustprobe/report.rs b/src/darwin/rustprobe/report.rs new file mode 100644 index 000000000..e8c237844 --- /dev/null +++ b/src/darwin/rustprobe/report.rs @@ -0,0 +1,16 @@ +// A SECOND FILE ON PURPOSE, and it is a check rather than a convenience. +// +// rustc finds this through `mod report;` in probe.rs, so it is a HIDDEN input: it appears in no +// argv and, because buck2 aquery reports no input list at all, in nothing the Nix endpoint can +// see either. Staging the crate ROOT and nothing else is what made a guest crate ONE FILE, and +// that limit is recorded in buck/rules/rust.bzl. srcset.rs now takes the whole directory for a +// darwin_rust_staticlib action, the same way it always has for a host rustc action. +// +// So if the endpoint ever regresses to staging only the root, this file stops existing during +// the build and the probe fails to compile with "file not found for module `report`". That is +// the point: the check is the crate itself, and it cannot pass by accident. + +/// The line the runtime check greps for, built here so the module is genuinely used. +pub fn line(argc: i32, from_env: usize) -> String { + format!("cider-rust-probe argc={argc} env_args={from_env}") +} diff --git a/src/linux/buildtools/graph-specs/src/srcset.rs b/src/linux/buildtools/graph-specs/src/srcset.rs index ba9d52a03..9ba19e8b6 100644 --- a/src/linux/buildtools/graph-specs/src/srcset.rs +++ b/src/linux/buildtools/graph-specs/src/srcset.rs @@ -463,7 +463,14 @@ pub fn target_sources( // "file not found for module `xnu`" after 1,462 green builders. for &i in acts { let ident = actions[i].get("identity").and_then(|v| v.as_str()).unwrap_or(""); - if !ident.contains("(rustc ") { + // BOTH RUST CATEGORIES, and the second one is why guest crates were single file. + // The host rule runs its action as category `rustc`; the guest rule + // (darwin_rust_staticlib in buck/rules/rust.bzl) runs its own, so a guest crate + // matched nothing here and got its crate ROOT staged and no `mod` files. That file + // records the consequence as "a guest crate is ONE FILE until the endpoint can be + // taught about hidden inputs" -- this is that lesson, and it is the same directory + // rule the host has always had. + if !ident.contains("(rustc ") && !ident.contains("(darwin_rust_staticlib ") { continue; } for tok in strs(&actions[i], "argv") { diff --git a/src/linux/native/BUCK b/src/linux/native/BUCK index 92a698e25..9cabf339f 100644 --- a/src/linux/native/BUCK +++ b/src/linux/native/BUCK @@ -30,6 +30,12 @@ _NATIVE = [ ("XRandR", "libXrandr.so", "/usr/lib/native"), ("Xcursor", "libXcursor.so", "/usr/lib/native"), ("xkbfile", "libxkbfile.so", "/usr/lib/native"), + # WAYLAND (#112). The GUI backend that replaces X11 reaches the compositor through these + # exactly the way the X11 backend reaches the X server: a generated Mach-O stub per library + # that forwards through libelfloader, so nothing has to be ported. + ("wayland-client", "libwayland-client.so", "/usr/lib/native"), + ("wayland-cursor", "libwayland-cursor.so", "/usr/lib/native"), + ("xkbcommon", "libxkbcommon.so", "/usr/lib/native"), ("cairo", "libcairo.so", "/usr/lib/native"), ("dbus", "libdbus-1.so", "/usr/lib/native"), # OpenGL's two live inside the framework rather than in /usr/lib/native, which is the @@ -57,6 +63,9 @@ _NATIVE = [ # buck-registry: libXRandR.dylib = XRandR_dylib # buck-registry: libXcursor.dylib = Xcursor_dylib # buck-registry: libxkbfile.dylib = xkbfile_dylib +# buck-registry: libwayland-client.dylib = wayland-client_dylib +# buck-registry: libwayland-cursor.dylib = wayland-cursor_dylib +# buck-registry: libxkbcommon.dylib = xkbcommon_dylib # buck-registry: libcairo.dylib = cairo_dylib # buck-registry: libdbus.dylib = dbus_dylib # buck-registry: libGL.dylib = GL_dylib