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.
ae207b8 parent: 719742d added
.buckroot +0 -0 | new file mode 100644 |
| new file mode 100644 |
modified
android/BUCK +7 -6 | @@ -9,7 +9,7 @@ | ||
| 9 | 9 | # The machine-specific paths are read from .buckconfig.local, which the `buck` |
| 10 | 10 | # recipe in the justfile writes. Nothing here is found by looking around the |
| 11 | 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 | 14 | _JOLT_NATIVE = read_root_config("frq", "jolt_native", "") |
| 15 | 15 | _ANDROID_HOME = read_root_config("frq", "android_home", "") |
| @@ -37,11 +37,10 @@ _CC = "$(location //scripts:android-cc)" | ||
| 37 | 37 | _GLIMMER_VIDYA = "" if read_root_config("frq", "libvidya", "pinned") == "checkout" else \ |
| 38 | 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 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)`" | |
| 45 | 44 | |
| 46 | 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 | 67 | # The recipe decides which, by whether that checkout exists, and says so here. |
| 69 | 68 | libvidya(name = "libvidya") |
| 70 | 69 | |
| 70 | +glue(c_name = "glue-c", include_name = "glue-include") | |
| 71 | + | |
| 71 | 72 | # --- the Jolt half ---------------------------------------------------------- |
| 72 | 73 | # The boot image: frq's Scheme, cross-compiled to arm64 by Chez. The sources |
| 73 | 74 | # 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 the | 10 | # 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 that | 40 | +# 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 None | 42 | +_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 sources | 73 | # 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 them | 74 | # 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): | ||
| 26 | 26 | out = "libvidya.so", |
| 27 | 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 | + ) | |
| @@ -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: | ||
| 71 | 71 | mkdir -p android/prebuilt/arm64-v8a |
| 72 | 72 | cp "{{jolt_native}}/build/android/arm64-v8a/libvidya.so" \ |
| 73 | 73 | 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 | 79 | fi |
| 75 | 80 | # The boot image's other source roots are outside this cell too; hash them |
| 76 | 81 | # here so the digest reaches the action. See android/BUCK. |
| @@ -71,6 +71,11 @@ buck *args: | |||
| 71 | mkdir -p android/prebuilt/arm64-v8a | 71 | 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.so | 73 | 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 | fi | 79 | fi |
| 75 | # The boot image's other source roots are outside this cell too; hash them | 80 | # 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. |