Run this tree on a native half the builders made
`just run` fetched the release the dotslash pins name, which answers the wrong question: a change to jolt-native is by definition not in a release yet, so the one run that is meant to show it working was the one run that could not. Everything under the frq source now comes from the flake and is built — jolt, glimmer, glimmer-vidya and both objects, at the revs flake.lock names, so a run says what it ran against and both halves of glimmer-vidya move together. The shell is where that is said, and entering it is the build. run.bb re-execs itself inside `nix develop` and asks for it with --max-jobs 0: left to the default nix prefers the local machine, and a cold jolt-native is egui and openh264 on a laptop for a derivation nixbuild has likely built already. Which is also why this is the cargo build rather than jolt-native's own buck2 graph, and that is a compromise: buck2 is what its CI runs and its cpal has the pipewire feature this one does not, so device names in a call come out as ALSA PCMs. But buck2 fetches its toolchain and every crate as it goes and writes buck-out into the tree it builds, and a sandbox with no network and a read-only store is the one place it cannot run. On a remote builder it is not the slower option, it is not an option. `just lib` and the pins are untouched — the APK and the buck2 build still take the released bytes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
a32699e parent: 4a372ae modified
flake.nix +79 -19 | @@ -86,16 +86,39 @@ | ||
| 86 | 86 | systems = [ "x86_64-linux" "aarch64-linux" ]; |
| 87 | 87 | forEachSystem = f: |
| 88 | 88 | nixpkgs.lib.genAttrs systems (system: f nixpkgs.legacyPackages.${system}); |
| 89 | + | |
| 90 | + # Mesa, despite the name: it covers Intel and AMD alike. The NVIDIA | |
| 91 | + # wrappers are the ones that need --impure (they read the host kernel | |
| 92 | + # module's version), which is why this only ever reaches for Intel. | |
| 93 | + nixGLFor = pkgs: nixgl.packages.${pkgs.stdenv.hostPlatform.system}.nixGLIntel; | |
| 94 | + | |
| 95 | + # egui reaches for these with dlopen rather than linking them, so being | |
| 96 | + # in the cdylib's buildInputs is not enough — whatever starts frq has to | |
| 97 | + # put them on the loader path itself. Without libX11 here, vidya reports | |
| 98 | + # "X11 unavailable", falls back to Wayland, and winit refuses to build a | |
| 99 | + # second event loop after the failed first one. | |
| 100 | + # | |
| 101 | + # Out here rather than beside the package that first needed them: the | |
| 102 | + # dev shell starts frq too, on this tree's source rather than the store's | |
| 103 | + # copy of it, and a second copy of this list is a second chance for the | |
| 104 | + # two ways of running to disagree about what the window needs. | |
| 105 | + runtimeLibsFor = pkgs: with pkgs; [ | |
| 106 | + libGL | |
| 107 | + libxkbcommon | |
| 108 | + wayland | |
| 109 | + xorg.libX11 | |
| 110 | + xorg.libXcursor | |
| 111 | + xorg.libXi | |
| 112 | + xorg.libXrandr | |
| 113 | + vulkan-loader | |
| 114 | + ]; | |
| 89 | 115 | in |
| 90 | 116 | { |
| 91 | 117 | packages = forEachSystem (pkgs: |
| 92 | 118 | let |
| 93 | 119 | inherit (pkgs) lib; |
| 94 | 120 | |
| 95 | - # Mesa, despite the name: it covers Intel and AMD alike. The NVIDIA | |
| 96 | - # wrappers are the ones that need --impure (they read the host kernel | |
| 97 | - # module's version), which is why this only ever reaches for Intel. | |
| 98 | - nixGL = nixgl.packages.${pkgs.stdenv.hostPlatform.system}.nixGLIntel; | |
| 121 | + nixGL = nixGLFor pkgs; | |
| 99 | 122 | |
| 100 | 123 | # libvidya (the retained-tree ABI glimmer-vidya binds, on egui) and |
| 101 | 124 | # libjoltmoq (the AV media plane). One workspace, two cdylibs. |
| @@ -202,21 +225,7 @@ | ||
| 202 | 225 | # answers for both. |
| 203 | 226 | glimmerVidya = "${jolt-native}/jolt/glimmer-vidya"; |
| 204 | 227 | |
| 205 | - # egui reaches for these with dlopen rather than linking them, so | |
| 206 | - # being in the cdylib's buildInputs is not enough — the launcher has | |
| 207 | - # to put them on the loader path itself. Without libX11 here, vidya | |
| 208 | - # reports "X11 unavailable", falls back to Wayland, and winit refuses | |
| 209 | - # to build a second event loop after the failed first one. | |
| 210 | - runtimeLibs = with pkgs; [ | |
| 211 | - libGL | |
| 212 | - libxkbcommon | |
| 213 | - wayland | |
| 214 | - xorg.libX11 | |
| 215 | - xorg.libXcursor | |
| 216 | - xorg.libXi | |
| 217 | - xorg.libXrandr | |
| 218 | - vulkan-loader | |
| 219 | - ]; | |
| 228 | + runtimeLibs = runtimeLibsFor pkgs; | |
| 220 | 229 | |
| 221 | 230 | # The project as jolt sees it: source, deps.edn, nothing else. |
| 222 | 231 | frqSource = pkgs.runCommand "frq-source" { } '' |
| @@ -304,6 +313,57 @@ | ||
| 304 | 313 | apk-unsigned = android.apk-unsigned; |
| 305 | 314 | }); |
| 306 | 315 | |
| 316 | + # Where `just run` runs, and — because entering it realises what it | |
| 317 | + # names — what builds the half of frq that is not this working tree. | |
| 318 | + # | |
| 319 | + # The two halves, and the split is the whole point of the shell. The frq | |
| 320 | + # source is the files on disk, uncommitted edits and all. Everything | |
| 321 | + # under it — jolt, glimmer, glimmer-vidya, both native objects — is the | |
| 322 | + # flake's, at the revs flake.lock names, so a run says what it ran | |
| 323 | + # against and both halves of glimmer-vidya move together. That is the | |
| 324 | + # drift the `jolt-native` input's comment is about, and a pin frq can | |
| 325 | + # answer for is worth more here than the convenience of a checkout. | |
| 326 | + # | |
| 327 | + # `native` is the cargo build of that input rather than jolt-native's own | |
| 328 | + # buck2 graph, which is a compromise and not a free one: buck2 is what | |
| 329 | + # its CI runs and what makes its releases, and its cpal has the pipewire | |
| 330 | + # feature this one does not, so device *names* in a call come out as ALSA | |
| 331 | + # PCMs. What it buys is a derivation — one thing nixbuild.net can be | |
| 332 | + # handed. The buck2 build fetches its rustc, zig and every third-party | |
| 333 | + # crate as it goes and writes buck-out into the tree it builds; a sandbox | |
| 334 | + # with no network and a read-only store is the one place it cannot run, | |
| 335 | + # so on a remote builder it is not a slower option but no option at all. | |
| 336 | + # | |
| 337 | + # Nothing here says "nixbuild", though: it is a plain derivation, and | |
| 338 | + # where it gets built is the machine's business. scripts/run.bb asks for | |
| 339 | + # the shell with --max-jobs 0, which is what sends it to the `builders` | |
| 340 | + # entry rather than compiling egui on a laptop. | |
| 341 | + devShells = forEachSystem (pkgs: | |
| 342 | + let | |
| 343 | + inherit (pkgs) lib; | |
| 344 | + inherit (self.packages.${pkgs.stdenv.hostPlatform.system}) jolt native; | |
| 345 | + in | |
| 346 | + { | |
| 347 | + default = pkgs.mkShellNoCC { | |
| 348 | + name = "frq"; | |
| 349 | + | |
| 350 | + # jolt, because the runtime frq is run by should be the flake's | |
| 351 | + # too. nixGL for the same reason the launcher reaches for it — see | |
| 352 | + # frqScript. | |
| 353 | + packages = [ jolt (nixGLFor pkgs) ]; | |
| 354 | + | |
| 355 | + # Read by scripts/run.bb rather than baked into a wrapper: the frq | |
| 356 | + # source `just run` runs is the working tree, so the launcher has | |
| 357 | + # to be a script in that tree and the shell has to hand it its | |
| 358 | + # answers. Naming these is also what makes the shell build them. | |
| 359 | + JOLT_NATIVE_LIB = "${native}/lib"; | |
| 360 | + GLIMMER_SRC = glimmer; | |
| 361 | + GLIMMER_VIDYA_SRC = "${jolt-native}/jolt/glimmer-vidya"; | |
| 362 | + FRQ_LIB_PATH = lib.makeLibraryPath (runtimeLibsFor pkgs); | |
| 363 | + NIXGL = "${nixGLFor pkgs}/bin/nixGLIntel"; | |
| 364 | + }; | |
| 365 | + }); | |
| 366 | + | |
| 307 | 367 | apps = forEachSystem (pkgs: { |
| 308 | 368 | default = { |
| 309 | 369 | type = "app"; |
| @@ -86,16 +86,39 @@ | |||
| 86 | systems = [ "x86_64-linux" "aarch64-linux" ]; | 86 | systems = [ "x86_64-linux" "aarch64-linux" ]; |
| 87 | forEachSystem = f: | 87 | forEachSystem = f: |
| 88 | nixpkgs.lib.genAttrs systems (system: f nixpkgs.legacyPackages.${system}); | 88 | nixpkgs.lib.genAttrs systems (system: f nixpkgs.legacyPackages.${system}); |
| 89 | + | ||
| 90 | + # Mesa, despite the name: it covers Intel and AMD alike. The NVIDIA | ||
| 91 | + # wrappers are the ones that need --impure (they read the host kernel | ||
| 92 | + # module's version), which is why this only ever reaches for Intel. | ||
| 93 | + nixGLFor = pkgs: nixgl.packages.${pkgs.stdenv.hostPlatform.system}.nixGLIntel; | ||
| 94 | + | ||
| 95 | + # egui reaches for these with dlopen rather than linking them, so being | ||
| 96 | + # in the cdylib's buildInputs is not enough — whatever starts frq has to | ||
| 97 | + # put them on the loader path itself. Without libX11 here, vidya reports | ||
| 98 | + # "X11 unavailable", falls back to Wayland, and winit refuses to build a | ||
| 99 | + # second event loop after the failed first one. | ||
| 100 | + # | ||
| 101 | + # Out here rather than beside the package that first needed them: the | ||
| 102 | + # dev shell starts frq too, on this tree's source rather than the store's | ||
| 103 | + # copy of it, and a second copy of this list is a second chance for the | ||
| 104 | + # two ways of running to disagree about what the window needs. | ||
| 105 | + runtimeLibsFor = pkgs: with pkgs; [ | ||
| 106 | + libGL | ||
| 107 | + libxkbcommon | ||
| 108 | + wayland | ||
| 109 | + xorg.libX11 | ||
| 110 | + xorg.libXcursor | ||
| 111 | + xorg.libXi | ||
| 112 | + xorg.libXrandr | ||
| 113 | + vulkan-loader | ||
| 114 | + ]; | ||
| 89 | in | 115 | in |
| 90 | { | 116 | { |
| 91 | packages = forEachSystem (pkgs: | 117 | packages = forEachSystem (pkgs: |
| 92 | let | 118 | let |
| 93 | inherit (pkgs) lib; | 119 | inherit (pkgs) lib; |
| 94 | 120 | ||
| 95 | - # Mesa, despite the name: it covers Intel and AMD alike. The NVIDIA | 121 | + nixGL = nixGLFor pkgs; |
| 96 | - # wrappers are the ones that need --impure (they read the host kernel | ||
| 97 | - # module's version), which is why this only ever reaches for Intel. | ||
| 98 | - nixGL = nixgl.packages.${pkgs.stdenv.hostPlatform.system}.nixGLIntel; | ||
| 99 | 122 | ||
| 100 | # libvidya (the retained-tree ABI glimmer-vidya binds, on egui) and | 123 | # libvidya (the retained-tree ABI glimmer-vidya binds, on egui) and |
| 101 | # libjoltmoq (the AV media plane). One workspace, two cdylibs. | 124 | # libjoltmoq (the AV media plane). One workspace, two cdylibs. |
| @@ -202,21 +225,7 @@ | |||
| 202 | # answers for both. | 225 | # answers for both. |
| 203 | glimmerVidya = "${jolt-native}/jolt/glimmer-vidya"; | 226 | glimmerVidya = "${jolt-native}/jolt/glimmer-vidya"; |
| 204 | 227 | ||
| 205 | - # egui reaches for these with dlopen rather than linking them, so | 228 | + runtimeLibs = runtimeLibsFor pkgs; |
| 206 | - # being in the cdylib's buildInputs is not enough — the launcher has | ||
| 207 | - # to put them on the loader path itself. Without libX11 here, vidya | ||
| 208 | - # reports "X11 unavailable", falls back to Wayland, and winit refuses | ||
| 209 | - # to build a second event loop after the failed first one. | ||
| 210 | - runtimeLibs = with pkgs; [ | ||
| 211 | - libGL | ||
| 212 | - libxkbcommon | ||
| 213 | - wayland | ||
| 214 | - xorg.libX11 | ||
| 215 | - xorg.libXcursor | ||
| 216 | - xorg.libXi | ||
| 217 | - xorg.libXrandr | ||
| 218 | - vulkan-loader | ||
| 219 | - ]; | ||
| 220 | 229 | ||
| 221 | # The project as jolt sees it: source, deps.edn, nothing else. | 230 | # The project as jolt sees it: source, deps.edn, nothing else. |
| 222 | frqSource = pkgs.runCommand "frq-source" { } '' | 231 | frqSource = pkgs.runCommand "frq-source" { } '' |
| @@ -304,6 +313,57 @@ | |||
| 304 | apk-unsigned = android.apk-unsigned; | 313 | apk-unsigned = android.apk-unsigned; |
| 305 | }); | 314 | }); |
| 306 | 315 | ||
| 316 | + # Where `just run` runs, and — because entering it realises what it | ||
| 317 | + # names — what builds the half of frq that is not this working tree. | ||
| 318 | + # | ||
| 319 | + # The two halves, and the split is the whole point of the shell. The frq | ||
| 320 | + # source is the files on disk, uncommitted edits and all. Everything | ||
| 321 | + # under it — jolt, glimmer, glimmer-vidya, both native objects — is the | ||
| 322 | + # flake's, at the revs flake.lock names, so a run says what it ran | ||
| 323 | + # against and both halves of glimmer-vidya move together. That is the | ||
| 324 | + # drift the `jolt-native` input's comment is about, and a pin frq can | ||
| 325 | + # answer for is worth more here than the convenience of a checkout. | ||
| 326 | + # | ||
| 327 | + # `native` is the cargo build of that input rather than jolt-native's own | ||
| 328 | + # buck2 graph, which is a compromise and not a free one: buck2 is what | ||
| 329 | + # its CI runs and what makes its releases, and its cpal has the pipewire | ||
| 330 | + # feature this one does not, so device *names* in a call come out as ALSA | ||
| 331 | + # PCMs. What it buys is a derivation — one thing nixbuild.net can be | ||
| 332 | + # handed. The buck2 build fetches its rustc, zig and every third-party | ||
| 333 | + # crate as it goes and writes buck-out into the tree it builds; a sandbox | ||
| 334 | + # with no network and a read-only store is the one place it cannot run, | ||
| 335 | + # so on a remote builder it is not a slower option but no option at all. | ||
| 336 | + # | ||
| 337 | + # Nothing here says "nixbuild", though: it is a plain derivation, and | ||
| 338 | + # where it gets built is the machine's business. scripts/run.bb asks for | ||
| 339 | + # the shell with --max-jobs 0, which is what sends it to the `builders` | ||
| 340 | + # entry rather than compiling egui on a laptop. | ||
| 341 | + devShells = forEachSystem (pkgs: | ||
| 342 | + let | ||
| 343 | + inherit (pkgs) lib; | ||
| 344 | + inherit (self.packages.${pkgs.stdenv.hostPlatform.system}) jolt native; | ||
| 345 | + in | ||
| 346 | + { | ||
| 347 | + default = pkgs.mkShellNoCC { | ||
| 348 | + name = "frq"; | ||
| 349 | + | ||
| 350 | + # jolt, because the runtime frq is run by should be the flake's | ||
| 351 | + # too. nixGL for the same reason the launcher reaches for it — see | ||
| 352 | + # frqScript. | ||
| 353 | + packages = [ jolt (nixGLFor pkgs) ]; | ||
| 354 | + | ||
| 355 | + # Read by scripts/run.bb rather than baked into a wrapper: the frq | ||
| 356 | + # source `just run` runs is the working tree, so the launcher has | ||
| 357 | + # to be a script in that tree and the shell has to hand it its | ||
| 358 | + # answers. Naming these is also what makes the shell build them. | ||
| 359 | + JOLT_NATIVE_LIB = "${native}/lib"; | ||
| 360 | + GLIMMER_SRC = glimmer; | ||
| 361 | + GLIMMER_VIDYA_SRC = "${jolt-native}/jolt/glimmer-vidya"; | ||
| 362 | + FRQ_LIB_PATH = lib.makeLibraryPath (runtimeLibsFor pkgs); | ||
| 363 | + NIXGL = "${nixGLFor pkgs}/bin/nixGLIntel"; | ||
| 364 | + }; | ||
| 365 | + }); | ||
| 366 | + | ||
| 307 | apps = forEachSystem (pkgs: { | 367 | apps = forEachSystem (pkgs: { |
| 308 | default = { | 368 | default = { |
| 309 | type = "app"; | 369 | type = "app"; |
modified
justfile +2 -2 | @@ -8,7 +8,7 @@ set shell := ["bash", "-euo", "pipefail", "-c"] | ||
| 8 | 8 | default: |
| 9 | 9 | @just --list |
| 10 | 10 | |
| 11 | -# Both native libraries, cloning jolt-native at the pinned commit if needed. | |
| 11 | +# Both native libraries, out of the release pins. `run` builds them instead. | |
| 12 | 12 | lib: |
| 13 | 13 | scripts/lib.bb |
| 14 | 14 | |
| @@ -28,6 +28,6 @@ bump tag="": | ||
| 28 | 28 | sync-dist: |
| 29 | 29 | scripts/dotslash-to-buck |
| 30 | 30 | |
| 31 | -# The app. | |
| 31 | +# The app: this tree's source on the flake's everything-else, in the dev shell. | |
| 32 | 32 | run *args: |
| 33 | 33 | scripts/run.bb {{args}} |
| @@ -8,7 +8,7 @@ set shell := ["bash", "-euo", "pipefail", "-c"] | |||
| 8 | default: | 8 | default: |
| 9 | @just --list | 9 | @just --list |
| 10 | 10 | ||
| 11 | -# Both native libraries, cloning jolt-native at the pinned commit if needed. | 11 | +# Both native libraries, out of the release pins. `run` builds them instead. |
| 12 | lib: | 12 | lib: |
| 13 | scripts/lib.bb | 13 | scripts/lib.bb |
| 14 | 14 | ||
| @@ -28,6 +28,6 @@ bump tag="": | |||
| 28 | sync-dist: | 28 | sync-dist: |
| 29 | scripts/dotslash-to-buck | 29 | scripts/dotslash-to-buck |
| 30 | 30 | ||
| 31 | -# The app. | 31 | +# The app: this tree's source on the flake's everything-else, in the dev shell. |
| 32 | run *args: | 32 | run *args: |
| 33 | scripts/run.bb {{args}} | 33 | scripts/run.bb {{args}} |
modified
scripts/lib.bb +4 -2 | @@ -7,8 +7,10 @@ exec "$(dirname "$0")/bb" "$0" "$@" | ||
| 7 | 7 | ;; |
| 8 | 8 | ;; libvidya is the tree ABI glimmer-vidya binds; libjoltmoq is the AV media |
| 9 | 9 | ;; plane. They come out of one archive because they are built together, and |
| 10 | -;; they land in build/lib because a loader wants one directory, which is where | |
| 11 | -;; run.bb points LD_LIBRARY_PATH. | |
| 10 | +;; they land in build/lib because a loader wants one directory. `just run` does | |
| 11 | +;; not come through here — running a change to jolt-native means building it, | |
| 12 | +;; which is what the dev shell is for — so this is the released half: what the | |
| 13 | +;; APK and the buck2 build take, and what a run of the last release takes. | |
| 12 | 14 | ;; |
| 13 | 15 | ;; Nothing is compiled here. The pinned bytes are the bytes: this repo used to |
| 14 | 16 | ;; clone jolt-native and cargo-build it, which meant a Rust toolchain, a build |
| @@ -7,8 +7,10 @@ exec "$(dirname "$0")/bb" "$0" "$@" | |||
| 7 | ;; | 7 | ;; |
| 8 | ;; libvidya is the tree ABI glimmer-vidya binds; libjoltmoq is the AV media | 8 | ;; libvidya is the tree ABI glimmer-vidya binds; libjoltmoq is the AV media |
| 9 | ;; plane. They come out of one archive because they are built together, and | 9 | ;; plane. They come out of one archive because they are built together, and |
| 10 | -;; they land in build/lib because a loader wants one directory, which is where | 10 | +;; they land in build/lib because a loader wants one directory. `just run` does |
| 11 | -;; run.bb points LD_LIBRARY_PATH. | 11 | +;; not come through here — running a change to jolt-native means building it, |
| 12 | +;; which is what the dev shell is for — so this is the released half: what the | ||
| 13 | +;; APK and the buck2 build take, and what a run of the last release takes. | ||
| 12 | ;; | 14 | ;; |
| 13 | ;; Nothing is compiled here. The pinned bytes are the bytes: this repo used to | 15 | ;; Nothing is compiled here. The pinned bytes are the bytes: this repo used to |
| 14 | ;; clone jolt-native and cargo-build it, which meant a Rust toolchain, a build | 16 | ;; clone jolt-native and cargo-build it, which meant a Rust toolchain, a build |
modified
scripts/run.bb +63 -18 | @@ -7,37 +7,82 @@ exec "$(dirname "$0")/bb" "$0" "$@" | ||
| 7 | 7 | ;; |
| 8 | 8 | ;; run.bb [args...] |
| 9 | 9 | ;; |
| 10 | -;; Everything but the source is pinned: jolt comes from scripts/jolt.dotslash | |
| 11 | -;; and the two native libraries from scripts/lib*.dotslash, fetched by digest | |
| 12 | -;; and linked into build/lib, which is the one directory the loader is pointed | |
| 13 | -;; at. `just lib` is done here rather than asked for — the pins say what those | |
| 14 | -;; bytes are, so there is nothing for a person to decide before running. | |
| 10 | +;; Two halves, and the split is the point. The frq source is the files on disk, | |
| 11 | +;; uncommitted edits and all. Everything under it — jolt, glimmer, | |
| 12 | +;; glimmer-vidya, both native objects — is the flake's, built rather than | |
| 13 | +;; fetched: this re-execs itself inside `nix develop`, and that shell is the | |
| 14 | +;; jolt-native input compiled and the Jolt halves that bind it, at the revs | |
| 15 | +;; flake.lock names. | |
| 15 | 16 | ;; |
| 16 | 17 | ;; Deliberately not `nix run .#frq`. That builds the flake's own copy of the |
| 17 | 18 | ;; source, which is the tree as git has it — so an edit that has not been |
| 18 | 19 | ;; committed, or has been committed on a branch the command was not pointed at, |
| 19 | 20 | ;; runs as whatever was there before, silently. A run that is meant to answer |
| 20 | 21 | ;; "does my change work" has to be the files on disk. |
| 21 | -(require '[babashka.fs :as fs] | |
| 22 | - '[babashka.process :as p]) | |
| 22 | +;; | |
| 23 | +;; And deliberately not the scripts/*.dotslash pins either, which is what this | |
| 24 | +;; used to do. Those name a release; a change to jolt-native is by definition | |
| 25 | +;; not in one yet. `just lib` still fetches them — the APK and the buck2 build | |
| 26 | +;; take the released bytes — but a run does not. | |
| 27 | +(require '[babashka.classpath :as cp]) | |
| 28 | +(cp/add-classpath (str (babashka.fs/parent *file*))) | |
| 29 | +(require '[frq.paths :as paths] | |
| 30 | + '[babashka.fs :as fs] | |
| 31 | + '[babashka.process :as p] | |
| 32 | + '[clojure.string :as str]) | |
| 23 | 33 | |
| 24 | 34 | (def root (str (fs/canonicalize (fs/path (fs/parent *file*) "..")))) |
| 25 | -(def lib (str (fs/path root "build" "lib"))) | |
| 35 | +(def self (str (fs/path root "scripts" "run.bb"))) | |
| 36 | + | |
| 37 | +;; Outside the shell, get inside it and come back to this same script. The | |
| 38 | +;; shell is what sets JOLT_NATIVE_LIB, so its absence is the test — no flag to | |
| 39 | +;; forget, and `nix develop --command scripts/run.bb` by hand is not a second | |
| 40 | +;; code path. | |
| 41 | +;; | |
| 42 | +;; --max-jobs 0 is what sends the work to the `builders` entry rather than | |
| 43 | +;; compiling it here. Left to the default, nix prefers the local machine, and a | |
| 44 | +;; cold jolt-native is egui, openh264 and quinn on a laptop — for a derivation | |
| 45 | +;; a remote builder has likely built already. FRQ_MAX_JOBS is the way out on a | |
| 46 | +;; machine with no builder configured: FRQ_MAX_JOBS=auto. | |
| 47 | +(when-not (System/getenv "JOLT_NATIVE_LIB") | |
| 48 | + (let [args ["nix" "develop" root "--max-jobs" (paths/env "FRQ_MAX_JOBS" "0") | |
| 49 | + "--command" self] | |
| 50 | + ;; nix is not on every host this runs on: on the machine this was | |
| 51 | + ;; written for it lives in an Arch distrobox, at the same path — which | |
| 52 | + ;; is why the container is entered rather than the tree copied into it. | |
| 53 | + ;; See CLAUDE.md. | |
| 54 | + cmd (if (fs/which "nix") | |
| 55 | + (concat args *command-line-args*) | |
| 56 | + (concat ["distrobox" "enter" "arch" "--" "bash" "-lc" | |
| 57 | + (str "cd " root " && exec " (str/join " " args) " \"$@\"") | |
| 58 | + "--"] | |
| 59 | + *command-line-args*))] | |
| 60 | + (System/exit (:exit @(apply p/process {:inherit true :dir root} cmd))))) | |
| 26 | 61 | |
| 27 | -;; The pinned jolt — scripts/jolt is a DotSlash script, so running it is | |
| 28 | -;; fetching it. Off linux-x86_64 the pin has no asset and the fallback is | |
| 29 | -;; whatever `jolt` is on PATH, which is what that manifest says to do. | |
| 30 | -(def jolt | |
| 31 | - (let [pin (fs/path root "scripts" "jolt")] | |
| 32 | - (if (and (fs/exists? pin) (fs/which "dotslash")) (str pin) "jolt"))) | |
| 62 | +;; The Jolt halves that have to match those objects. glimmer-vidya lives inside | |
| 63 | +;; jolt-native and binds libvidya's ABI, so it comes out of the same input that | |
| 64 | +;; was built rather than deps.edn's git sha — the pin drifting from the library | |
| 65 | +;; is exactly what the flake input's comment describes. glimmer is the flake's | |
| 66 | +;; for the same reason. | |
| 67 | +(def overrides | |
| 68 | + (str "{:deps {jolt-lang/glimmer {:local/root \"" (System/getenv "GLIMMER_SRC") "\"}" | |
| 69 | + " nandi/glimmer-vidya {:local/root \"" (System/getenv "GLIMMER_VIDYA_SRC") "\"}}}")) | |
| 33 | 70 | |
| 34 | -(p/shell (str (fs/path root "scripts" "lib.bb"))) | |
| 71 | +;; On NixOS the store's Mesa is the system's and the window opens. Anywhere | |
| 72 | +;; else — a bare host, or the distrobox above — the real driver is the host's, | |
| 73 | +;; so defer to nixGL, which prepends it. Same rule the flake's launcher uses. | |
| 74 | +(def runner | |
| 75 | + (when-not (fs/exists? "/run/current-system") | |
| 76 | + (some-> (System/getenv "NIXGL") not-empty vector))) | |
| 35 | 77 | |
| 36 | 78 | (System/exit |
| 37 | 79 | (:exit @(apply p/process |
| 38 | 80 | {:inherit true |
| 39 | 81 | :dir root |
| 40 | 82 | :extra-env {"LD_LIBRARY_PATH" |
| 41 | - (str lib (when-let [p (System/getenv "LD_LIBRARY_PATH")] | |
| 42 | - (str ":" p)))}} | |
| 43 | - jolt "-M:frq" *command-line-args*))) | |
| 83 | + (->> [(System/getenv "JOLT_NATIVE_LIB") | |
| 84 | + (System/getenv "FRQ_LIB_PATH") | |
| 85 | + (System/getenv "LD_LIBRARY_PATH")] | |
| 86 | + (remove str/blank?) | |
| 87 | + (str/join ":"))}} | |
| 88 | + (concat runner ["jolt" "-Sdeps" overrides "-M:frq"] *command-line-args*)))) | |
| @@ -7,37 +7,82 @@ exec "$(dirname "$0")/bb" "$0" "$@" | |||
| 7 | ;; | 7 | ;; |
| 8 | ;; run.bb [args...] | 8 | ;; run.bb [args...] |
| 9 | ;; | 9 | ;; |
| 10 | -;; Everything but the source is pinned: jolt comes from scripts/jolt.dotslash | 10 | +;; Two halves, and the split is the point. The frq source is the files on disk, |
| 11 | -;; and the two native libraries from scripts/lib*.dotslash, fetched by digest | 11 | +;; uncommitted edits and all. Everything under it — jolt, glimmer, |
| 12 | -;; and linked into build/lib, which is the one directory the loader is pointed | 12 | +;; glimmer-vidya, both native objects — is the flake's, built rather than |
| 13 | -;; at. `just lib` is done here rather than asked for — the pins say what those | 13 | +;; fetched: this re-execs itself inside `nix develop`, and that shell is the |
| 14 | -;; bytes are, so there is nothing for a person to decide before running. | 14 | +;; jolt-native input compiled and the Jolt halves that bind it, at the revs |
| 15 | +;; flake.lock names. | ||
| 15 | ;; | 16 | ;; |
| 16 | ;; Deliberately not `nix run .#frq`. That builds the flake's own copy of the | 17 | ;; Deliberately not `nix run .#frq`. That builds the flake's own copy of the |
| 17 | ;; source, which is the tree as git has it — so an edit that has not been | 18 | ;; source, which is the tree as git has it — so an edit that has not been |
| 18 | ;; committed, or has been committed on a branch the command was not pointed at, | 19 | ;; committed, or has been committed on a branch the command was not pointed at, |
| 19 | ;; runs as whatever was there before, silently. A run that is meant to answer | 20 | ;; runs as whatever was there before, silently. A run that is meant to answer |
| 20 | ;; "does my change work" has to be the files on disk. | 21 | ;; "does my change work" has to be the files on disk. |
| 21 | -(require '[babashka.fs :as fs] | 22 | +;; |
| 22 | - '[babashka.process :as p]) | 23 | +;; And deliberately not the scripts/*.dotslash pins either, which is what this |
| 24 | +;; used to do. Those name a release; a change to jolt-native is by definition | ||
| 25 | +;; not in one yet. `just lib` still fetches them — the APK and the buck2 build | ||
| 26 | +;; take the released bytes — but a run does not. | ||
| 27 | +(require '[babashka.classpath :as cp]) | ||
| 28 | +(cp/add-classpath (str (babashka.fs/parent *file*))) | ||
| 29 | +(require '[frq.paths :as paths] | ||
| 30 | + '[babashka.fs :as fs] | ||
| 31 | + '[babashka.process :as p] | ||
| 32 | + '[clojure.string :as str]) | ||
| 23 | 33 | ||
| 24 | (def root (str (fs/canonicalize (fs/path (fs/parent *file*) "..")))) | 34 | (def root (str (fs/canonicalize (fs/path (fs/parent *file*) "..")))) |
| 25 | -(def lib (str (fs/path root "build" "lib"))) | 35 | +(def self (str (fs/path root "scripts" "run.bb"))) |
| 36 | + | ||
| 37 | +;; Outside the shell, get inside it and come back to this same script. The | ||
| 38 | +;; shell is what sets JOLT_NATIVE_LIB, so its absence is the test — no flag to | ||
| 39 | +;; forget, and `nix develop --command scripts/run.bb` by hand is not a second | ||
| 40 | +;; code path. | ||
| 41 | +;; | ||
| 42 | +;; --max-jobs 0 is what sends the work to the `builders` entry rather than | ||
| 43 | +;; compiling it here. Left to the default, nix prefers the local machine, and a | ||
| 44 | +;; cold jolt-native is egui, openh264 and quinn on a laptop — for a derivation | ||
| 45 | +;; a remote builder has likely built already. FRQ_MAX_JOBS is the way out on a | ||
| 46 | +;; machine with no builder configured: FRQ_MAX_JOBS=auto. | ||
| 47 | +(when-not (System/getenv "JOLT_NATIVE_LIB") | ||
| 48 | + (let [args ["nix" "develop" root "--max-jobs" (paths/env "FRQ_MAX_JOBS" "0") | ||
| 49 | + "--command" self] | ||
| 50 | + ;; nix is not on every host this runs on: on the machine this was | ||
| 51 | + ;; written for it lives in an Arch distrobox, at the same path — which | ||
| 52 | + ;; is why the container is entered rather than the tree copied into it. | ||
| 53 | + ;; See CLAUDE.md. | ||
| 54 | + cmd (if (fs/which "nix") | ||
| 55 | + (concat args *command-line-args*) | ||
| 56 | + (concat ["distrobox" "enter" "arch" "--" "bash" "-lc" | ||
| 57 | + (str "cd " root " && exec " (str/join " " args) " \"$@\"") | ||
| 58 | + "--"] | ||
| 59 | + *command-line-args*))] | ||
| 60 | + (System/exit (:exit @(apply p/process {:inherit true :dir root} cmd))))) | ||
| 26 | 61 | ||
| 27 | -;; The pinned jolt — scripts/jolt is a DotSlash script, so running it is | 62 | +;; The Jolt halves that have to match those objects. glimmer-vidya lives inside |
| 28 | -;; fetching it. Off linux-x86_64 the pin has no asset and the fallback is | 63 | +;; jolt-native and binds libvidya's ABI, so it comes out of the same input that |
| 29 | -;; whatever `jolt` is on PATH, which is what that manifest says to do. | 64 | +;; was built rather than deps.edn's git sha — the pin drifting from the library |
| 30 | -(def jolt | 65 | +;; is exactly what the flake input's comment describes. glimmer is the flake's |
| 31 | - (let [pin (fs/path root "scripts" "jolt")] | 66 | +;; for the same reason. |
| 32 | - (if (and (fs/exists? pin) (fs/which "dotslash")) (str pin) "jolt"))) | 67 | +(def overrides |
| 68 | + (str "{:deps {jolt-lang/glimmer {:local/root \"" (System/getenv "GLIMMER_SRC") "\"}" | ||
| 69 | + " nandi/glimmer-vidya {:local/root \"" (System/getenv "GLIMMER_VIDYA_SRC") "\"}}}")) | ||
| 33 | 70 | ||
| 34 | -(p/shell (str (fs/path root "scripts" "lib.bb"))) | 71 | +;; On NixOS the store's Mesa is the system's and the window opens. Anywhere |
| 72 | +;; else — a bare host, or the distrobox above — the real driver is the host's, | ||
| 73 | +;; so defer to nixGL, which prepends it. Same rule the flake's launcher uses. | ||
| 74 | +(def runner | ||
| 75 | + (when-not (fs/exists? "/run/current-system") | ||
| 76 | + (some-> (System/getenv "NIXGL") not-empty vector))) | ||
| 35 | 77 | ||
| 36 | (System/exit | 78 | (System/exit |
| 37 | (:exit @(apply p/process | 79 | (:exit @(apply p/process |
| 38 | {:inherit true | 80 | {:inherit true |
| 39 | :dir root | 81 | :dir root |
| 40 | :extra-env {"LD_LIBRARY_PATH" | 82 | :extra-env {"LD_LIBRARY_PATH" |
| 41 | - (str lib (when-let [p (System/getenv "LD_LIBRARY_PATH")] | 83 | + (->> [(System/getenv "JOLT_NATIVE_LIB") |
| 42 | - (str ":" p)))}} | 84 | + (System/getenv "FRQ_LIB_PATH") |
| 43 | - jolt "-M:frq" *command-line-args*))) | 85 | + (System/getenv "LD_LIBRARY_PATH")] |
| 86 | + (remove str/blank?) | ||
| 87 | + (str/join ":"))}} | ||
| 88 | + (concat runner ["jolt" "-Sdeps" overrides "-M:frq"] *command-line-args*)))) | ||