jevsnes.git / tools / mcp / install.sh
1#!/usr/bin/env bash

Build native and keep a copy of it where launch.sh looks. See ./README.md.

3set -euo pipefail
5REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
6cd "$REPO_ROOT"

The library path the copy will run with is the DEVSHELL's: read it here, inside the shell, and write it down for launch.sh, which runs outside one.

10if [[ -z "${IN_NIX_SHELL:-}" ]]; then
11    exec nix develop -c "$0" "$@"
12fi
14BIN_DIR="run/bin"
15ROOTS="$BIN_DIR/roots"
16mkdir -p "$BIN_DIR"
17
18built="$(buck2 build //apps/native:native --show-full-simple-output)"
19[[ -x "$built" ]] || { echo "install.sh: buck2 named no executable ($built)" >&2; exit 1; }

A copy, never a symlink into buck-out: buck-out is wiped (2026-09-21) and rewritten mid-build, and either would take the proxy away from the client. The rename is atomic, so a launch racing this sees the old copy or the new.

24cp "$built" "$BIN_DIR/native.new"

The hot-patch build keeps every symbol and all debug info (285 MB, measured 2026-09-21). The proxy is never patched - patch.sh reads the WINDOW's own /proc/PID/exe - so its copy drops the debug info; C: is the scarce thing.

28strip --strip-debug "$BIN_DIR/native.new"
29printf 'LD_LIBRARY_PATH=%s\n' "$LD_LIBRARY_PATH" >"$BIN_DIR/native.env.new"
30mv -f "$BIN_DIR/native.env.new" "$BIN_DIR/native.env"
31mv -f "$BIN_DIR/native.new" "$BIN_DIR/native"

The copy names store paths - its ELF interpreter and every library it links

  • that nothing else keeps alive outside the devshell. Root the ones ldd resolves, so a garbage collection cannot leave a binary that will not start.
36rm -rf "$ROOTS"
37mkdir -p "$ROOTS"
38i=0
39while read -r store; do
40    nix-store --add-root "$ROOTS/$i" --realise "$store" >/dev/null
41    i=$((i + 1))
42done < <(ldd "$BIN_DIR/native" | grep -o '/nix/store/[^/]*' | sort -u)
44echo "install.sh: $BIN_DIR/native from $built ($i store paths rooted)" >&2