nandi/frqpublic Fork 0
ae207b8
Commits
Clone
git clone https://git.rickub.com/nandi/frq.git
git clone ssh://git@rickub.com/nandi/frq.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Make the worktree its own buck root, and the glue an input

Two bugs, both of which hid behind a stale artifact rather than an error.

A worktree under .claude/worktrees sits inside the checkout it came from, so
buck2's search for a project root walked straight past it and landed on the
outer .buckconfig once main had one. Everything then built the *other* tree:
its .buckconfig.local does not exist, so android_home read as empty, the
classpath pointed at /platforms/android-36/android.jar, and javac reported
every android.* import missing — a JDK-shaped error with nothing wrong with
the JDK. .buckroot is the marker that stops the search, and jolt-native
already carries one.

And jolt_main.c was named by absolute path when a sibling checkout answered
for it, which left buck nothing to notice when it changed: editing the glue
rebuilt nothing, and the APK kept the object it had. It is staged into the
cell and declared now, like the library beside it. Both come out of a macro,
because a BUCK file cannot branch and this varies by what is next door rather
than by configuration.

The glue matters because it is where the ABI is registered by hand, and the
first thing the app did on the phone was die on a symbol missing from that
list — a fix that rebuilt nothing at all until this landed.
nandi committed 2026-08-31T18:13:12-07:00 Browse files
ae207b8 parent: 719742d
added .buckroot +0 -0
new file mode 100644
new file mode 100644
modified android/BUCK +7 -6
@@ -9,7 +9,7 @@
99 # The machine-specific paths are read from .buckconfig.local, which the `buck`
1010 # recipe in the justfile writes. Nothing here is found by looking around the
1111 # machine; if a path is missing the recipe says which.
12-load(":defs.bzl", "libvidya")
12+load(":defs.bzl", "glue", "libvidya")
1313
1414 _JOLT_NATIVE = read_root_config("frq", "jolt_native", "")
1515 _ANDROID_HOME = read_root_config("frq", "android_home", "")
@@ -37,11 +37,10 @@ _CC = "$(location //scripts:android-cc)"
3737 _GLIMMER_VIDYA = "" if read_root_config("frq", "libvidya", "pinned") == "checkout" else \
3838 "GLIMMER_VIDYA=`realpath $(location toolchains//dist:glimmer-vidya)/src` "
3939
40-# jolt_main.c and the ABI's headers. A sibling checkout wins here too, so that
41-# editing the glue and the library together works; otherwise the release.
42-_GLUE = _JOLT_NATIVE if read_root_config("frq", "libvidya", "pinned") == "checkout" else None
43-_GLUE_C = (_GLUE + "/android/jolt_main.c") if _GLUE else "`realpath $(location toolchains//dist:android-glue)/android/jolt_main.c`"
44-_GLUE_INCLUDE = (_GLUE + "/crates/jolt-vidya/include") if _GLUE else "`realpath $(location toolchains//dist:android-glue)/include`"
40+# jolt_main.c and the ABI's headers, as targets — see defs.bzl for which of
41+# the two sources answers, and why neither may be a bare path.
42+_GLUE_C = "`realpath $(location :glue-c)`"
43+_GLUE_INCLUDE = "`realpath $(location :glue-include)`"
4544
4645 _ABS_OUT = 'd=`dirname "$OUT"` && b=`basename "$OUT"` && d=`cd "$d" && pwd` && out="$d/$b"'
4746
@@ -68,6 +67,8 @@ export_file(
6867 # The recipe decides which, by whether that checkout exists, and says so here.
6968 libvidya(name = "libvidya")
7069
70+glue(c_name = "glue-c", include_name = "glue-include")
71+
7172 # --- the Jolt half ----------------------------------------------------------
7273 # The boot image: frq's Scheme, cross-compiled to arm64 by Chez. The sources
7374 # are an input so that editing one rebuilds this; the compile itself reads them
@@ -9,7 +9,7 @@
9 # The machine-specific paths are read from .buckconfig.local, which the `buck`9 # The machine-specific paths are read from .buckconfig.local, which the `buck`
10 # recipe in the justfile writes. Nothing here is found by looking around the10 # recipe in the justfile writes. Nothing here is found by looking around the
11 # machine; if a path is missing the recipe says which.11 # machine; if a path is missing the recipe says which.
12-load(":defs.bzl", "libvidya")12+load(":defs.bzl", "glue", "libvidya")
13 13
14 _JOLT_NATIVE = read_root_config("frq", "jolt_native", "")14 _JOLT_NATIVE = read_root_config("frq", "jolt_native", "")
15 _ANDROID_HOME = read_root_config("frq", "android_home", "")15 _ANDROID_HOME = read_root_config("frq", "android_home", "")
@@ -37,11 +37,10 @@ _CC = "$(location //scripts:android-cc)"
37 _GLIMMER_VIDYA = "" if read_root_config("frq", "libvidya", "pinned") == "checkout" else \37 _GLIMMER_VIDYA = "" if read_root_config("frq", "libvidya", "pinned") == "checkout" else \
38 "GLIMMER_VIDYA=`realpath $(location toolchains//dist:glimmer-vidya)/src` "38 "GLIMMER_VIDYA=`realpath $(location toolchains//dist:glimmer-vidya)/src` "
39 39
40-# jolt_main.c and the ABI's headers. A sibling checkout wins here too, so that40+# jolt_main.c and the ABI's headers, as targets — see defs.bzl for which of
41-# editing the glue and the library together works; otherwise the release.41+# the two sources answers, and why neither may be a bare path.
42-_GLUE = _JOLT_NATIVE if read_root_config("frq", "libvidya", "pinned") == "checkout" else None42+_GLUE_C = "`realpath $(location :glue-c)`"
43-_GLUE_C = (_GLUE + "/android/jolt_main.c") if _GLUE else "`realpath $(location toolchains//dist:android-glue)/android/jolt_main.c`"43+_GLUE_INCLUDE = "`realpath $(location :glue-include)`"
44-_GLUE_INCLUDE = (_GLUE + "/crates/jolt-vidya/include") if _GLUE else "`realpath $(location toolchains//dist:android-glue)/include`"
45 44
46 _ABS_OUT = 'd=`dirname "$OUT"` && b=`basename "$OUT"` && d=`cd "$d" && pwd` && out="$d/$b"'45 _ABS_OUT = 'd=`dirname "$OUT"` && b=`basename "$OUT"` && d=`cd "$d" && pwd` && out="$d/$b"'
47 46
@@ -68,6 +67,8 @@ export_file(
68 # The recipe decides which, by whether that checkout exists, and says so here.67 # The recipe decides which, by whether that checkout exists, and says so here.
69 libvidya(name = "libvidya")68 libvidya(name = "libvidya")
70 69
70+glue(c_name = "glue-c", include_name = "glue-include")
71+
71 # --- the Jolt half ----------------------------------------------------------72 # --- the Jolt half ----------------------------------------------------------
72 # The boot image: frq's Scheme, cross-compiled to arm64 by Chez. The sources73 # The boot image: frq's Scheme, cross-compiled to arm64 by Chez. The sources
73 # are an input so that editing one rebuilds this; the compile itself reads them74 # are an input so that editing one rebuilds this; the compile itself reads them
modified android/defs.bzl +37 -0
@@ -26,3 +26,40 @@ def libvidya(name):
2626 out = "libvidya.so",
2727 cmd = "cp $(location toolchains//dist:libvidya-android)/libvidya.so \"$OUT\"",
2828 )
29+
30+def glue(c_name, include_name):
31+ """jolt_main.c and the ABI's headers, from wherever libvidya came from.
32+
33+ Targets rather than paths, and that is the point: naming a checkout's file
34+ by absolute path leaves buck with nothing to notice when it changes, so
35+ editing the glue rebuilt nothing and the APK kept the old object. It has to
36+ be an input.
37+ """
38+ if native.read_root_config("frq", "libvidya", "pinned") == "checkout":
39+ # Staged by the `buck` recipe, because a cell cannot reach outside its
40+ # own root.
41+ native.export_file(
42+ name = c_name,
43+ src = "prebuilt/glue/android/jolt_main.c",
44+ mode = "reference",
45+ )
46+ # A genrule rather than a filegroup: a filegroup keeps each file at
47+ # its own path inside the output, so `-I` would have to name the
48+ # staging directory again. This hands back a directory of headers.
49+ native.genrule(
50+ name = include_name,
51+ out = "include",
52+ srcs = native.glob(["prebuilt/glue/include/*.h"]),
53+ cmd = "mkdir -p \"$OUT\" && cp $SRCS \"$OUT\"/",
54+ )
55+ else:
56+ native.genrule(
57+ name = c_name,
58+ out = "jolt_main.c",
59+ cmd = "cp $(location toolchains//dist:android-glue)/android/jolt_main.c \"$OUT\"",
60+ )
61+ native.genrule(
62+ name = include_name,
63+ out = "include",
64+ cmd = "cp -r $(location toolchains//dist:android-glue)/include \"$OUT\"",
65+ )
@@ -26,3 +26,40 @@ def libvidya(name):
26 out = "libvidya.so",26 out = "libvidya.so",
27 cmd = "cp $(location toolchains//dist:libvidya-android)/libvidya.so \"$OUT\"",27 cmd = "cp $(location toolchains//dist:libvidya-android)/libvidya.so \"$OUT\"",
28 )28 )
29+
30+def glue(c_name, include_name):
31+ """jolt_main.c and the ABI's headers, from wherever libvidya came from.
32+
33+ Targets rather than paths, and that is the point: naming a checkout's file
34+ by absolute path leaves buck with nothing to notice when it changes, so
35+ editing the glue rebuilt nothing and the APK kept the old object. It has to
36+ be an input.
37+ """
38+ if native.read_root_config("frq", "libvidya", "pinned") == "checkout":
39+ # Staged by the `buck` recipe, because a cell cannot reach outside its
40+ # own root.
41+ native.export_file(
42+ name = c_name,
43+ src = "prebuilt/glue/android/jolt_main.c",
44+ mode = "reference",
45+ )
46+ # A genrule rather than a filegroup: a filegroup keeps each file at
47+ # its own path inside the output, so `-I` would have to name the
48+ # staging directory again. This hands back a directory of headers.
49+ native.genrule(
50+ name = include_name,
51+ out = "include",
52+ srcs = native.glob(["prebuilt/glue/include/*.h"]),
53+ cmd = "mkdir -p \"$OUT\" && cp $SRCS \"$OUT\"/",
54+ )
55+ else:
56+ native.genrule(
57+ name = c_name,
58+ out = "jolt_main.c",
59+ cmd = "cp $(location toolchains//dist:android-glue)/android/jolt_main.c \"$OUT\"",
60+ )
61+ native.genrule(
62+ name = include_name,
63+ out = "include",
64+ cmd = "cp -r $(location toolchains//dist:android-glue)/include \"$OUT\"",
65+ )
modified justfile +5 -0
@@ -71,6 +71,11 @@ buck *args:
7171 mkdir -p android/prebuilt/arm64-v8a
7272 cp "{{jolt_native}}/build/android/arm64-v8a/libvidya.so" \
7373 android/prebuilt/arm64-v8a/libvidya.so
74+ # The glue travels with it, for the same reason: editing jolt_main.c
75+ # should relink libjoltapp, and it cannot if buck only knows a path.
76+ mkdir -p android/prebuilt/glue/android android/prebuilt/glue/include
77+ cp "{{jolt_native}}/android/jolt_main.c" android/prebuilt/glue/android/
78+ cp "{{jolt_native}}"/crates/jolt-vidya/include/*.h android/prebuilt/glue/include/
7479 fi
7580 # The boot image's other source roots are outside this cell too; hash them
7681 # here so the digest reaches the action. See android/BUCK.
@@ -71,6 +71,11 @@ buck *args:
71 mkdir -p android/prebuilt/arm64-v8a71 mkdir -p android/prebuilt/arm64-v8a
72 cp "{{jolt_native}}/build/android/arm64-v8a/libvidya.so" \72 cp "{{jolt_native}}/build/android/arm64-v8a/libvidya.so" \
73 android/prebuilt/arm64-v8a/libvidya.so73 android/prebuilt/arm64-v8a/libvidya.so
74+ # The glue travels with it, for the same reason: editing jolt_main.c
75+ # should relink libjoltapp, and it cannot if buck only knows a path.
76+ mkdir -p android/prebuilt/glue/android android/prebuilt/glue/include
77+ cp "{{jolt_native}}/android/jolt_main.c" android/prebuilt/glue/android/
78+ cp "{{jolt_native}}"/crates/jolt-vidya/include/*.h android/prebuilt/glue/include/
74 fi79 fi
75 # The boot image's other source roots are outside this cell too; hash them80 # The boot image's other source roots are outside this cell too; hash them
76 # here so the digest reaches the action. See android/BUCK.81 # here so the digest reaches the action. See android/BUCK.