-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbb.edn
More file actions
197 lines (181 loc) · 12.8 KB
/
Copy pathbb.edn
File metadata and controls
197 lines (181 loc) · 12.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
;; Task runner. `bb tasks` lists everything.
;; These are the only sanctioned entry points — CI, the push hook, and humans
;; all call them, so there is exactly one definition of "does it pass".
{:min-bb-version "1.12.0"
:tasks
{:requires ([babashka.fs :as fs]
[babashka.process :as p]
[clojure.string :as str]
[cheshire.core :as json])
;; A failing task reports the tool's own output plus one line, not a babashka
;; stack trace — the trace buries the part you actually need.
:init (do
(def start-ms (System/currentTimeMillis))
(defn run [& args]
(let [{:keys [exit]} (apply p/shell {:continue true} args)]
(when-not (zero? exit)
(println (str "\n✗ failed: " (str/join " " args)))
(System/exit exit)))))
ref {:doc "Clone/refresh reference sources into .ref/ (see refs.json). `bb ref clojure` for one."
:task (let [want (first *command-line-args*)
all (get (json/parse-string (slurp "refs.json")) "refs")
;; Whole language SDKs are opt-in by name: cloning them
;; by default would turn `bb ref` from seconds into
;; minutes, and they are read a subdirectory at a time.
large? (fn [[_ v]] (get v "large"))
refs (if want
(select-keys all [want])
(into {} (remove large? all)))]
(when (empty? refs)
(println "unknown ref. known:" (str/join ", " (keys all)))
(System/exit 1))
(when-not want
(when-let [skipped (seq (keep (fn [[k v]] (when (get v "large") k)) all))]
(println (str "skipping (large, name it to clone): " (str/join ", " skipped)))))
(fs/create-dirs ".ref")
(doseq [[name {:strs [url why]}] refs
:let [dir (str ".ref/" name)]]
(if (fs/exists? dir)
(do (print (format "%-16s updating... " name)) (flush)
(run "git" "-C" dir "pull" "--ff-only" "--depth" "50" "-q"))
(do (println (format "%-16s %s" name why))
(run "git" "clone" "--depth" "50" "-q" url dir)))
(println (format "%-16s ok %s" name dir))))}
check-tools {:doc "Verify the local toolchain against tools.json"
:task (run "bin/check-tools")}
test {:doc "Unit tests (JVM)"
:task (if (and (fs/exists? "test") (seq (fs/glob "test" "**.clj")))
(run "clojure" "-X:test")
(println "no tests yet — skipping"))}
lint {:doc "clj-kondo over the source tree"
:task (let [dirs (filter fs/exists? ["src" "test" "bench" "dev"])]
(cond
(not (fs/which "clj-kondo")) (println "clj-kondo not installed — skipping")
(empty? dirs) (println "nothing to lint yet — skipping")
:else (apply run "clj-kondo" "--lint" dirs)))}
fmt-check {:doc "cljfmt check"
:task (let [dirs (filter fs/exists? ["src" "test" "bench" "dev"])]
(cond
(not (fs/which "cljfmt")) (println "cljfmt not installed — skipping")
(empty? dirs) (println "nothing to format-check yet — skipping")
:else (apply run "cljfmt" "check" dirs)))}
bench-s0 {:doc "S0 dispatch benchmarks (V8 + wasmtime). See bench/s0/README.md"
:task (let [need (remove fs/which ["wasmtime" "wasm-opt" "node" "wasm-tools"])]
(cond
(seq need)
(do (println (str "S0 needs: " (str/join ", " need)))
(println " nix develop (exact versions), or see tools.json")
(System/exit 1))
(not (fs/exists? "bench/s0/run.clj"))
(println "S0 not written yet — bench/s0/README.md is its contract")
:else (apply run "bb" "bench/s0/run.clj" *command-line-args*)))}
spike-host {:doc "S1 spike: call a Wasm component from the JVM through FFM. Needs `nix develop`."
:task (let [need (remove fs/which ["wasm-tools" "clojure"])]
(cond
(seq need)
(do (println (str "needs: " (str/join ", " need))) (System/exit 1))
(not (System/getenv "CLJWIT_WASMTIME_LIB"))
(do (println "CLJWIT_WASMTIME_LIB is unset — run inside `nix develop`")
(System/exit 1))
:else
(do ;; Built here rather than committed: it is a build
;; output, and building it is also a check that the
;; toolchain still produces what the spike expects.
(run "wasm-tools" "parse" "dev/resources/add.wat" "-o" "/tmp/cljwit-add.core.wasm")
(run "wasm-tools" "component" "embed" "dev/resources/add.wit"
"/tmp/cljwit-add.core.wasm" "-o" "/tmp/cljwit-add.embed.wasm")
(run "wasm-tools" "component" "new" "/tmp/cljwit-add.embed.wasm"
"-o" "dev/resources/add.component.wasm")
(run "clojure" "-J--enable-native-access=ALL-UNNAMED"
"-M:dev" "-m" "cljwit.spike.component-call"))))}
reflection {:doc "Fail if any namespace resolves a call reflectively. See 0013."
:task (let [nss (->> (concat (babashka.fs/glob "src" "**.clj")
(babashka.fs/glob "dev" "**.clj")
(babashka.fs/glob "test" "**.clj"))
(map (fn [f] (-> (str f)
(clojure.string/replace (re-pattern "^(src|dev|test)/") "")
(clojure.string/replace (re-pattern "\\.clj$") "")
(clojure.string/replace "/" ".")
(clojure.string/replace "_" "-"))))
sort)
form (str "(binding [*warn-on-reflection* true] (require "
(clojure.string/join " " (map (fn [n] (str "'" n)) nss))
"))")
res (babashka.process/shell {:out :string :err :string :continue true}
"clojure" "-M:dev" "-e" form)
warns (->> (clojure.string/split-lines (str (:err res)))
(filter (fn [l] (clojure.string/includes? l "Reflection warning"))))]
(when (seq warns)
(run! println warns)
(println (format "\n%d reflective call(s). A reflective MemorySegment read cost this project two design notes." (count warns)))
(System/exit 1))
(println (format "no reflective calls in %d namespaces" (count nss))))}
spike-ffm-shape {:doc "Is an FFM downcall expensive because of its shape? See 0013."
:task (do (babashka.fs/create-dirs "target")
(let [so (str "target/libnoop7"
(if (= "Mac OS X" (System/getProperty "os.name")) ".dylib" ".so"))]
(run "cc" "-O2" "-shared" "-fPIC" "-o" so "dev/spike/noop7.c")
(run "clojure" "-M:dev" "-m" "cljwit.spike.ffm-shape")))}
spike-hres {:doc "Can the host define a resource the guest imports? See 0017 F."
:task (do (babashka.fs/create-dirs "target")
(run "wasm-tools" "parse" "dev/resources/hres.wat" "-o" "target/hres.core.wasm")
(run "wasm-tools" "component" "embed" "dev/resources/hres.wit"
"target/hres.core.wasm" "-o" "target/hres.embed.wasm")
(run "wasm-tools" "component" "new" "target/hres.embed.wasm"
"-o" "target/hres.component.wasm")
(run "clojure" "-M:dev" "-m" "cljwit.spike.host-resource"
"target/hres.component.wasm"))}
spike-import {:doc "Can a Wasm guest call back into Clojure? See 0014's falsifier."
:task (do (babashka.fs/create-dirs "target")
(run "wasm-tools" "parse" "dev/resources/imp.wat" "-o" "target/imp.core.wasm")
(run "wasm-tools" "component" "embed" "dev/resources/imp.wit"
"target/imp.core.wasm" "-o" "target/imp.embed.wasm")
(run "wasm-tools" "component" "new" "target/imp.embed.wasm"
"-o" "target/imp.component.wasm")
(run "clojure" "-M:dev" "-m" "cljwit.spike.host-import"))}
spike-reflect {:doc "Can a component describe itself at run time? See 0014."
:task (do (babashka.fs/create-dirs "target")
(run "wasm-tools" "parse" "dev/resources/echo.wat" "-o" "target/echo.core.wasm")
(run "wasm-tools" "component" "embed" "dev/resources/echo.wit"
"target/echo.core.wasm" "-o" "target/echo.embed.wasm")
(run "wasm-tools" "component" "new" "target/echo.embed.wasm"
"-o" "target/echo.component.wasm")
(let [bin "target/spike-reflect"]
(run "cc" "-O2" "-o" bin "dev/spike/reflect.c"
(str "-I" (System/getenv "CLJWIT_WASMTIME_INCLUDE"))
(str "-L" (babashka.fs/parent (System/getenv "CLJWIT_WASMTIME_LIB")))
"-lwasmtime")
(apply run bin (or (seq *command-line-args*)
["target/echo.component.wasm"]))))}
spike-c-cost {:doc "The C control for spike-cost: same C API, caller is C not the JVM."
:task (if-not (System/getenv "CLJWIT_WASMTIME_INCLUDE")
(do (println "CLJWIT_WASMTIME_INCLUDE is unset — run inside `nix develop`")
(System/exit 1))
(let [lib (System/getenv "CLJWIT_WASMTIME_LIB")
bin "target/spike-c-cost"]
(babashka.fs/create-dirs "target")
(run "cc" "-O2" "-o" bin "dev/spike/call_cost.c"
(str "-I" (System/getenv "CLJWIT_WASMTIME_INCLUDE"))
(str "-L" (babashka.fs/parent lib)) "-lwasmtime")
(when-not (babashka.fs/exists? "dev/resources/add.component.wasm")
(run "bb" "run" "spike-host"))
(apply run bin *command-line-args*)))}
spike-cost {:doc "S1 spike: what one call costs. One JVM per path. Needs `nix develop`."
:task (if-not (System/getenv "CLJWIT_WASMTIME_LIB")
(do (println "CLJWIT_WASMTIME_LIB is unset — run inside `nix develop`")
(System/exit 1))
(do (run "bb" "run" "spike-host")
(run "wasm-tools" "parse" "dev/resources/add.wat"
"-o" "dev/resources/add.core.wasm")
;; A fresh JVM per path: the previous attempt measured
;; them together and they contaminated each other.
(doseq [p ["trivial" "core" "core-raw" "component"]]
(run "clojure" "-J--enable-native-access=ALL-UNNAMED"
"-M:dev" "-m" "cljwit.spike.call-cost" p))))}
;; The gate prints its own wall time on purpose. When it drifts past ~60s the
;; push-time hook stops being a good trade — and this is how that becomes
;; visible, without a rule anyone has to remember to read.
check {:doc "The gate. Everything a change must pass; CI runs exactly this."
:depends [check-tools lint fmt-check reflection test]
:task (println (format "\n✓ gate green (%.1fs)"
(/ (- (System/currentTimeMillis) start-ms) 1000.0)))}}}