Take the jolt-native you name, not the one next door
The dev shell already ships libjoltcosmic, in the pin's frq-native/lib. The shellHook was putting a sibling checkout's target/release ahead of it whenever ../jolt-native happened to exist with a built libjolttui.so — nobody had asked, and the only sign was a line on stderr. What it prepends there is a raw cargo build: no store RUNPATH, so its libc.so.6 resolves to the host's. The jolt that dlopens it is linked against the store's glibc, and a second libc in that process does not load. jolt reports it as "required native library joltcosmic not found" — a file that is present, readable, and exports the right symbols — which names neither libc nor the tree the object came from. So the search is gone and FRQ_JOLT_NATIVE is honoured only when set. Empty still means the pin. A named tree still has to carry the RUNPATH the store copy does, which in practice means building it under Nix; naming it does not make a host-toolchain .so loadable. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
c6ce105 parent: 7659480 modified
flake.nix +27 -40 | @@ -812,48 +812,36 @@ | ||
| 812 | 812 | FRQ_LIB_PATH = lib.makeLibraryPath (runtimeLibsFor pkgs); |
| 813 | 813 | NIXGL = "${nixGLFor pkgs}/bin/nixGLIntel"; |
| 814 | 814 | |
| 815 | - # A checkout of jolt-native beside this one, in place of the pin. | |
| 815 | + # A checkout of jolt-native in place of the pin, when one is NAMED. | |
| 816 | 816 | # |
| 817 | - # The pin is a rev on a server, so the loop for a change to the | |
| 818 | - # terminal backend was commit, push, re-pin, re-lock — four steps | |
| 819 | - # and an upload for a line of Rust. With a working copy beside this | |
| 820 | - # one the loop is `cargo build` and `just tui`, and the shell finds | |
| 821 | - # that copy itself: ../jolt-native from the checkout this was run | |
| 822 | - # in, which is where it is on the machines this is developed on. | |
| 823 | - # A worktree under .claude/worktrees counts as the same checkout — | |
| 824 | - # the sibling is the main one's, not the worktree's. | |
| 817 | + # The pin is a rev on a server, so the loop for a change to a | |
| 818 | + # backend would be commit, push, re-pin, re-lock — four steps and | |
| 819 | + # an upload for a line of Rust. Pointing FRQ_JOLT_NATIVE at a | |
| 820 | + # working copy makes the loop `cargo build` and `just tui`. | |
| 825 | 821 | # |
| 826 | - # Found rather than named, but not silently: it says which tree it | |
| 827 | - # took on the way in, because `just tui` running something other | |
| 828 | - # than the pin is the sort of thing you have to be able to see. | |
| 822 | + # This used to find that copy by itself — ../jolt-native beside the | |
| 823 | + # checkout — and that is gone, because a found tree is the wrong | |
| 824 | + # default twice over. It fired on a sibling nobody had asked about, | |
| 825 | + # so a shell could be running something other than the pin on the | |
| 826 | + # strength of a directory existing. And what it prepended was a raw | |
| 827 | + # `cargo build` artifact: no store RUNPATH, so its libc.so.6 | |
| 828 | + # resolves to the host's, and the Nix-glibc jolt that dlopens it | |
| 829 | + # gets a second libc and fails. jolt reports that as "required | |
| 830 | + # native library ... not found", which names neither libc nor the | |
| 831 | + # tree the object came from. An override worth having is one you | |
| 832 | + # can see in the command you typed. | |
| 829 | 833 | # |
| 830 | - # It has to be a built one. A checkout with no target/release/ | |
| 831 | - # libjolttui.so in it would mean the Jolt half of the backend from | |
| 832 | - # the working copy and the shared object from the pin — two halves | |
| 833 | - # of two different libraries, which fail in ways that look like | |
| 834 | - # neither. So an unbuilt sibling is left alone and the pin stands. | |
| 834 | + # So: named or nothing. A named tree is taken even unbuilt (with a | |
| 835 | + # word about what to run) — naming it is asking for it — and it has | |
| 836 | + # to carry the RUNPATH the store copy does, which in practice means | |
| 837 | + # building it under Nix. | |
| 835 | 838 | # |
| 836 | - # FRQ_JOLT_NATIVE overrides the search, and is taken even unbuilt | |
| 837 | - # (with a word about what to run): naming a tree is asking for it. | |
| 838 | - # Empty is how you say the pin, on a machine that has a sibling and | |
| 839 | - # wants what everyone else is running. | |
| 840 | - # | |
| 841 | - # Only the sources and libjolttui move either way. Everything else | |
| 842 | - # on the library path — libopus, libmoq_ffi, the ALSA plugins — | |
| 843 | - # stays the pin's, since a checkout has no build of those to offer. | |
| 839 | + # Only the sources and the objects a checkout actually builds move. | |
| 840 | + # Everything else on the library path — libopus, libmoq_ffi, the | |
| 841 | + # ALSA plugins — stays the pin's, since a checkout has no build of | |
| 842 | + # those to offer. | |
| 844 | 843 | shellHook = '' |
| 845 | - frq_named=1 | |
| 846 | - if [ -z "''${FRQ_JOLT_NATIVE+named}" ]; then | |
| 847 | - frq_named= | |
| 848 | - frq_git="$(git rev-parse --path-format=absolute --git-common-dir 2>/dev/null || true)" | |
| 849 | - frq_near="''${frq_git:+$(dirname "$(dirname "$frq_git")")/jolt-native}" | |
| 850 | - if [ -n "$frq_near" ] && [ -e "$frq_near/target/release/libjolttui.so" ]; then | |
| 851 | - FRQ_JOLT_NATIVE="$frq_near" | |
| 852 | - else | |
| 853 | - FRQ_JOLT_NATIVE="" | |
| 854 | - fi | |
| 855 | - fi | |
| 856 | - if [ -n "$FRQ_JOLT_NATIVE" ]; then | |
| 844 | + if [ -n "''${FRQ_JOLT_NATIVE:-}" ]; then | |
| 857 | 845 | if [ -d "$FRQ_JOLT_NATIVE/crates/jolt-tui" ]; then |
| 858 | 846 | FRQ_JOLT_NATIVE="$(cd "$FRQ_JOLT_NATIVE" && pwd)" |
| 859 | 847 | export FRQ_JOLT_NATIVE |
| @@ -863,15 +851,14 @@ | ||
| 863 | 851 | # same object. The rest of the pin's lib directory is still |
| 864 | 852 | # behind it. |
| 865 | 853 | export JOLT_NATIVE_LIB="$FRQ_JOLT_NATIVE/target/release:$JOLT_NATIVE_LIB" |
| 866 | - echo "frq: jolt-native from $FRQ_JOLT_NATIVE, not the pin (FRQ_JOLT_NATIVE= for the pin)" >&2 | |
| 854 | + echo "frq: jolt-native from $FRQ_JOLT_NATIVE, not the pin (unset FRQ_JOLT_NATIVE for the pin)" >&2 | |
| 867 | 855 | if [ ! -e "$FRQ_JOLT_NATIVE/target/release/libjolttui.so" ]; then |
| 868 | 856 | echo "frq: no libjolttui.so there yet — cargo build --release --features terminal -p jolt-tui" >&2 |
| 869 | 857 | fi |
| 870 | - elif [ -n "$frq_named" ]; then | |
| 858 | + else | |
| 871 | 859 | echo "frq: FRQ_JOLT_NATIVE=$FRQ_JOLT_NATIVE is not a jolt-native checkout; using the pin" >&2 |
| 872 | 860 | fi |
| 873 | 861 | fi |
| 874 | - unset frq_named frq_git frq_near | |
| 875 | 862 | ''; |
| 876 | 863 | }; |
| 877 | 864 | |
| @@ -812,48 +812,36 @@ | |||
| 812 | FRQ_LIB_PATH = lib.makeLibraryPath (runtimeLibsFor pkgs); | 812 | FRQ_LIB_PATH = lib.makeLibraryPath (runtimeLibsFor pkgs); |
| 813 | NIXGL = "${nixGLFor pkgs}/bin/nixGLIntel"; | 813 | NIXGL = "${nixGLFor pkgs}/bin/nixGLIntel"; |
| 814 | 814 | ||
| 815 | - # A checkout of jolt-native beside this one, in place of the pin. | 815 | + # A checkout of jolt-native in place of the pin, when one is NAMED. |
| 816 | # | 816 | # |
| 817 | - # The pin is a rev on a server, so the loop for a change to the | 817 | + # The pin is a rev on a server, so the loop for a change to a |
| 818 | - # terminal backend was commit, push, re-pin, re-lock — four steps | 818 | + # backend would be commit, push, re-pin, re-lock — four steps and |
| 819 | - # and an upload for a line of Rust. With a working copy beside this | 819 | + # an upload for a line of Rust. Pointing FRQ_JOLT_NATIVE at a |
| 820 | - # one the loop is `cargo build` and `just tui`, and the shell finds | 820 | + # working copy makes the loop `cargo build` and `just tui`. |
| 821 | - # that copy itself: ../jolt-native from the checkout this was run | ||
| 822 | - # in, which is where it is on the machines this is developed on. | ||
| 823 | - # A worktree under .claude/worktrees counts as the same checkout — | ||
| 824 | - # the sibling is the main one's, not the worktree's. | ||
| 825 | # | 821 | # |
| 826 | - # Found rather than named, but not silently: it says which tree it | 822 | + # This used to find that copy by itself — ../jolt-native beside the |
| 827 | - # took on the way in, because `just tui` running something other | 823 | + # checkout — and that is gone, because a found tree is the wrong |
| 828 | - # than the pin is the sort of thing you have to be able to see. | 824 | + # default twice over. It fired on a sibling nobody had asked about, |
| 825 | + # so a shell could be running something other than the pin on the | ||
| 826 | + # strength of a directory existing. And what it prepended was a raw | ||
| 827 | + # `cargo build` artifact: no store RUNPATH, so its libc.so.6 | ||
| 828 | + # resolves to the host's, and the Nix-glibc jolt that dlopens it | ||
| 829 | + # gets a second libc and fails. jolt reports that as "required | ||
| 830 | + # native library ... not found", which names neither libc nor the | ||
| 831 | + # tree the object came from. An override worth having is one you | ||
| 832 | + # can see in the command you typed. | ||
| 829 | # | 833 | # |
| 830 | - # It has to be a built one. A checkout with no target/release/ | 834 | + # So: named or nothing. A named tree is taken even unbuilt (with a |
| 831 | - # libjolttui.so in it would mean the Jolt half of the backend from | 835 | + # word about what to run) — naming it is asking for it — and it has |
| 832 | - # the working copy and the shared object from the pin — two halves | 836 | + # to carry the RUNPATH the store copy does, which in practice means |
| 833 | - # of two different libraries, which fail in ways that look like | 837 | + # building it under Nix. |
| 834 | - # neither. So an unbuilt sibling is left alone and the pin stands. | ||
| 835 | # | 838 | # |
| 836 | - # FRQ_JOLT_NATIVE overrides the search, and is taken even unbuilt | 839 | + # Only the sources and the objects a checkout actually builds move. |
| 837 | - # (with a word about what to run): naming a tree is asking for it. | 840 | + # Everything else on the library path — libopus, libmoq_ffi, the |
| 838 | - # Empty is how you say the pin, on a machine that has a sibling and | 841 | + # ALSA plugins — stays the pin's, since a checkout has no build of |
| 839 | - # wants what everyone else is running. | 842 | + # those to offer. |
| 840 | - # | ||
| 841 | - # Only the sources and libjolttui move either way. Everything else | ||
| 842 | - # on the library path — libopus, libmoq_ffi, the ALSA plugins — | ||
| 843 | - # stays the pin's, since a checkout has no build of those to offer. | ||
| 844 | shellHook = '' | 843 | shellHook = '' |
| 845 | - frq_named=1 | 844 | + if [ -n "''${FRQ_JOLT_NATIVE:-}" ]; then |
| 846 | - if [ -z "''${FRQ_JOLT_NATIVE+named}" ]; then | ||
| 847 | - frq_named= | ||
| 848 | - frq_git="$(git rev-parse --path-format=absolute --git-common-dir 2>/dev/null || true)" | ||
| 849 | - frq_near="''${frq_git:+$(dirname "$(dirname "$frq_git")")/jolt-native}" | ||
| 850 | - if [ -n "$frq_near" ] && [ -e "$frq_near/target/release/libjolttui.so" ]; then | ||
| 851 | - FRQ_JOLT_NATIVE="$frq_near" | ||
| 852 | - else | ||
| 853 | - FRQ_JOLT_NATIVE="" | ||
| 854 | - fi | ||
| 855 | - fi | ||
| 856 | - if [ -n "$FRQ_JOLT_NATIVE" ]; then | ||
| 857 | if [ -d "$FRQ_JOLT_NATIVE/crates/jolt-tui" ]; then | 845 | if [ -d "$FRQ_JOLT_NATIVE/crates/jolt-tui" ]; then |
| 858 | FRQ_JOLT_NATIVE="$(cd "$FRQ_JOLT_NATIVE" && pwd)" | 846 | FRQ_JOLT_NATIVE="$(cd "$FRQ_JOLT_NATIVE" && pwd)" |
| 859 | export FRQ_JOLT_NATIVE | 847 | export FRQ_JOLT_NATIVE |
| @@ -863,15 +851,14 @@ | |||
| 863 | # same object. The rest of the pin's lib directory is still | 851 | # same object. The rest of the pin's lib directory is still |
| 864 | # behind it. | 852 | # behind it. |
| 865 | export JOLT_NATIVE_LIB="$FRQ_JOLT_NATIVE/target/release:$JOLT_NATIVE_LIB" | 853 | export JOLT_NATIVE_LIB="$FRQ_JOLT_NATIVE/target/release:$JOLT_NATIVE_LIB" |
| 866 | - echo "frq: jolt-native from $FRQ_JOLT_NATIVE, not the pin (FRQ_JOLT_NATIVE= for the pin)" >&2 | 854 | + echo "frq: jolt-native from $FRQ_JOLT_NATIVE, not the pin (unset FRQ_JOLT_NATIVE for the pin)" >&2 |
| 867 | if [ ! -e "$FRQ_JOLT_NATIVE/target/release/libjolttui.so" ]; then | 855 | if [ ! -e "$FRQ_JOLT_NATIVE/target/release/libjolttui.so" ]; then |
| 868 | echo "frq: no libjolttui.so there yet — cargo build --release --features terminal -p jolt-tui" >&2 | 856 | echo "frq: no libjolttui.so there yet — cargo build --release --features terminal -p jolt-tui" >&2 |
| 869 | fi | 857 | fi |
| 870 | - elif [ -n "$frq_named" ]; then | 858 | + else |
| 871 | echo "frq: FRQ_JOLT_NATIVE=$FRQ_JOLT_NATIVE is not a jolt-native checkout; using the pin" >&2 | 859 | echo "frq: FRQ_JOLT_NATIVE=$FRQ_JOLT_NATIVE is not a jolt-native checkout; using the pin" >&2 |
| 872 | fi | 860 | fi |
| 873 | fi | 861 | fi |
| 874 | - unset frq_named frq_git frq_near | ||
| 875 | ''; | 862 | ''; |
| 876 | }; | 863 | }; |
| 877 | 864 | ||