@scriptc/compiler 0.2.4 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1104) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +915 -215
  2. package/ambient/scriptc-overrides.d.ts +5 -1
  3. package/ambient/scriptc.d.ts +22 -2
  4. package/dist/backend/build-cache.d.ts +4 -0
  5. package/dist/backend/build-cache.js +16 -2
  6. package/dist/backend/build-cache.js.map +1 -1
  7. package/dist/backend/cycle-analysis.js +17 -5
  8. package/dist/backend/cycle-analysis.js.map +1 -1
  9. package/dist/backend/cycle-analysis.test.js +50 -11
  10. package/dist/backend/cycle-analysis.test.js.map +1 -1
  11. package/dist/backend/debug-symbols.js.map +1 -1
  12. package/dist/backend/executable-features.js +2 -1
  13. package/dist/backend/executable-features.js.map +1 -1
  14. package/dist/backend/external-c.d.ts +13 -6
  15. package/dist/backend/external-c.js +15 -3
  16. package/dist/backend/external-c.js.map +1 -1
  17. package/dist/backend/ffi-callbacks.js +6 -9
  18. package/dist/backend/ffi-callbacks.js.map +1 -1
  19. package/dist/backend/library-identity-markers.js.map +1 -1
  20. package/dist/backend/library-pack.d.ts +1 -1
  21. package/dist/backend/library-pack.js +81 -24
  22. package/dist/backend/library-pack.js.map +1 -1
  23. package/dist/backend/link-plan-core.js +9 -2
  24. package/dist/backend/link-plan-core.js.map +1 -1
  25. package/dist/backend/link-plan.d.ts +1 -1
  26. package/dist/backend/link-plan.js +4 -5
  27. package/dist/backend/link-plan.js.map +1 -1
  28. package/dist/backend/linker.d.ts +1 -1
  29. package/dist/backend/linker.js +42 -23
  30. package/dist/backend/linker.js.map +1 -1
  31. package/dist/backend/literals.js +5 -4
  32. package/dist/backend/literals.js.map +1 -1
  33. package/dist/backend/literals.test.js +30 -5
  34. package/dist/backend/literals.test.js.map +1 -1
  35. package/dist/backend/llvm/blocks.test.js +5 -2
  36. package/dist/backend/llvm/blocks.test.js.map +1 -1
  37. package/dist/backend/llvm/borrowed-inputs.js.map +1 -1
  38. package/dist/backend/llvm/borrowed-receivers.js +43 -19
  39. package/dist/backend/llvm/borrowed-receivers.js.map +1 -1
  40. package/dist/backend/llvm/byte-numbers.js +6 -1
  41. package/dist/backend/llvm/byte-numbers.js.map +1 -1
  42. package/dist/backend/llvm/bytes-bounds.js +73 -22
  43. package/dist/backend/llvm/bytes-bounds.js.map +1 -1
  44. package/dist/backend/llvm/call-lifetimes.d.ts +3 -0
  45. package/dist/backend/llvm/call-lifetimes.js +60 -17
  46. package/dist/backend/llvm/call-lifetimes.js.map +1 -1
  47. package/dist/backend/llvm/call-lifetimes.test.js +159 -28
  48. package/dist/backend/llvm/call-lifetimes.test.js.map +1 -1
  49. package/dist/backend/llvm/checked-value-lifetimes.d.ts +4 -0
  50. package/dist/backend/llvm/checked-value-lifetimes.js +14 -4
  51. package/dist/backend/llvm/checked-value-lifetimes.js.map +1 -1
  52. package/dist/backend/llvm/classes.js +16 -12
  53. package/dist/backend/llvm/classes.js.map +1 -1
  54. package/dist/backend/llvm/common.js +4 -1
  55. package/dist/backend/llvm/common.js.map +1 -1
  56. package/dist/backend/llvm/counted-loops.js +10 -3
  57. package/dist/backend/llvm/counted-loops.js.map +1 -1
  58. package/dist/backend/llvm/debug-info.js +33 -13
  59. package/dist/backend/llvm/debug-info.js.map +1 -1
  60. package/dist/backend/llvm/debug-info.test.js +28 -6
  61. package/dist/backend/llvm/debug-info.test.js.map +1 -1
  62. package/dist/backend/llvm/dyn.js +68 -22
  63. package/dist/backend/llvm/dyn.js.map +1 -1
  64. package/dist/backend/llvm/emitter.d.ts +9 -3
  65. package/dist/backend/llvm/emitter.js +238 -105
  66. package/dist/backend/llvm/emitter.js.map +1 -1
  67. package/dist/backend/llvm/emitter.test.js +233 -42
  68. package/dist/backend/llvm/emitter.test.js.map +1 -1
  69. package/dist/backend/llvm/expr-async.js +25 -6
  70. package/dist/backend/llvm/expr-async.js.map +1 -1
  71. package/dist/backend/llvm/expr-bytes.js +13 -4
  72. package/dist/backend/llvm/expr-bytes.js.map +1 -1
  73. package/dist/backend/llvm/expr-callbacks.js +10 -4
  74. package/dist/backend/llvm/expr-callbacks.js.map +1 -1
  75. package/dist/backend/llvm/expr-calls.js +20 -9
  76. package/dist/backend/llvm/expr-calls.js.map +1 -1
  77. package/dist/backend/llvm/expr-containers.d.ts +2 -0
  78. package/dist/backend/llvm/expr-containers.js +92 -33
  79. package/dist/backend/llvm/expr-containers.js.map +1 -1
  80. package/dist/backend/llvm/expr-control.js +1 -3
  81. package/dist/backend/llvm/expr-control.js.map +1 -1
  82. package/dist/backend/llvm/expr-dispatch.js +3 -1
  83. package/dist/backend/llvm/expr-dispatch.js.map +1 -1
  84. package/dist/backend/llvm/expr-dynamic.js +19 -4
  85. package/dist/backend/llvm/expr-dynamic.js.map +1 -1
  86. package/dist/backend/llvm/expr-island.js +26 -6
  87. package/dist/backend/llvm/expr-island.js.map +1 -1
  88. package/dist/backend/llvm/expr-primitives.js +88 -19
  89. package/dist/backend/llvm/expr-primitives.js.map +1 -1
  90. package/dist/backend/llvm/expr-primitives.test.js +43 -1
  91. package/dist/backend/llvm/expr-primitives.test.js.map +1 -1
  92. package/dist/backend/llvm/expr-records.js +10 -9
  93. package/dist/backend/llvm/expr-records.js.map +1 -1
  94. package/dist/backend/llvm/expr-stream-bridges.js +44 -26
  95. package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
  96. package/dist/backend/llvm/expr-stream-bridges.test.js +51 -14
  97. package/dist/backend/llvm/expr-stream-bridges.test.js.map +1 -1
  98. package/dist/backend/llvm/expr-stream-callbacks.js +34 -14
  99. package/dist/backend/llvm/expr-stream-callbacks.js.map +1 -1
  100. package/dist/backend/llvm/integer-values.js +15 -4
  101. package/dist/backend/llvm/integer-values.js.map +1 -1
  102. package/dist/backend/llvm/integer-views.js +23 -7
  103. package/dist/backend/llvm/integer-views.js.map +1 -1
  104. package/dist/backend/llvm/integer-views.test.js +42 -7
  105. package/dist/backend/llvm/integer-views.test.js.map +1 -1
  106. package/dist/backend/llvm/lib-abi.js +13 -4
  107. package/dist/backend/llvm/lib-abi.js.map +1 -1
  108. package/dist/backend/llvm/lib-connect.js +7 -1
  109. package/dist/backend/llvm/lib-connect.js.map +1 -1
  110. package/dist/backend/llvm/lib-datagram.js +35 -10
  111. package/dist/backend/llvm/lib-datagram.js.map +1 -1
  112. package/dist/backend/llvm/lib-dispatch.js +35 -16
  113. package/dist/backend/llvm/lib-dispatch.js.map +1 -1
  114. package/dist/backend/llvm/lib-filesystem.js +33 -18
  115. package/dist/backend/llvm/lib-filesystem.js.map +1 -1
  116. package/dist/backend/llvm/lib-http2.js +60 -15
  117. package/dist/backend/llvm/lib-http2.js.map +1 -1
  118. package/dist/backend/llvm/lib-lookup.js +12 -5
  119. package/dist/backend/llvm/lib-lookup.js.map +1 -1
  120. package/dist/backend/llvm/lib-network.js +97 -31
  121. package/dist/backend/llvm/lib-network.js.map +1 -1
  122. package/dist/backend/llvm/lib-process.js +57 -14
  123. package/dist/backend/llvm/lib-process.js.map +1 -1
  124. package/dist/backend/llvm/lib-shared.js +107 -31
  125. package/dist/backend/llvm/lib-shared.js.map +1 -1
  126. package/dist/backend/llvm/lib-stream.js +33 -14
  127. package/dist/backend/llvm/lib-stream.js.map +1 -1
  128. package/dist/backend/llvm/lib-test.js +21 -7
  129. package/dist/backend/llvm/lib-test.js.map +1 -1
  130. package/dist/backend/llvm/lib-tls.js +69 -20
  131. package/dist/backend/llvm/lib-tls.js.map +1 -1
  132. package/dist/backend/llvm/local-array-reads.d.ts +1 -0
  133. package/dist/backend/llvm/local-array-reads.js +96 -30
  134. package/dist/backend/llvm/local-array-reads.js.map +1 -1
  135. package/dist/backend/llvm/local-array-reads.test.js +368 -60
  136. package/dist/backend/llvm/local-array-reads.test.js.map +1 -1
  137. package/dist/backend/llvm/local-union-storage.d.ts +25 -0
  138. package/dist/backend/llvm/local-union-storage.js +109 -0
  139. package/dist/backend/llvm/local-union-storage.js.map +1 -0
  140. package/dist/backend/llvm/local-union-storage.test.d.ts +1 -0
  141. package/dist/backend/llvm/local-union-storage.test.js +210 -0
  142. package/dist/backend/llvm/local-union-storage.test.js.map +1 -0
  143. package/dist/backend/llvm/map-read-lifetimes.d.ts +6 -2
  144. package/dist/backend/llvm/map-read-lifetimes.js +44 -14
  145. package/dist/backend/llvm/map-read-lifetimes.js.map +1 -1
  146. package/dist/backend/llvm/map-read-lifetimes.test.js +89 -17
  147. package/dist/backend/llvm/map-read-lifetimes.test.js.map +1 -1
  148. package/dist/backend/llvm/reference-effects.d.ts +3 -2
  149. package/dist/backend/llvm/reference-effects.js +67 -36
  150. package/dist/backend/llvm/reference-effects.js.map +1 -1
  151. package/dist/backend/llvm/reference-effects.test.js +92 -9
  152. package/dist/backend/llvm/reference-effects.test.js.map +1 -1
  153. package/dist/backend/llvm/shapes.js +60 -17
  154. package/dist/backend/llvm/shapes.js.map +1 -1
  155. package/dist/backend/llvm/shapes.test.js +3 -1
  156. package/dist/backend/llvm/shapes.test.js.map +1 -1
  157. package/dist/backend/llvm/split.js +4 -4
  158. package/dist/backend/llvm/split.js.map +1 -1
  159. package/dist/backend/llvm/split.test.js +14 -6
  160. package/dist/backend/llvm/split.test.js.map +1 -1
  161. package/dist/backend/llvm/stack-unions.js +14 -5
  162. package/dist/backend/llvm/stack-unions.js.map +1 -1
  163. package/dist/backend/llvm/stack-unions.test.js +151 -32
  164. package/dist/backend/llvm/stack-unions.test.js.map +1 -1
  165. package/dist/backend/llvm/string-construction.js.map +1 -1
  166. package/dist/backend/llvm/string-construction.test.js +32 -7
  167. package/dist/backend/llvm/string-construction.test.js.map +1 -1
  168. package/dist/backend/llvm/string-lifetimes.js +14 -8
  169. package/dist/backend/llvm/string-lifetimes.js.map +1 -1
  170. package/dist/backend/llvm/string-lifetimes.test.js +112 -26
  171. package/dist/backend/llvm/string-lifetimes.test.js.map +1 -1
  172. package/dist/backend/llvm/switch-dispatch.d.ts +9 -0
  173. package/dist/backend/llvm/switch-dispatch.js +114 -0
  174. package/dist/backend/llvm/switch-dispatch.js.map +1 -0
  175. package/dist/backend/llvm/switch-dispatch.test.d.ts +1 -0
  176. package/dist/backend/llvm/switch-dispatch.test.js +83 -0
  177. package/dist/backend/llvm/switch-dispatch.test.js.map +1 -0
  178. package/dist/backend/llvm/unsupported.js.map +1 -1
  179. package/dist/backend/llvm/walkers.js +6 -3
  180. package/dist/backend/llvm/walkers.js.map +1 -1
  181. package/dist/backend/mangle.js +9 -3
  182. package/dist/backend/mangle.js.map +1 -1
  183. package/dist/backend/may-throw.js +18 -8
  184. package/dist/backend/may-throw.js.map +1 -1
  185. package/dist/backend/may-throw.test.js +118 -22
  186. package/dist/backend/may-throw.test.js.map +1 -1
  187. package/dist/backend/native/artifact-stamps.d.ts +39 -0
  188. package/dist/backend/native/artifact-stamps.js +371 -0
  189. package/dist/backend/native/artifact-stamps.js.map +1 -0
  190. package/dist/backend/native/cache-warm.d.ts +24 -0
  191. package/dist/backend/native/cache-warm.js +80 -0
  192. package/dist/backend/native/cache-warm.js.map +1 -0
  193. package/dist/backend/native/compiler-fingerprint.d.ts +19 -0
  194. package/dist/backend/native/compiler-fingerprint.js +357 -0
  195. package/dist/backend/native/compiler-fingerprint.js.map +1 -0
  196. package/dist/backend/native/contracts.d.ts +314 -0
  197. package/dist/backend/native/contracts.js +2 -0
  198. package/dist/backend/native/contracts.js.map +1 -0
  199. package/dist/backend/native/dependency-files.d.ts +5 -0
  200. package/dist/backend/native/dependency-files.js +83 -0
  201. package/dist/backend/native/dependency-files.js.map +1 -0
  202. package/dist/backend/native/driver.d.ts +50 -0
  203. package/dist/backend/native/driver.js +294 -0
  204. package/dist/backend/native/driver.js.map +1 -0
  205. package/dist/backend/native/executable.d.ts +18 -0
  206. package/dist/backend/native/executable.js +1267 -0
  207. package/dist/backend/native/executable.js.map +1 -0
  208. package/dist/backend/native/library.d.ts +2 -0
  209. package/dist/backend/native/library.js +614 -0
  210. package/dist/backend/native/library.js.map +1 -0
  211. package/dist/backend/native/linker-fingerprint.d.ts +8 -0
  212. package/dist/backend/native/linker-fingerprint.js +174 -0
  213. package/dist/backend/native/linker-fingerprint.js.map +1 -0
  214. package/dist/backend/native/object-merge.d.ts +2 -0
  215. package/dist/backend/native/object-merge.js +154 -0
  216. package/dist/backend/native/object-merge.js.map +1 -0
  217. package/dist/backend/native/process.d.ts +17 -0
  218. package/dist/backend/native/process.js +42 -0
  219. package/dist/backend/native/process.js.map +1 -0
  220. package/dist/backend/native/program-shards.d.ts +21 -0
  221. package/dist/backend/native/program-shards.js +99 -0
  222. package/dist/backend/native/program-shards.js.map +1 -0
  223. package/dist/backend/native/runtime-inputs.d.ts +12 -0
  224. package/dist/backend/native/runtime-inputs.js +163 -0
  225. package/dist/backend/native/runtime-inputs.js.map +1 -0
  226. package/dist/backend/native/runtime-inputs.test.d.ts +1 -0
  227. package/dist/backend/native/runtime-inputs.test.js +64 -0
  228. package/dist/backend/native/runtime-inputs.test.js.map +1 -0
  229. package/dist/backend/native/runtime-objects.d.ts +16 -0
  230. package/dist/backend/native/runtime-objects.js +122 -0
  231. package/dist/backend/native/runtime-objects.js.map +1 -0
  232. package/dist/backend/native/session.d.ts +12 -0
  233. package/dist/backend/native/session.js +31 -0
  234. package/dist/backend/native/session.js.map +1 -0
  235. package/dist/backend/native/tool-identity.d.ts +37 -0
  236. package/dist/backend/native/tool-identity.js +310 -0
  237. package/dist/backend/native/tool-identity.js.map +1 -0
  238. package/dist/backend/native/trace-paths.d.ts +12 -0
  239. package/dist/backend/native/trace-paths.js +73 -0
  240. package/dist/backend/native/trace-paths.js.map +1 -0
  241. package/dist/backend/native/vendor.d.ts +1 -0
  242. package/dist/backend/native/vendor.js +12 -0
  243. package/dist/backend/native/vendor.js.map +1 -0
  244. package/dist/backend/native-codegen-core.js +2 -1
  245. package/dist/backend/native-codegen-core.js.map +1 -1
  246. package/dist/backend/native-codegen.d.ts +1 -1
  247. package/dist/backend/native-codegen.js +24 -13
  248. package/dist/backend/native-codegen.js.map +1 -1
  249. package/dist/backend/native-codegen.test.js +12 -9
  250. package/dist/backend/native-codegen.test.js.map +1 -1
  251. package/dist/backend/native-link-info-core.js +9 -5
  252. package/dist/backend/native-link-info-core.js.map +1 -1
  253. package/dist/backend/native-link-info.js +14 -5
  254. package/dist/backend/native-link-info.js.map +1 -1
  255. package/dist/backend/native-link-info.test.js +58 -13
  256. package/dist/backend/native-link-info.test.js.map +1 -1
  257. package/dist/backend/native-toolchain.d.ts +17 -450
  258. package/dist/backend/native-toolchain.js +17 -3971
  259. package/dist/backend/native-toolchain.js.map +1 -1
  260. package/dist/backend/native-toolchain.test.js +103 -72
  261. package/dist/backend/native-toolchain.test.js.map +1 -1
  262. package/dist/backend/native-tools.js +27 -8
  263. package/dist/backend/native-tools.js.map +1 -1
  264. package/dist/backend/object-localize.js +17 -14
  265. package/dist/backend/object-localize.js.map +1 -1
  266. package/dist/backend/object-localize.test.js +59 -12
  267. package/dist/backend/object-localize.test.js.map +1 -1
  268. package/dist/backend/runtime-pack-core.js +96 -49
  269. package/dist/backend/runtime-pack-core.js.map +1 -1
  270. package/dist/backend/runtime-pack-native.js +5 -3
  271. package/dist/backend/runtime-pack-native.js.map +1 -1
  272. package/dist/backend/runtime-pack-targets.test.js +87 -15
  273. package/dist/backend/runtime-pack-targets.test.js.map +1 -1
  274. package/dist/backend/runtime-pack.d.ts +1 -1
  275. package/dist/backend/runtime-pack.js +11 -12
  276. package/dist/backend/runtime-pack.js.map +1 -1
  277. package/dist/backend/runtime-pack.test.js +40 -24
  278. package/dist/backend/runtime-pack.test.js.map +1 -1
  279. package/dist/backend/source-locations.js.map +1 -1
  280. package/dist/backend/source-locations.test.js +7 -2
  281. package/dist/backend/source-locations.test.js.map +1 -1
  282. package/dist/backend/target-diagnostics.js +44 -14
  283. package/dist/backend/target-diagnostics.js.map +1 -1
  284. package/dist/backend/target-diagnostics.test.js +93 -20
  285. package/dist/backend/target-diagnostics.test.js.map +1 -1
  286. package/dist/backend/targets.js +230 -86
  287. package/dist/backend/targets.js.map +1 -1
  288. package/dist/backend/targets.test.js +32 -18
  289. package/dist/backend/targets.test.js.map +1 -1
  290. package/dist/backend/toolchain-environment.js +5 -1
  291. package/dist/backend/toolchain-environment.js.map +1 -1
  292. package/dist/backend/vendor-archives.d.ts +2 -2
  293. package/dist/backend/vendor-archives.js +84 -35
  294. package/dist/backend/vendor-archives.js.map +1 -1
  295. package/dist/backend/vendor-inputs.js +13 -1
  296. package/dist/backend/vendor-inputs.js.map +1 -1
  297. package/dist/backend/warm-cache.d.ts +1 -1
  298. package/dist/backend/warm-cache.js +33 -9
  299. package/dist/backend/warm-cache.js.map +1 -1
  300. package/dist/cli/command.js +39 -9
  301. package/dist/cli/command.js.map +1 -1
  302. package/dist/cli/output-options.js +14 -4
  303. package/dist/cli/output-options.js.map +1 -1
  304. package/dist/cli/paths.js.map +1 -1
  305. package/dist/cli/wasi-runner.js.map +1 -1
  306. package/dist/compat/fetch-profile.js +36 -35
  307. package/dist/compat/fetch-profile.js.map +1 -1
  308. package/dist/coverage/report.js +16 -17
  309. package/dist/coverage/report.js.map +1 -1
  310. package/dist/coverage/surface-manifest.js +112 -26
  311. package/dist/coverage/surface-manifest.js.map +1 -1
  312. package/dist/diagnostics/diagnostic.js +55 -16
  313. package/dist/diagnostics/diagnostic.js.map +1 -1
  314. package/dist/executable/executable-cache.d.ts +1 -1
  315. package/dist/executable/executable-cache.js +78 -48
  316. package/dist/executable/executable-cache.js.map +1 -1
  317. package/dist/executable/executable-cache.test.js +75 -26
  318. package/dist/executable/executable-cache.test.js.map +1 -1
  319. package/dist/executable/prepare.js +2 -2
  320. package/dist/executable/prepare.js.map +1 -1
  321. package/dist/ffi/ffi-manifest.js +78 -20
  322. package/dist/ffi/ffi-manifest.js.map +1 -1
  323. package/dist/ffi/ffi-manifest.test.js +96 -16
  324. package/dist/ffi/ffi-manifest.test.js.map +1 -1
  325. package/dist/format-integer.js.map +1 -1
  326. package/dist/frontend/analysis.js +12 -2
  327. package/dist/frontend/analysis.js.map +1 -1
  328. package/dist/frontend/arguments-usage.js.map +1 -1
  329. package/dist/frontend/binding-source.js +9 -3
  330. package/dist/frontend/binding-source.js.map +1 -1
  331. package/dist/frontend/builtin-modules.js +46 -2
  332. package/dist/frontend/builtin-modules.js.map +1 -1
  333. package/dist/frontend/cjs-resolve.js +40 -17
  334. package/dist/frontend/cjs-resolve.js.map +1 -1
  335. package/dist/frontend/cjs-syntax.js +31 -10
  336. package/dist/frontend/cjs-syntax.js.map +1 -1
  337. package/dist/frontend/comptime-node.test.js +10 -11
  338. package/dist/frontend/comptime-node.test.js.map +1 -1
  339. package/dist/frontend/dts-paths.js +7 -3
  340. package/dist/frontend/dts-paths.js.map +1 -1
  341. package/dist/frontend/fork-target.js +17 -12
  342. package/dist/frontend/fork-target.js.map +1 -1
  343. package/dist/frontend/function-completion.js +11 -6
  344. package/dist/frontend/function-completion.js.map +1 -1
  345. package/dist/frontend/helper-tokens.js +53 -6
  346. package/dist/frontend/helper-tokens.js.map +1 -1
  347. package/dist/frontend/helper-tokens.test.js +18 -2
  348. package/dist/frontend/helper-tokens.test.js.map +1 -1
  349. package/dist/frontend/inferred-js-diagnostics.js +32 -12
  350. package/dist/frontend/inferred-js-diagnostics.js.map +1 -1
  351. package/dist/frontend/inferred-js-diagnostics.test.js +11 -15
  352. package/dist/frontend/inferred-js-diagnostics.test.js.map +1 -1
  353. package/dist/frontend/input-tracker.js +11 -11
  354. package/dist/frontend/input-tracker.js.map +1 -1
  355. package/dist/frontend/input-tracker.test.js +4 -1
  356. package/dist/frontend/input-tracker.test.js.map +1 -1
  357. package/dist/frontend/lib-contract.js +38 -9
  358. package/dist/frontend/lib-contract.js.map +1 -1
  359. package/dist/frontend/literal-values.js.map +1 -1
  360. package/dist/frontend/literal-values.test.js +28 -8
  361. package/dist/frontend/literal-values.test.js.map +1 -1
  362. package/dist/frontend/lowering/abstract-equality.js +53 -10
  363. package/dist/frontend/lowering/abstract-equality.js.map +1 -1
  364. package/dist/frontend/lowering/array-indexed-mutation.d.ts +1 -1
  365. package/dist/frontend/lowering/array-indexed-mutation.js +108 -106
  366. package/dist/frontend/lowering/array-indexed-mutation.js.map +1 -1
  367. package/dist/frontend/lowering/array-values.js +37 -14
  368. package/dist/frontend/lowering/array-values.js.map +1 -1
  369. package/dist/frontend/lowering/binding-analysis.d.ts +50 -0
  370. package/dist/frontend/lowering/binding-analysis.js +376 -0
  371. package/dist/frontend/lowering/binding-analysis.js.map +1 -0
  372. package/dist/frontend/lowering/builtin-calls.d.ts +9 -0
  373. package/dist/frontend/lowering/builtin-calls.js +60 -0
  374. package/dist/frontend/lowering/builtin-calls.js.map +1 -0
  375. package/dist/frontend/lowering/builtins/arguments.d.ts +43 -0
  376. package/dist/frontend/lowering/builtins/arguments.js +247 -0
  377. package/dist/frontend/lowering/builtins/arguments.js.map +1 -0
  378. package/dist/frontend/lowering/builtins/async-context.d.ts +52 -0
  379. package/dist/frontend/lowering/builtins/async-context.js +436 -0
  380. package/dist/frontend/lowering/builtins/async-context.js.map +1 -0
  381. package/dist/frontend/lowering/builtins/atomics.d.ts +15 -0
  382. package/dist/frontend/lowering/builtins/atomics.js +46 -0
  383. package/dist/frontend/lowering/builtins/atomics.js.map +1 -0
  384. package/dist/frontend/lowering/builtins/callable-aliases.d.ts +13 -0
  385. package/dist/frontend/lowering/builtins/callable-aliases.js +87 -0
  386. package/dist/frontend/lowering/builtins/callable-aliases.js.map +1 -0
  387. package/dist/frontend/lowering/builtins/child-process-async.d.ts +18 -0
  388. package/dist/frontend/lowering/builtins/child-process-async.js +245 -0
  389. package/dist/frontend/lowering/builtins/child-process-async.js.map +1 -0
  390. package/dist/frontend/lowering/builtins/child-process-methods.d.ts +21 -0
  391. package/dist/frontend/lowering/builtins/child-process-methods.js +362 -0
  392. package/dist/frontend/lowering/builtins/child-process-methods.js.map +1 -0
  393. package/dist/frontend/lowering/builtins/child-process-sync.d.ts +4 -0
  394. package/dist/frontend/lowering/builtins/child-process-sync.js +639 -0
  395. package/dist/frontend/lowering/builtins/child-process-sync.js.map +1 -0
  396. package/dist/frontend/lowering/builtins/child-process.d.ts +55 -0
  397. package/dist/frontend/lowering/builtins/child-process.js +669 -0
  398. package/dist/frontend/lowering/builtins/child-process.js.map +1 -0
  399. package/dist/frontend/lowering/builtins/compression.d.ts +7 -0
  400. package/dist/frontend/lowering/builtins/compression.js +115 -0
  401. package/dist/frontend/lowering/builtins/compression.js.map +1 -0
  402. package/dist/frontend/lowering/builtins/console.d.ts +10 -0
  403. package/dist/frontend/lowering/builtins/console.js +38 -0
  404. package/dist/frontend/lowering/builtins/console.js.map +1 -0
  405. package/dist/frontend/lowering/builtins/constants.d.ts +24 -0
  406. package/dist/frontend/lowering/builtins/constants.js +141 -0
  407. package/dist/frontend/lowering/builtins/constants.js.map +1 -0
  408. package/dist/frontend/lowering/builtins/crypto.d.ts +22 -0
  409. package/dist/frontend/lowering/builtins/crypto.js +517 -0
  410. package/dist/frontend/lowering/builtins/crypto.js.map +1 -0
  411. package/dist/frontend/lowering/builtins/dates.d.ts +7 -0
  412. package/dist/frontend/lowering/builtins/dates.js +101 -0
  413. package/dist/frontend/lowering/builtins/dates.js.map +1 -0
  414. package/dist/frontend/lowering/builtins/environment.d.ts +34 -0
  415. package/dist/frontend/lowering/builtins/environment.js +95 -0
  416. package/dist/frontend/lowering/builtins/environment.js.map +1 -0
  417. package/dist/frontend/lowering/builtins/errors.d.ts +14 -0
  418. package/dist/frontend/lowering/builtins/errors.js +83 -0
  419. package/dist/frontend/lowering/builtins/errors.js.map +1 -0
  420. package/dist/frontend/lowering/builtins/filesystem-calls.d.ts +32 -0
  421. package/dist/frontend/lowering/builtins/filesystem-calls.js +678 -0
  422. package/dist/frontend/lowering/builtins/filesystem-calls.js.map +1 -0
  423. package/dist/frontend/lowering/builtins/filesystem.d.ts +108 -0
  424. package/dist/frontend/lowering/builtins/filesystem.js +1061 -0
  425. package/dist/frontend/lowering/builtins/filesystem.js.map +1 -0
  426. package/dist/frontend/lowering/builtins/ipc.d.ts +8 -0
  427. package/dist/frontend/lowering/builtins/ipc.js +76 -0
  428. package/dist/frontend/lowering/builtins/ipc.js.map +1 -0
  429. package/dist/frontend/lowering/builtins/json.d.ts +12 -0
  430. package/dist/frontend/lowering/builtins/json.js +387 -0
  431. package/dist/frontend/lowering/builtins/json.js.map +1 -0
  432. package/dist/frontend/lowering/builtins/module-bindings.d.ts +85 -0
  433. package/dist/frontend/lowering/builtins/module-bindings.js +346 -0
  434. package/dist/frontend/lowering/builtins/module-bindings.js.map +1 -0
  435. package/dist/frontend/lowering/builtins/module-calls.d.ts +8 -0
  436. package/dist/frontend/lowering/builtins/module-calls.js +303 -0
  437. package/dist/frontend/lowering/builtins/module-calls.js.map +1 -0
  438. package/dist/frontend/lowering/builtins/module-resolution.d.ts +38 -0
  439. package/dist/frontend/lowering/builtins/module-resolution.js +344 -0
  440. package/dist/frontend/lowering/builtins/module-resolution.js.map +1 -0
  441. package/dist/frontend/lowering/builtins/numbers.d.ts +15 -0
  442. package/dist/frontend/lowering/builtins/numbers.js +124 -0
  443. package/dist/frontend/lowering/builtins/numbers.js.map +1 -0
  444. package/dist/frontend/lowering/builtins/operating-system.d.ts +13 -0
  445. package/dist/frontend/lowering/builtins/operating-system.js +148 -0
  446. package/dist/frontend/lowering/builtins/operating-system.js.map +1 -0
  447. package/dist/frontend/lowering/builtins/performance.d.ts +13 -0
  448. package/dist/frontend/lowering/builtins/performance.js +100 -0
  449. package/dist/frontend/lowering/builtins/performance.js.map +1 -0
  450. package/dist/frontend/lowering/builtins/process.d.ts +50 -0
  451. package/dist/frontend/lowering/builtins/process.js +1138 -0
  452. package/dist/frontend/lowering/builtins/process.js.map +1 -0
  453. package/dist/frontend/lowering/builtins/promises.d.ts +14 -0
  454. package/dist/frontend/lowering/builtins/promises.js +356 -0
  455. package/dist/frontend/lowering/builtins/promises.js.map +1 -0
  456. package/dist/frontend/lowering/builtins/properties.d.ts +11 -0
  457. package/dist/frontend/lowering/builtins/properties.js +186 -0
  458. package/dist/frontend/lowering/builtins/properties.js.map +1 -0
  459. package/dist/frontend/lowering/builtins/querystring.d.ts +19 -0
  460. package/dist/frontend/lowering/builtins/querystring.js +150 -0
  461. package/dist/frontend/lowering/builtins/querystring.js.map +1 -0
  462. package/dist/frontend/lowering/builtins/readline.d.ts +13 -0
  463. package/dist/frontend/lowering/builtins/readline.js +138 -0
  464. package/dist/frontend/lowering/builtins/readline.js.map +1 -0
  465. package/dist/frontend/lowering/builtins/receiver-types.d.ts +5 -0
  466. package/dist/frontend/lowering/builtins/receiver-types.js +15 -0
  467. package/dist/frontend/lowering/builtins/receiver-types.js.map +1 -0
  468. package/dist/frontend/lowering/builtins/reflection.d.ts +13 -0
  469. package/dist/frontend/lowering/builtins/reflection.js +95 -0
  470. package/dist/frontend/lowering/builtins/reflection.js.map +1 -0
  471. package/dist/frontend/lowering/builtins/strings.d.ts +14 -0
  472. package/dist/frontend/lowering/builtins/strings.js +121 -0
  473. package/dist/frontend/lowering/builtins/strings.js.map +1 -0
  474. package/dist/frontend/lowering/builtins/text-codecs.d.ts +29 -0
  475. package/dist/frontend/lowering/builtins/text-codecs.js +590 -0
  476. package/dist/frontend/lowering/builtins/text-codecs.js.map +1 -0
  477. package/dist/frontend/lowering/builtins/timers.d.ts +22 -0
  478. package/dist/frontend/lowering/builtins/timers.js +180 -0
  479. package/dist/frontend/lowering/builtins/timers.js.map +1 -0
  480. package/dist/frontend/lowering/builtins/url.d.ts +37 -0
  481. package/dist/frontend/lowering/builtins/url.js +596 -0
  482. package/dist/frontend/lowering/builtins/url.js.map +1 -0
  483. package/dist/frontend/lowering/builtins/util-types.d.ts +7 -0
  484. package/dist/frontend/lowering/builtins/util-types.js +31 -0
  485. package/dist/frontend/lowering/builtins/util-types.js.map +1 -0
  486. package/dist/frontend/lowering/call-arguments.d.ts +72 -0
  487. package/dist/frontend/lowering/call-arguments.js +618 -0
  488. package/dist/frontend/lowering/call-arguments.js.map +1 -0
  489. package/dist/frontend/lowering/call-signatures.d.ts +115 -0
  490. package/dist/frontend/lowering/call-signatures.js +719 -0
  491. package/dist/frontend/lowering/call-signatures.js.map +1 -0
  492. package/dist/frontend/lowering/callback-arg.js.map +1 -1
  493. package/dist/frontend/lowering/checked-iterable-spread.js +53 -10
  494. package/dist/frontend/lowering/checked-iterable-spread.js.map +1 -1
  495. package/dist/frontend/lowering/checked-promise-all.js +41 -9
  496. package/dist/frontend/lowering/checked-promise-all.js.map +1 -1
  497. package/dist/frontend/lowering/class-callbacks.d.ts +1 -1
  498. package/dist/frontend/lowering/class-callbacks.js +130 -27
  499. package/dist/frontend/lowering/class-callbacks.js.map +1 -1
  500. package/dist/frontend/lowering/class-construction.d.ts +1 -1
  501. package/dist/frontend/lowering/class-construction.js +247 -50
  502. package/dist/frontend/lowering/class-construction.js.map +1 -1
  503. package/dist/frontend/lowering/class-descriptors.js +109 -29
  504. package/dist/frontend/lowering/class-descriptors.js.map +1 -1
  505. package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +6 -1
  506. package/dist/frontend/lowering/class-dynamic-dispatch.js +2471 -465
  507. package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
  508. package/dist/frontend/lowering/class-dynamic-dispatch.test.js +284 -44
  509. package/dist/frontend/lowering/class-dynamic-dispatch.test.js.map +1 -1
  510. package/dist/frontend/lowering/class-instance-constructor.js +17 -5
  511. package/dist/frontend/lowering/class-instance-constructor.js.map +1 -1
  512. package/dist/frontend/lowering/class-method-values.js +199 -51
  513. package/dist/frontend/lowering/class-method-values.js.map +1 -1
  514. package/dist/frontend/lowering/class-prototypes.js +345 -86
  515. package/dist/frontend/lowering/class-prototypes.js.map +1 -1
  516. package/dist/frontend/lowering/class-runtime-statics.d.ts +1 -1
  517. package/dist/frontend/lowering/class-runtime-statics.js +80 -17
  518. package/dist/frontend/lowering/class-runtime-statics.js.map +1 -1
  519. package/dist/frontend/lowering/class-static-data.js +76 -16
  520. package/dist/frontend/lowering/class-static-data.js.map +1 -1
  521. package/dist/frontend/lowering/coercions/builders.d.ts +13 -0
  522. package/dist/frontend/lowering/coercions/builders.js +77 -0
  523. package/dist/frontend/lowering/coercions/builders.js.map +1 -0
  524. package/dist/frontend/lowering/coercions/function-adapters.d.ts +58 -0
  525. package/dist/frontend/lowering/coercions/function-adapters.js +430 -0
  526. package/dist/frontend/lowering/coercions/function-adapters.js.map +1 -0
  527. package/dist/frontend/lowering/coercions/island.d.ts +37 -0
  528. package/dist/frontend/lowering/coercions/island.js +350 -0
  529. package/dist/frontend/lowering/coercions/island.js.map +1 -0
  530. package/dist/frontend/lowering/coercions/state.d.ts +14 -0
  531. package/dist/frontend/lowering/coercions/state.js +16 -0
  532. package/dist/frontend/lowering/coercions/state.js.map +1 -0
  533. package/dist/frontend/lowering/coercions/structural-plans.d.ts +40 -0
  534. package/dist/frontend/lowering/coercions/structural-plans.js +447 -0
  535. package/dist/frontend/lowering/coercions/structural-plans.js.map +1 -0
  536. package/dist/frontend/lowering/coercions/structural.d.ts +63 -0
  537. package/dist/frontend/lowering/coercions/structural.js +616 -0
  538. package/dist/frontend/lowering/coercions/structural.js.map +1 -0
  539. package/dist/frontend/lowering/coercions/unions.d.ts +65 -0
  540. package/dist/frontend/lowering/coercions/unions.js +318 -0
  541. package/dist/frontend/lowering/coercions/unions.js.map +1 -0
  542. package/dist/frontend/lowering/collection-ingestion.js +355 -72
  543. package/dist/frontend/lowering/collection-ingestion.js.map +1 -1
  544. package/dist/frontend/lowering/containers/array-callbacks.d.ts +92 -0
  545. package/dist/frontend/lowering/containers/array-callbacks.js +1646 -0
  546. package/dist/frontend/lowering/containers/array-callbacks.js.map +1 -0
  547. package/dist/frontend/lowering/containers/array-construction.d.ts +42 -0
  548. package/dist/frontend/lowering/containers/array-construction.js +1044 -0
  549. package/dist/frontend/lowering/containers/array-construction.js.map +1 -0
  550. package/dist/frontend/lowering/containers/array-iteration.d.ts +16 -0
  551. package/dist/frontend/lowering/containers/array-iteration.js +95 -0
  552. package/dist/frontend/lowering/containers/array-iteration.js.map +1 -0
  553. package/dist/frontend/lowering/containers/array-methods.d.ts +27 -0
  554. package/dist/frontend/lowering/containers/array-methods.js +1854 -0
  555. package/dist/frontend/lowering/containers/array-methods.js.map +1 -0
  556. package/dist/frontend/lowering/containers/bytes.d.ts +17 -17
  557. package/dist/frontend/lowering/containers/bytes.js +419 -105
  558. package/dist/frontend/lowering/containers/bytes.js.map +1 -1
  559. package/dist/frontend/lowering/containers/callback-arguments.d.ts +26 -0
  560. package/dist/frontend/lowering/containers/callback-arguments.js +179 -0
  561. package/dist/frontend/lowering/containers/callback-arguments.js.map +1 -0
  562. package/dist/frontend/lowering/containers/collection-grouping.d.ts +19 -0
  563. package/dist/frontend/lowering/containers/collection-grouping.js +297 -0
  564. package/dist/frontend/lowering/containers/collection-grouping.js.map +1 -0
  565. package/dist/frontend/lowering/containers/collection-methods.d.ts +57 -0
  566. package/dist/frontend/lowering/containers/collection-methods.js +1314 -0
  567. package/dist/frontend/lowering/containers/collection-methods.js.map +1 -0
  568. package/dist/frontend/lowering/containers/dynamic-receivers.d.ts +18 -0
  569. package/dist/frontend/lowering/containers/dynamic-receivers.js +114 -0
  570. package/dist/frontend/lowering/containers/dynamic-receivers.js.map +1 -0
  571. package/dist/frontend/lowering/containers/for-of.d.ts +60 -0
  572. package/dist/frontend/lowering/containers/for-of.js +643 -0
  573. package/dist/frontend/lowering/containers/for-of.js.map +1 -0
  574. package/dist/frontend/lowering/containers/indexed-objects.d.ts +132 -0
  575. package/dist/frontend/lowering/containers/indexed-objects.js +1743 -0
  576. package/dist/frontend/lowering/containers/indexed-objects.js.map +1 -0
  577. package/dist/frontend/lowering/containers/iterator-helpers.d.ts +20 -0
  578. package/dist/frontend/lowering/containers/iterator-helpers.js +809 -0
  579. package/dist/frontend/lowering/containers/iterator-helpers.js.map +1 -0
  580. package/dist/frontend/lowering/containers/string-and-regexp.js +580 -158
  581. package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
  582. package/dist/frontend/lowering/containers/string-replacement.js +213 -63
  583. package/dist/frontend/lowering/containers/string-replacement.js.map +1 -1
  584. package/dist/frontend/lowering/crypto-tables.js +263 -64
  585. package/dist/frontend/lowering/crypto-tables.js.map +1 -1
  586. package/dist/frontend/lowering/deferred-module-initializers.js +172 -68
  587. package/dist/frontend/lowering/deferred-module-initializers.js.map +1 -1
  588. package/dist/frontend/lowering/deferred-module-initializers.test.js +41 -8
  589. package/dist/frontend/lowering/deferred-module-initializers.test.js.map +1 -1
  590. package/dist/frontend/lowering/error-methods.js +339 -65
  591. package/dist/frontend/lowering/error-methods.js.map +1 -1
  592. package/dist/frontend/lowering/expressions/evaluation-safety.js +3 -2
  593. package/dist/frontend/lowering/expressions/evaluation-safety.js.map +1 -1
  594. package/dist/frontend/lowering/expressions/global-symbols.js +2 -1
  595. package/dist/frontend/lowering/expressions/global-symbols.js.map +1 -1
  596. package/dist/frontend/lowering/expressions/native-proxy.js +11 -5
  597. package/dist/frontend/lowering/expressions/native-proxy.js.map +1 -1
  598. package/dist/frontend/lowering/expressions/nullish-assignment.js +67 -13
  599. package/dist/frontend/lowering/expressions/nullish-assignment.js.map +1 -1
  600. package/dist/frontend/lowering/expressions/object-literals.js +589 -162
  601. package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
  602. package/dist/frontend/lowering/expressions/optional-chains.d.ts +1 -1
  603. package/dist/frontend/lowering/expressions/optional-chains.js +68 -17
  604. package/dist/frontend/lowering/expressions/optional-chains.js.map +1 -1
  605. package/dist/frontend/lowering/expressions/union-field-write.js +45 -18
  606. package/dist/frontend/lowering/expressions/union-field-write.js.map +1 -1
  607. package/dist/frontend/lowering/function-context.js +5 -1
  608. package/dist/frontend/lowering/function-context.js.map +1 -1
  609. package/dist/frontend/lowering/function-returns.d.ts +67 -0
  610. package/dist/frontend/lowering/function-returns.js +392 -0
  611. package/dist/frontend/lowering/function-returns.js.map +1 -0
  612. package/dist/frontend/lowering/generator-delegation.d.ts +1 -1
  613. package/dist/frontend/lowering/generator-delegation.js +171 -39
  614. package/dist/frontend/lowering/generator-delegation.js.map +1 -1
  615. package/dist/frontend/lowering/generator-dynamic-dispatch.d.ts +1 -1
  616. package/dist/frontend/lowering/generator-dynamic-dispatch.js +176 -36
  617. package/dist/frontend/lowering/generator-dynamic-dispatch.js.map +1 -1
  618. package/dist/frontend/lowering/generic-functions.d.ts +274 -0
  619. package/dist/frontend/lowering/generic-functions.js +1727 -0
  620. package/dist/frontend/lowering/generic-functions.js.map +1 -0
  621. package/dist/frontend/lowering/import-meta.d.ts +1 -1
  622. package/dist/frontend/lowering/import-meta.js +37 -14
  623. package/dist/frontend/lowering/import-meta.js.map +1 -1
  624. package/dist/frontend/lowering/indexed-comparison.js +6 -2
  625. package/dist/frontend/lowering/indexed-comparison.js.map +1 -1
  626. package/dist/frontend/lowering/iterator-consumption.d.ts +9 -0
  627. package/dist/frontend/lowering/iterator-consumption.js +91 -0
  628. package/dist/frontend/lowering/iterator-consumption.js.map +1 -0
  629. package/dist/frontend/lowering/lib-boundary.js +40 -17
  630. package/dist/frontend/lowering/lib-boundary.js.map +1 -1
  631. package/dist/frontend/lowering/lib-boundary.test.js +49 -11
  632. package/dist/frontend/lowering/lib-boundary.test.js.map +1 -1
  633. package/dist/frontend/lowering/lower-array-sort.d.ts +0 -19
  634. package/dist/frontend/lowering/lower-array-sort.js +331 -566
  635. package/dist/frontend/lowering/lower-array-sort.js.map +1 -1
  636. package/dist/frontend/lowering/lower-assert.js +248 -43
  637. package/dist/frontend/lowering/lower-assert.js.map +1 -1
  638. package/dist/frontend/lowering/lower-async-iteration.js +71 -16
  639. package/dist/frontend/lowering/lower-async-iteration.js.map +1 -1
  640. package/dist/frontend/lowering/lower-builtin-values.js +420 -71
  641. package/dist/frontend/lowering/lower-builtin-values.js.map +1 -1
  642. package/dist/frontend/lowering/lower-calls.d.ts +39 -558
  643. package/dist/frontend/lowering/lower-calls.js +2593 -5667
  644. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  645. package/dist/frontend/lowering/lower-classes.d.ts +243 -242
  646. package/dist/frontend/lowering/lower-classes.js +1701 -724
  647. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  648. package/dist/frontend/lowering/lower-comptime.d.ts +35 -35
  649. package/dist/frontend/lowering/lower-comptime.js +39 -37
  650. package/dist/frontend/lowering/lower-comptime.js.map +1 -1
  651. package/dist/frontend/lowering/lower-dgram.js +59 -31
  652. package/dist/frontend/lowering/lower-dgram.js.map +1 -1
  653. package/dist/frontend/lowering/lower-enums.js +5 -2
  654. package/dist/frontend/lowering/lower-enums.js.map +1 -1
  655. package/dist/frontend/lowering/lower-event-emitter.js +322 -85
  656. package/dist/frontend/lowering/lower-event-emitter.js.map +1 -1
  657. package/dist/frontend/lowering/lower-expando.js +19 -7
  658. package/dist/frontend/lowering/lower-expando.js.map +1 -1
  659. package/dist/frontend/lowering/lower-exprs.d.ts +194 -194
  660. package/dist/frontend/lowering/lower-exprs.js +3446 -1154
  661. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  662. package/dist/frontend/lowering/lower-functions.d.ts +23 -0
  663. package/dist/frontend/lowering/lower-functions.js +449 -0
  664. package/dist/frontend/lowering/lower-functions.js.map +1 -0
  665. package/dist/frontend/lowering/lower-generators.js +121 -32
  666. package/dist/frontend/lowering/lower-generators.js.map +1 -1
  667. package/dist/frontend/lowering/lower-global-value.js +15 -4
  668. package/dist/frontend/lowering/lower-global-value.js.map +1 -1
  669. package/dist/frontend/lowering/lower-inspect.js +479 -89
  670. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  671. package/dist/frontend/lowering/lower-island.d.ts +79 -79
  672. package/dist/frontend/lowering/lower-island.js +365 -273
  673. package/dist/frontend/lowering/lower-island.js.map +1 -1
  674. package/dist/frontend/lowering/lower-island.test.js +7 -2
  675. package/dist/frontend/lowering/lower-island.test.js.map +1 -1
  676. package/dist/frontend/lowering/lower-mixins.js +17 -8
  677. package/dist/frontend/lowering/lower-mixins.js.map +1 -1
  678. package/dist/frontend/lowering/lower-modules.d.ts +94 -94
  679. package/dist/frontend/lowering/lower-modules.js +612 -321
  680. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  681. package/dist/frontend/lowering/lower-modules.test.js +91 -20
  682. package/dist/frontend/lowering/lower-modules.test.js.map +1 -1
  683. package/dist/frontend/lowering/lower-namespaces.js +25 -8
  684. package/dist/frontend/lowering/lower-namespaces.js.map +1 -1
  685. package/dist/frontend/lowering/lower-node-module.js +115 -34
  686. package/dist/frontend/lowering/lower-node-module.js.map +1 -1
  687. package/dist/frontend/lowering/lower-server.js +1210 -290
  688. package/dist/frontend/lowering/lower-server.js.map +1 -1
  689. package/dist/frontend/lowering/lower-stmts.d.ts +148 -148
  690. package/dist/frontend/lowering/lower-stmts.js +2312 -984
  691. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  692. package/dist/frontend/lowering/lower-stmts.test.js +13 -5
  693. package/dist/frontend/lowering/lower-stmts.test.js.map +1 -1
  694. package/dist/frontend/lowering/lower-stream.js +362 -90
  695. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  696. package/dist/frontend/lowering/lower-system-errors.js +30 -8
  697. package/dist/frontend/lowering/lower-system-errors.js.map +1 -1
  698. package/dist/frontend/lowering/lower-test.js +40 -13
  699. package/dist/frontend/lowering/lower-test.js.map +1 -1
  700. package/dist/frontend/lowering/lower-timers.d.ts +31 -0
  701. package/dist/frontend/lowering/lower-timers.js +336 -0
  702. package/dist/frontend/lowering/lower-timers.js.map +1 -0
  703. package/dist/frontend/lowering/lower-url.d.ts +1 -1
  704. package/dist/frontend/lowering/lower-url.js +46 -13
  705. package/dist/frontend/lowering/lower-url.js.map +1 -1
  706. package/dist/frontend/lowering/lowerer.d.ts +21 -351
  707. package/dist/frontend/lowering/lowerer.js +1024 -2704
  708. package/dist/frontend/lowering/lowerer.js.map +1 -1
  709. package/dist/frontend/lowering/lowerer.test.js +85 -17
  710. package/dist/frontend/lowering/lowerer.test.js.map +1 -1
  711. package/dist/frontend/lowering/module-namespace-elements.js +43 -8
  712. package/dist/frontend/lowering/module-namespace-elements.js.map +1 -1
  713. package/dist/frontend/lowering/native-ffi.d.ts +21 -1
  714. package/dist/frontend/lowering/native-ffi.js +487 -18
  715. package/dist/frontend/lowering/native-ffi.js.map +1 -1
  716. package/dist/frontend/lowering/object-enumeration-receiver.js +55 -10
  717. package/dist/frontend/lowering/object-enumeration-receiver.js.map +1 -1
  718. package/dist/frontend/lowering/object-factory-new.d.ts +1 -1
  719. package/dist/frontend/lowering/object-factory-new.js +36 -11
  720. package/dist/frontend/lowering/object-factory-new.js.map +1 -1
  721. package/dist/frontend/lowering/optional-arguments.js +49 -20
  722. package/dist/frontend/lowering/optional-arguments.js.map +1 -1
  723. package/dist/frontend/lowering/pairs-snapshot.js +66 -14
  724. package/dist/frontend/lowering/pairs-snapshot.js.map +1 -1
  725. package/dist/frontend/lowering/runtime-optional-locals.js +3 -1
  726. package/dist/frontend/lowering/runtime-optional-locals.js.map +1 -1
  727. package/dist/frontend/lowering/runtime-optional-locals.test.js.map +1 -1
  728. package/dist/frontend/lowering/sanitize-class-types.js +4 -1
  729. package/dist/frontend/lowering/sanitize-class-types.js.map +1 -1
  730. package/dist/frontend/lowering/sanitize-class-types.test.js +86 -18
  731. package/dist/frontend/lowering/sanitize-class-types.test.js.map +1 -1
  732. package/dist/frontend/lowering/static-this.js +13 -6
  733. package/dist/frontend/lowering/static-this.js.map +1 -1
  734. package/dist/frontend/lowering/string-index.js +32 -10
  735. package/dist/frontend/lowering/string-index.js.map +1 -1
  736. package/dist/frontend/lowering/surfaces.d.ts +42 -42
  737. package/dist/frontend/lowering/surfaces.js +1094 -249
  738. package/dist/frontend/lowering/surfaces.js.map +1 -1
  739. package/dist/frontend/lowering/symbol-fields.js +40 -15
  740. package/dist/frontend/lowering/symbol-fields.js.map +1 -1
  741. package/dist/frontend/lowering/symbol-methods.js.map +1 -1
  742. package/dist/frontend/lowering/text-decoder-encoding.js +236 -24
  743. package/dist/frontend/lowering/text-decoder-encoding.js.map +1 -1
  744. package/dist/frontend/lowering/text-decoder-encoding.test.js +84 -12
  745. package/dist/frontend/lowering/text-decoder-encoding.test.js.map +1 -1
  746. package/dist/frontend/lowering/union-narrow.js +59 -16
  747. package/dist/frontend/lowering/union-narrow.js.map +1 -1
  748. package/dist/frontend/lowering/union-narrow.test.js +24 -7
  749. package/dist/frontend/lowering/union-narrow.test.js.map +1 -1
  750. package/dist/frontend/lowering/union-retag.js +155 -40
  751. package/dist/frontend/lowering/union-retag.js.map +1 -1
  752. package/dist/frontend/lowering/union-retag.test.js +131 -33
  753. package/dist/frontend/lowering/union-retag.test.js.map +1 -1
  754. package/dist/frontend/lowering/unregistered-class-types.js.map +1 -1
  755. package/dist/frontend/lowering/unregistered-class-types.test.js +34 -8
  756. package/dist/frontend/lowering/unregistered-class-types.test.js.map +1 -1
  757. package/dist/frontend/module-syntax.js +21 -8
  758. package/dist/frontend/module-syntax.js.map +1 -1
  759. package/dist/frontend/module-syntax.test.js +37 -13
  760. package/dist/frontend/module-syntax.test.js.map +1 -1
  761. package/dist/frontend/npm-fetch-analysis.js +13 -4
  762. package/dist/frontend/npm-fetch-analysis.js.map +1 -1
  763. package/dist/frontend/npm-fetch-analysis.test.js +33 -10
  764. package/dist/frontend/npm-fetch-analysis.test.js.map +1 -1
  765. package/dist/frontend/npm-fetch-node.js.map +1 -1
  766. package/dist/frontend/npm-fetch-syntax.js +4 -9
  767. package/dist/frontend/npm-fetch-syntax.js.map +1 -1
  768. package/dist/frontend/npm-node.js +3 -1
  769. package/dist/frontend/npm-node.js.map +1 -1
  770. package/dist/frontend/npm-static-bundled-cjs.js +88 -29
  771. package/dist/frontend/npm-static-bundled-cjs.js.map +1 -1
  772. package/dist/frontend/npm-static-bundled-cjs.test.js +29 -10
  773. package/dist/frontend/npm-static-bundled-cjs.test.js.map +1 -1
  774. package/dist/frontend/npm-static-declaration-syntax.js +148 -56
  775. package/dist/frontend/npm-static-declaration-syntax.js.map +1 -1
  776. package/dist/frontend/npm-static-declarations.d.ts +1 -1
  777. package/dist/frontend/npm-static-declarations.js.map +1 -1
  778. package/dist/frontend/npm-static-declarations.test.js +33 -7
  779. package/dist/frontend/npm-static-declarations.test.js.map +1 -1
  780. package/dist/frontend/npm-static-prune.js +26 -12
  781. package/dist/frontend/npm-static-prune.js.map +1 -1
  782. package/dist/frontend/npm-static-prune.test.js +17 -3
  783. package/dist/frontend/npm-static-prune.test.js.map +1 -1
  784. package/dist/frontend/npm-static-rewrite-host.js +2 -3
  785. package/dist/frontend/npm-static-rewrite-host.js.map +1 -1
  786. package/dist/frontend/npm-static-rewrite-syntax.js +64 -21
  787. package/dist/frontend/npm-static-rewrite-syntax.js.map +1 -1
  788. package/dist/frontend/npm-static-rewrite.js.map +1 -1
  789. package/dist/frontend/npm-static-subtyping.js +9 -4
  790. package/dist/frontend/npm-static-subtyping.js.map +1 -1
  791. package/dist/frontend/npm-static-subtyping.test.js +30 -6
  792. package/dist/frontend/npm-static-subtyping.test.js.map +1 -1
  793. package/dist/frontend/npm-static.js +15 -4
  794. package/dist/frontend/npm-static.js.map +1 -1
  795. package/dist/frontend/npm.js +122 -36
  796. package/dist/frontend/npm.js.map +1 -1
  797. package/dist/frontend/npm.test.js +30 -10
  798. package/dist/frontend/npm.test.js.map +1 -1
  799. package/dist/frontend/pipeline-native.js.map +1 -1
  800. package/dist/frontend/pipeline.js +25 -8
  801. package/dist/frontend/pipeline.js.map +1 -1
  802. package/dist/frontend/pipeline.test.js +21 -7
  803. package/dist/frontend/pipeline.test.js.map +1 -1
  804. package/dist/frontend/program-node.js +5 -3
  805. package/dist/frontend/program-node.js.map +1 -1
  806. package/dist/frontend/program.d.ts +2 -2
  807. package/dist/frontend/program.js +234 -101
  808. package/dist/frontend/program.js.map +1 -1
  809. package/dist/frontend/program.test.js +27 -27
  810. package/dist/frontend/program.test.js.map +1 -1
  811. package/dist/frontend/provenance-core.js +8 -4
  812. package/dist/frontend/provenance-core.js.map +1 -1
  813. package/dist/frontend/provenance-registry.js +1 -4
  814. package/dist/frontend/provenance-registry.js.map +1 -1
  815. package/dist/frontend/resolve.js +32 -20
  816. package/dist/frontend/resolve.js.map +1 -1
  817. package/dist/frontend/resolve.test.js +1 -1
  818. package/dist/frontend/resolve.test.js.map +1 -1
  819. package/dist/frontend/runtime-resolve.js +13 -4
  820. package/dist/frontend/runtime-resolve.js.map +1 -1
  821. package/dist/frontend/runtime-resolve.test.js +25 -9
  822. package/dist/frontend/runtime-resolve.test.js.map +1 -1
  823. package/dist/frontend/services-node.js +6 -2
  824. package/dist/frontend/services-node.js.map +1 -1
  825. package/dist/frontend/services-node.test.js +18 -6
  826. package/dist/frontend/services-node.test.js.map +1 -1
  827. package/dist/frontend/services.js +8 -4
  828. package/dist/frontend/services.js.map +1 -1
  829. package/dist/frontend/services.test.js +6 -2
  830. package/dist/frontend/services.test.js.map +1 -1
  831. package/dist/frontend/ts7/api.js +12 -4
  832. package/dist/frontend/ts7/api.js.map +1 -1
  833. package/dist/frontend/ts7/ast-bytes.js +10 -3
  834. package/dist/frontend/ts7/ast-bytes.js.map +1 -1
  835. package/dist/frontend/ts7/ast-bytes.test.js +23 -4
  836. package/dist/frontend/ts7/ast-bytes.test.js.map +1 -1
  837. package/dist/frontend/ts7/ast-guards.test.js +14 -5
  838. package/dist/frontend/ts7/ast-guards.test.js.map +1 -1
  839. package/dist/frontend/ts7/ast-node.d.ts +6 -1
  840. package/dist/frontend/ts7/ast-node.js +484 -164
  841. package/dist/frontend/ts7/ast-node.js.map +1 -1
  842. package/dist/frontend/ts7/ast-node.test.js +109 -36
  843. package/dist/frontend/ts7/ast-node.test.js.map +1 -1
  844. package/dist/frontend/ts7/ast-text.js +13 -3
  845. package/dist/frontend/ts7/ast-text.js.map +1 -1
  846. package/dist/frontend/ts7/ast-text.test.js.map +1 -1
  847. package/dist/frontend/ts7/ast-types.js.map +1 -1
  848. package/dist/frontend/ts7/ast-wire.d.ts +1 -1
  849. package/dist/frontend/ts7/ast-wire.js +55 -20
  850. package/dist/frontend/ts7/ast-wire.js.map +1 -1
  851. package/dist/frontend/ts7/ast-wire.test.js +53 -8
  852. package/dist/frontend/ts7/ast-wire.test.js.map +1 -1
  853. package/dist/frontend/ts7/ast.js +47 -28
  854. package/dist/frontend/ts7/ast.js.map +1 -1
  855. package/dist/frontend/ts7/census-check.js +1 -1
  856. package/dist/frontend/ts7/census-check.js.map +1 -1
  857. package/dist/frontend/ts7/checker-cache.js.map +1 -1
  858. package/dist/frontend/ts7/checker.js +5 -3
  859. package/dist/frontend/ts7/checker.js.map +1 -1
  860. package/dist/frontend/ts7/checker.test.js +54 -17
  861. package/dist/frontend/ts7/checker.test.js.map +1 -1
  862. package/dist/frontend/ts7/enums.test.js +9 -4
  863. package/dist/frontend/ts7/enums.test.js.map +1 -1
  864. package/dist/frontend/ts7/native-api.js.map +1 -1
  865. package/dist/frontend/ts7/native-host.js.map +1 -1
  866. package/dist/frontend/ts7/native-process.js +9 -3
  867. package/dist/frontend/ts7/native-process.js.map +1 -1
  868. package/dist/frontend/ts7/program-adapter.js +1 -1
  869. package/dist/frontend/ts7/program-adapter.js.map +1 -1
  870. package/dist/frontend/ts7/program-host.js +7 -4
  871. package/dist/frontend/ts7/program-host.js.map +1 -1
  872. package/dist/frontend/ts7/program-host.test.js +43 -11
  873. package/dist/frontend/ts7/program-host.test.js.map +1 -1
  874. package/dist/frontend/ts7/rpc-api.js +3 -1
  875. package/dist/frontend/ts7/rpc-api.js.map +1 -1
  876. package/dist/frontend/ts7/rpc-client.js +15 -5
  877. package/dist/frontend/ts7/rpc-client.js.map +1 -1
  878. package/dist/frontend/ts7/rpc-client.test.js +26 -8
  879. package/dist/frontend/ts7/rpc-client.test.js.map +1 -1
  880. package/dist/frontend/ts7/rpc-filesystem.js.map +1 -1
  881. package/dist/frontend/ts7/rpc-filesystem.test.js +43 -10
  882. package/dist/frontend/ts7/rpc-filesystem.test.js.map +1 -1
  883. package/dist/frontend/ts7/rpc-process.js +16 -6
  884. package/dist/frontend/ts7/rpc-process.js.map +1 -1
  885. package/dist/frontend/ts7/rpc-process.test.js.map +1 -1
  886. package/dist/frontend/ts7/rpc-wire.d.ts +1 -0
  887. package/dist/frontend/ts7/rpc-wire.js +41 -14
  888. package/dist/frontend/ts7/rpc-wire.js.map +1 -1
  889. package/dist/frontend/ts7/rpc-wire.test.js +36 -6
  890. package/dist/frontend/ts7/rpc-wire.test.js.map +1 -1
  891. package/dist/frontend/ts7/semantic-checker.js +209 -68
  892. package/dist/frontend/ts7/semantic-checker.js.map +1 -1
  893. package/dist/frontend/ts7/semantic-checker.test.js +29 -14
  894. package/dist/frontend/ts7/semantic-checker.test.js.map +1 -1
  895. package/dist/frontend/ts7/semantic-json.js +7 -1
  896. package/dist/frontend/ts7/semantic-json.js.map +1 -1
  897. package/dist/frontend/ts7/semantic-json.test.js +17 -3
  898. package/dist/frontend/ts7/semantic-json.test.js.map +1 -1
  899. package/dist/frontend/ts7/semantic-model.js +147 -51
  900. package/dist/frontend/ts7/semantic-model.js.map +1 -1
  901. package/dist/frontend/ts7/semantic-model.test.js +72 -19
  902. package/dist/frontend/ts7/semantic-model.test.js.map +1 -1
  903. package/dist/frontend/ts7/semantic-types.d.ts +2 -2
  904. package/dist/frontend/ts7/session-cache.js +10 -3
  905. package/dist/frontend/ts7/session-cache.js.map +1 -1
  906. package/dist/frontend/ts7/session-cache.test.js +13 -4
  907. package/dist/frontend/ts7/session-cache.test.js.map +1 -1
  908. package/dist/frontend/ts7/session-path.js +25 -10
  909. package/dist/frontend/ts7/session-path.js.map +1 -1
  910. package/dist/frontend/ts7/session-path.test.js +47 -4
  911. package/dist/frontend/ts7/session-path.test.js.map +1 -1
  912. package/dist/frontend/ts7/session-timing.js +22 -3
  913. package/dist/frontend/ts7/session-timing.js.map +1 -1
  914. package/dist/frontend/ts7/session-timing.test.js +12 -3
  915. package/dist/frontend/ts7/session-timing.test.js.map +1 -1
  916. package/dist/frontend/ts7/session.d.ts +1 -0
  917. package/dist/frontend/ts7/session.js +109 -35
  918. package/dist/frontend/ts7/session.js.map +1 -1
  919. package/dist/frontend/ts7/session.test.js +69 -15
  920. package/dist/frontend/ts7/session.test.js.map +1 -1
  921. package/dist/frontend/ts7/source-parser.js +17 -6
  922. package/dist/frontend/ts7/source-parser.js.map +1 -1
  923. package/dist/frontend/ts7/source-parser.test.js +32 -9
  924. package/dist/frontend/ts7/source-parser.test.js.map +1 -1
  925. package/dist/frontend/tsc-codes.js +56 -11
  926. package/dist/frontend/tsc-codes.js.map +1 -1
  927. package/dist/frontend/tsc-codes.test.d.ts +1 -0
  928. package/dist/frontend/tsc-codes.test.js +16 -0
  929. package/dist/frontend/tsc-codes.test.js.map +1 -0
  930. package/dist/frontend/type-mapper.js +545 -204
  931. package/dist/frontend/type-mapper.js.map +1 -1
  932. package/dist/frontend/type-mapper.test.js +108 -33
  933. package/dist/frontend/type-mapper.test.js.map +1 -1
  934. package/dist/frontend/union-discriminants.js +8 -2
  935. package/dist/frontend/union-discriminants.js.map +1 -1
  936. package/dist/frontend/union-discriminants.test.js +77 -20
  937. package/dist/frontend/union-discriminants.test.js.map +1 -1
  938. package/dist/index.d.ts +9 -8
  939. package/dist/index.js +150 -81
  940. package/dist/index.js.map +1 -1
  941. package/dist/ir/analysis.js +95 -38
  942. package/dist/ir/analysis.js.map +1 -1
  943. package/dist/ir/analysis.test.js +91 -15
  944. package/dist/ir/analysis.test.js.map +1 -1
  945. package/dist/ir/api.d.ts +4 -0
  946. package/dist/ir/api.js +6 -0
  947. package/dist/ir/api.js.map +1 -0
  948. package/dist/ir/build.d.ts +7 -0
  949. package/dist/ir/build.js +27 -1
  950. package/dist/ir/build.js.map +1 -1
  951. package/dist/ir/builtin-effects.d.ts +9 -0
  952. package/dist/ir/builtin-effects.js +631 -0
  953. package/dist/ir/builtin-effects.js.map +1 -0
  954. package/dist/ir/builtin-signatures.d.ts +15 -0
  955. package/dist/ir/builtin-signatures.js +3396 -0
  956. package/dist/ir/builtin-signatures.js.map +1 -0
  957. package/dist/ir/byte-numbers.js +67 -16
  958. package/dist/ir/byte-numbers.js.map +1 -1
  959. package/dist/ir/byte-numbers.test.js +17 -4
  960. package/dist/ir/byte-numbers.test.js.map +1 -1
  961. package/dist/ir/constant-tables.js +13 -5
  962. package/dist/ir/constant-tables.js.map +1 -1
  963. package/dist/ir/constant-tables.test.js +47 -7
  964. package/dist/ir/constant-tables.test.js.map +1 -1
  965. package/dist/ir/control-flow.js +2 -1
  966. package/dist/ir/control-flow.js.map +1 -1
  967. package/dist/ir/control-flow.test.js +35 -11
  968. package/dist/ir/control-flow.test.js.map +1 -1
  969. package/dist/ir/initializer-bindings.d.ts +9 -0
  970. package/dist/ir/initializer-bindings.js +115 -0
  971. package/dist/ir/initializer-bindings.js.map +1 -0
  972. package/dist/ir/initializer-bindings.test.d.ts +1 -0
  973. package/dist/ir/initializer-bindings.test.js +118 -0
  974. package/dist/ir/initializer-bindings.test.js.map +1 -0
  975. package/dist/ir/integer-loop-facts.d.ts +12 -0
  976. package/dist/ir/integer-loop-facts.js +137 -0
  977. package/dist/ir/integer-loop-facts.js.map +1 -0
  978. package/dist/ir/integer-loops.js +85 -30
  979. package/dist/ir/integer-loops.js.map +1 -1
  980. package/dist/ir/integer-loops.test.js +76 -13
  981. package/dist/ir/integer-loops.test.js.map +1 -1
  982. package/dist/ir/integer-ranges.js +93 -21
  983. package/dist/ir/integer-ranges.js.map +1 -1
  984. package/dist/ir/integer-ranges.test.js +199 -21
  985. package/dist/ir/integer-ranges.test.js.map +1 -1
  986. package/dist/ir/intrinsic-signatures.d.ts +20 -0
  987. package/dist/ir/intrinsic-signatures.js +57 -0
  988. package/dist/ir/intrinsic-signatures.js.map +1 -0
  989. package/dist/ir/ir.d.ts +6 -2150
  990. package/dist/ir/ir.js +160 -1396
  991. package/dist/ir/ir.js.map +1 -1
  992. package/dist/ir/ir.test.js +98 -77
  993. package/dist/ir/ir.test.js.map +1 -1
  994. package/dist/ir/runtime-features.d.ts +221 -0
  995. package/dist/ir/runtime-features.js +551 -0
  996. package/dist/ir/runtime-features.js.map +1 -0
  997. package/dist/ir/runtime-features.test.d.ts +1 -0
  998. package/dist/ir/runtime-features.test.js +98 -0
  999. package/dist/ir/runtime-features.test.js.map +1 -0
  1000. package/dist/ir/scalar-records.js +130 -40
  1001. package/dist/ir/scalar-records.js.map +1 -1
  1002. package/dist/ir/scalar-records.test.js +146 -27
  1003. package/dist/ir/scalar-records.test.js.map +1 -1
  1004. package/dist/ir/serialize.js +4 -2
  1005. package/dist/ir/serialize.js.map +1 -1
  1006. package/dist/ir/serialize.test.js +44 -9
  1007. package/dist/ir/serialize.test.js.map +1 -1
  1008. package/dist/ir/traverse.js +156 -43
  1009. package/dist/ir/traverse.js.map +1 -1
  1010. package/dist/ir/traverse.test.js +99 -24
  1011. package/dist/ir/traverse.test.js.map +1 -1
  1012. package/dist/ir/validate.d.ts +1 -31
  1013. package/dist/ir/validate.js +782 -1889
  1014. package/dist/ir/validate.js.map +1 -1
  1015. package/dist/ir/validate.test.js +610 -114
  1016. package/dist/ir/validate.test.js.map +1 -1
  1017. package/dist/library/cache-primitives.js +9 -10
  1018. package/dist/library/cache-primitives.js.map +1 -1
  1019. package/dist/library/cache-reset.test.js +2 -1
  1020. package/dist/library/cache-reset.test.js.map +1 -1
  1021. package/dist/library/compiler-self-identity.js +11 -5
  1022. package/dist/library/compiler-self-identity.js.map +1 -1
  1023. package/dist/library/compiler-self-identity.test.js +10 -3
  1024. package/dist/library/compiler-self-identity.test.js.map +1 -1
  1025. package/dist/library/fence-eval.js +24 -7
  1026. package/dist/library/fence-eval.js.map +1 -1
  1027. package/dist/library/fence-eval.test.js +31 -7
  1028. package/dist/library/fence-eval.test.js.map +1 -1
  1029. package/dist/library/int-infer.js +199 -59
  1030. package/dist/library/int-infer.js.map +1 -1
  1031. package/dist/library/int-infer.test.js +133 -57
  1032. package/dist/library/int-infer.test.js.map +1 -1
  1033. package/dist/library/ir-policy.d.ts +27 -0
  1034. package/dist/library/ir-policy.js +232 -0
  1035. package/dist/library/ir-policy.js.map +1 -0
  1036. package/dist/library/library-cache.js +40 -17
  1037. package/dist/library/library-cache.js.map +1 -1
  1038. package/dist/library/library-cache.test.js +24 -13
  1039. package/dist/library/library-cache.test.js.map +1 -1
  1040. package/dist/library/library-profile.js +68 -13
  1041. package/dist/library/library-profile.js.map +1 -1
  1042. package/dist/library/prepare.js +48 -20
  1043. package/dist/library/prepare.js.map +1 -1
  1044. package/dist/library/semantic-source.js +16 -14
  1045. package/dist/library/semantic-source.js.map +1 -1
  1046. package/dist/library/semantic-source.test.js +9 -14
  1047. package/dist/library/semantic-source.test.js.map +1 -1
  1048. package/dist/library/sidecar-validate.js +53 -12
  1049. package/dist/library/sidecar-validate.js.map +1 -1
  1050. package/dist/library/sidecar.js +85 -24
  1051. package/dist/library/sidecar.js.map +1 -1
  1052. package/dist/library/trap-teaching.js +11 -2
  1053. package/dist/library/trap-teaching.js.map +1 -1
  1054. package/dist/native/cache.js +10 -4
  1055. package/dist/native/cache.js.map +1 -1
  1056. package/dist/native/cli.js +34 -9
  1057. package/dist/native/cli.js.map +1 -1
  1058. package/dist/native/compiler.js +167 -43
  1059. package/dist/native/compiler.js.map +1 -1
  1060. package/dist/native/compiler.test.js +129 -32
  1061. package/dist/native/compiler.test.js.map +1 -1
  1062. package/dist/native/comptime.js +23 -7
  1063. package/dist/native/comptime.js.map +1 -1
  1064. package/dist/native/comptime.test.js +26 -6
  1065. package/dist/native/comptime.test.js.map +1 -1
  1066. package/dist/native/executable-cache.js +77 -27
  1067. package/dist/native/executable-cache.js.map +1 -1
  1068. package/dist/native/executable-cache.test.js +41 -6
  1069. package/dist/native/executable-cache.test.js.map +1 -1
  1070. package/dist/native/file-identity.js +9 -2
  1071. package/dist/native/file-identity.js.map +1 -1
  1072. package/dist/native/file-identity.test.js.map +1 -1
  1073. package/dist/native/library.js +50 -12
  1074. package/dist/native/library.js.map +1 -1
  1075. package/dist/native/prepare.js +119 -34
  1076. package/dist/native/prepare.js.map +1 -1
  1077. package/dist/native/prepare.test.js +22 -6
  1078. package/dist/native/prepare.test.js.map +1 -1
  1079. package/dist/native/runtime-typescript.js +24 -11
  1080. package/dist/native/runtime-typescript.js.map +1 -1
  1081. package/dist/native/runtime-typescript.test.js.map +1 -1
  1082. package/dist/native/sanitizer.js +71 -18
  1083. package/dist/native/sanitizer.js.map +1 -1
  1084. package/dist/native/sanitizer.test.js +77 -20
  1085. package/dist/native/sanitizer.test.js.map +1 -1
  1086. package/dist/native/task.js.map +1 -1
  1087. package/dist/native/task.test.js +7 -2
  1088. package/dist/native/task.test.js.map +1 -1
  1089. package/dist/native/toolchain.js +68 -26
  1090. package/dist/native/toolchain.js.map +1 -1
  1091. package/dist/native/toolchain.test.js +59 -20
  1092. package/dist/native/toolchain.test.js.map +1 -1
  1093. package/dist/startup-cache.d.ts +1 -1
  1094. package/dist/startup-cache.js +1 -1
  1095. package/dist/startup-cache.js.map +1 -1
  1096. package/dist/timing.js.map +1 -1
  1097. package/package.json +20 -20
  1098. package/surface-manifest.json +1 -1
  1099. package/dist/frontend/lowering/lower-builtins.d.ts +0 -601
  1100. package/dist/frontend/lowering/lower-builtins.js +0 -8986
  1101. package/dist/frontend/lowering/lower-builtins.js.map +0 -1
  1102. package/dist/frontend/lowering/lower-containers.d.ts +0 -382
  1103. package/dist/frontend/lowering/lower-containers.js +0 -7344
  1104. package/dist/frontend/lowering/lower-containers.js.map +0 -1
@@ -1,3973 +1,19 @@
1
- import { driverTraceCandidates, linkTraceCandidate } from "./link-trace.js";
2
- import { toolchainEnvironmentCachePolicy, toolchainEnvironmentFingerprint } from "./toolchain-environment.js";
3
- export { toolchainEnvironmentCachePolicy, toolchainEnvironmentFingerprint } from "./toolchain-environment.js";
4
- import { IPHONEOS_MIN_VERSION, ANDROID_MIN_API, isIosTarget, isAndroidTarget, isMobileTarget, mobileLibraryTarget, mobileTargetRefusal, configuredTargetPlatform } from "./target-platform.js";
5
- export { IPHONEOS_MIN_VERSION, ANDROID_MIN_API, isIosTarget, isAndroidTarget, isMobileTarget, mobileLibraryTarget, mobileTargetRefusal, configuredTargetPlatform } from "./target-platform.js";
6
- import { InternalCompilerError } from "../errors.js";
7
- import { execFile, spawnSync } from "node:child_process";
8
- import { createHash, randomUUID } from "node:crypto";
9
- import { constants as fsConstants, existsSync, readdirSync } from "node:fs";
10
- import { createRequire } from "node:module";
11
- import { access, chmod, copyFile, link, lstat, mkdir, mkdtemp, readdir, readFile, realpath, rename, rm, stat, utimes, writeFile } from "node:fs/promises";
12
- import { availableParallelism, homedir, tmpdir } from "node:os";
13
- import { basename, delimiter, dirname, extname, isAbsolute, join, relative, resolve } from "node:path";
14
- import { performance } from "node:perf_hooks";
15
- import { fileURLToPath } from "node:url";
16
- import { promisify } from "node:util";
17
- import { localizeElfObject, mergeAndLocalizeCoffObjects } from "./object-localize.js";
18
- import { executableOptimizationLinkerArgs, executableStripLinkerArgs, windowsSubsystemLinkerArgs } from "./targets.js";
19
- import { createDarwinDebugSymbols, installDarwinDebugSymbols, needsDarwinDebugSymbols, readDarwinDebugSymbols } from "./debug-symbols.js";
20
- import { createVendorArchives, MBEDTLS_VERSION, QJS_COMMIT, ZLIB_VERSION, } from "./vendor-archives.js";
21
- import { cacheDigestPath, cacheRootDir, copyValidCachedFile, ensurePrivateCacheRoot, fileDigest, fileExists, installArtifact, privateSiblingPath, protectCachedArtifact, pruneCache, publishCachedFile, validCachedFile, } from "./build-cache.js";
1
+ /** Native compiler facade. Recipe implementation lives with its semantic owner. */
2
+ export { EXECUTABLE_RUNTIME_SOURCES, runtimeSrcDir, runtimeFingerprint, } from "./native/runtime-inputs.js";
3
+ export { executableSectionEliminationFlags, isZigDriver, resolveCc, targetPlatform, cacheTargetIdentity, } from "./native/driver.js";
4
+ export { executableNativeEnvironmentFingerprint, compilerDriverSupportsPersistentCache, ccVersion, } from "./native/tool-identity.js";
5
+ export {} from "./native/contracts.js";
6
+ export { CcCompileError, subprocessFailureDetail } from "./native/process.js";
7
+ export { compileLibArchive } from "./native/library.js";
8
+ export { localizeLibraryObjects } from "./native/object-merge.js";
9
+ export { implicitDependencyProbeIncludes } from "./native/compiler-fingerprint.js";
10
+ export { parseLinkTraceFiles, nativeLinkerDependencyPaths } from "./native/linker-fingerprint.js";
11
+ export { clearCcCaches, stageRuntimeObjects } from "./native/runtime-objects.js";
12
+ export { snapshotNativeArtifactDependencies, nativeArtifactDependenciesStillMatch, } from "./native/artifact-stamps.js";
13
+ export { compileC } from "./native/executable.js";
14
+ export { supportedNativeCacheWarmProfiles, warmNativeCaches, } from "./native/cache-warm.js";
15
+ export { toolchainEnvironmentCachePolicy, toolchainEnvironmentFingerprint, } from "./toolchain-environment.js";
16
+ export { IPHONEOS_MIN_VERSION, ANDROID_MIN_API, isIosTarget, isAndroidTarget, isMobileTarget, mobileLibraryTarget, mobileTargetRefusal, configuredTargetPlatform, } from "./target-platform.js";
22
17
  export { buildCacheRoot, prepareBuildCacheRoot, pruneBuildCache, resolveBuildCacheRoot, } from "./build-cache.js";
23
- const execFileAsync = promisify(execFile);
24
- const NATIVE_TOOLCHAIN_IMPLEMENTATION_PATH = fileURLToPath(import.meta.url);
25
- const NATIVE_RECIPE_IMPLEMENTATION_PATHS = [
26
- NATIVE_TOOLCHAIN_IMPLEMENTATION_PATH,
27
- join(dirname(NATIVE_TOOLCHAIN_IMPLEMENTATION_PATH), `build-cache${extname(NATIVE_TOOLCHAIN_IMPLEMENTATION_PATH)}`),
28
- join(dirname(NATIVE_TOOLCHAIN_IMPLEMENTATION_PATH), `vendor-archives${extname(NATIVE_TOOLCHAIN_IMPLEMENTATION_PATH)}`),
29
- ];
30
- /** Test lanes run against one immutable checkout and one immutable toolchain
31
- * for the lifetime of each Vitest worker. Production deliberately rediscovers
32
- * compiler/linker inputs on every invocation, but doing that thousands of
33
- * times in the differential corpus costs far more than the compile itself.
34
- * This test-only opt-in lets those workers reuse metadata probes for their
35
- * session; the cache-correctness suite removes the flag and exercises the
36
- * strict production path. */
37
- function stableTestToolchainSession() {
38
- return process.env["SCRIPTC_TEST_STABLE_TOOLCHAIN"] === "1";
39
- }
40
- function stableTestMemo(cache, key, probe) {
41
- if (!stableTestToolchainSession())
42
- return probe();
43
- const existing = cache.get(key);
44
- if (existing !== undefined)
45
- return existing;
46
- const pending = probe();
47
- cache.set(key, pending);
48
- void pending.catch(() => {
49
- if (cache.get(key) === pending)
50
- cache.delete(key);
51
- });
52
- return pending;
53
- }
54
- export const EXECUTABLE_RUNTIME_SOURCES = ["scr_number.c", "scr_bigint.c", "scr_string.c", "scr_grapheme.c", "scr_array.c", "scr_bytes.c", "scr_bytes_io.c", "scr_map.c", "scr_closure.c", "scr_ffi.c", "scr_object.c", "scr_union.c", "scr_exception.c", "scr_error.c", "scr_console.c", "scr_lib.c", "scr_path.c", "scr_url.c", "scr_url_params.c", "scr_json.c", "scr_node_builtin.c", "scr_async.c", "scr_crypto_async.c", "scr_child.c", "scr_cycle.c"];
55
- /**
56
- * Per-target section-elimination recipe. This belongs beside the native
57
- * driver rather than a particular build path: one-shot compilation, cached
58
- * runtime objects, external object recipes, and runtime packs must all agree
59
- * on what their final linker is allowed to discard.
60
- *
61
- * Executable recipes use both halves. Archive and compile-only recipes never
62
- * use the link half, but `--lib` uses the compile half so its consumers retain
63
- * the choice to eliminate unused sections when they perform the final link.
64
- */
65
- export function executableSectionEliminationFlags(platform) {
66
- switch (platform) {
67
- case "darwin":
68
- // ld64's symbol subsections make this sufficient for ordinary C/LLVM
69
- // objects. Do not attach it only to --dynamic: static programs have the
70
- // same unreachable runtime sections.
71
- return { compile: [], link: ["-Wl,-dead_strip"] };
72
- case "linux":
73
- return {
74
- compile: ["-ffunction-sections", "-fdata-sections"],
75
- link: ["-Wl,--gc-sections"],
76
- };
77
- case "win32":
78
- // clang's MinGW driver forwards this to GNU-flavor ld/lld. A direct
79
- // local lld-link invocation instead uses /OPT:REF, but scriptc only
80
- // drives the compiler's GNU-flavor route here.
81
- return {
82
- compile: ["-ffunction-sections", "-fdata-sections"],
83
- link: ["-Wl,--gc-sections"],
84
- };
85
- // WASI has a distinct linker/runtime contract. Keep its existing object
86
- // layout until its linker invocation is validated separately.
87
- default:
88
- return { compile: [], link: [] };
89
- }
90
- }
91
- /** Inputs that can change which native tool/runtime implementation an
92
- * executable build selects before compileC has a chance to rediscover it.
93
- * The early whole-program cache keys this exact posture before restoring a
94
- * final binary; compileC retains its deeper inode/content validation. */
95
- export async function executableNativeEnvironmentFingerprint(env = process.env) {
96
- const configuredCompiler = env["SCRIPTC_CC"] ?? "";
97
- let compilerIdentity;
98
- try {
99
- compilerIdentity = await effectiveCompilerEnvironmentIdentity(resolveCc(env), env);
100
- }
101
- catch {
102
- // A failed trace cannot safely describe a reusable native posture. Keep
103
- // the build working, but make this invocation miss every persistent early
104
- // entry so compileC performs its full discovery and validation.
105
- compilerIdentity = `<unavailable:${configuredCompiler}:${randomUUID()}>`;
106
- }
107
- const hash = createHash("sha256")
108
- .update("executable-native-environment-v2\0")
109
- .update(toolchainEnvironmentFingerprint(env)).update("\0")
110
- // PATH text alone is not a resolution proof, and on Darwin /usr/bin/clang
111
- // is a stable shim whose selected Xcode compiler can change underneath it.
112
- // Re-resolve and trace the effective driver on every early lookup.
113
- .update(compilerIdentity).update("\0");
114
- for (const name of [
115
- "PATH",
116
- "SCRIPTC_FETCH_CURL",
117
- "SCRIPTC_TEST_RUNTIME_SRC_DIR",
118
- "SCRIPTC_TEST_VENDOR_CACHE_DIR",
119
- "SCRIPTC_TEST_TRUST_COMPILER_WRAPPER",
120
- ]) {
121
- const value = env[name];
122
- hash.update(name).update(value === undefined ? "\0unset\0" : "\0set\0").update(value ?? "").update("\0");
123
- }
124
- return hash.digest("hex");
125
- }
126
- /** Structured compiler-driver failure. Most callers still let this surface
127
- * as an internal build error; the TypeScript compiler pipeline recognizes it
128
- * when an outbound FFI profile is active and turns user-controlled native
129
- * link failures into SC5004. */
130
- export class CcCompileError extends Error {
131
- driver;
132
- stderr;
133
- constructor(driver, stderr, message) {
134
- super(message);
135
- this.driver = driver;
136
- this.stderr = stderr;
137
- this.name = "CcCompileError";
138
- }
139
- }
140
- /** Preserve the useful output from a failed compiler/tool invocation. Node's
141
- * execFile error exposes stderr and stdout independently, but either stream
142
- * may be present as an empty string. Prefer compiler diagnostics, retain a
143
- * non-standard stdout diagnostic when that is all the tool emitted, and only
144
- * then fall back to the process error itself. */
145
- export function subprocessFailureDetail(err) {
146
- const failure = err;
147
- const output = (value) => {
148
- const text = Buffer.isBuffer(value) ? value.toString("utf8") : value ?? "";
149
- return text.trim().length > 0 ? text.trimEnd() : "";
150
- };
151
- const stderr = output(failure.stderr);
152
- const stdout = output(failure.stdout);
153
- if (stderr !== "" && stdout !== "")
154
- return `${stderr}\n\ncompiler stdout:\n${stdout}`;
155
- if (stderr !== "")
156
- return stderr;
157
- if (stdout !== "")
158
- return `compiler stdout:\n${stdout}`;
159
- if (typeof failure.message === "string" && failure.message.trim() !== "") {
160
- return failure.message;
161
- }
162
- return String(err);
163
- }
164
- export function runtimeSrcDir() {
165
- const testRoot = process.env["SCRIPTC_TEST_RUNTIME_SRC_DIR"];
166
- if (testRoot !== undefined)
167
- return resolve(testRoot);
168
- const require = createRequire(import.meta.url);
169
- return join(dirname(require.resolve("@scriptc/runtime/package.json")), "src");
170
- }
171
- /** Whether the selected compiler driver is Zig. This is deliberately based on
172
- * the executable prefix rather than target presence: targetless Zig is still
173
- * a Zig build, while target presence is only the platform/target contract. */
174
- export function isZigDriver(driver) {
175
- return driver.argv[0] === "zig";
176
- }
177
- /* ── mobile targets (library mode) ─────────────────────────────────────────
178
- * Three mobile triples are admitted, and only for LIBRARY-MODE archive
179
- * builds — the consuming pattern is an embedding app linking the archive,
180
- * never a standalone executable (compile()/compileC refuse the executable
181
- * lane with the pointer to --lib):
182
- *
183
- * aarch64-apple-ios device archives; zig `aarch64-ios.15.0`
184
- * aarch64-apple-ios-simulator simulator archives; zig
185
- * `aarch64-ios.15.0-simulator`
186
- * aarch64-linux-android zig `aarch64-linux-android.26`
187
- *
188
- * The minimum-version floors are part of the target contract: iOS archives
189
- * build for iOS 15.0 (IPHONEOS_MIN_VERSION), Android archives for API level
190
- * 26 (ANDROID_MIN_API) — LC_BUILD_VERSION minos and the bionic stub level
191
- * both come from the pinned zig spelling above, so an embedder's deployment
192
- * target at or above the floor links cleanly.
193
- *
194
- * Zig bundles no Apple or bionic libc, so both families compile against an
195
- * explicit sysroot discovered here and spelled into targetArgs (where every
196
- * cache tier already keys it):
197
- *
198
- * iOS darwin hosts only — `xcrun --show-sdk-path` selects the
199
- * iPhoneOS/iPhoneSimulator SDK; compiles add `-isysroot <sdk>`
200
- * plus `-isystem <sdk>/usr/include` (zig's driver manages libc
201
- * header search itself and would otherwise find no headers).
202
- * Android any host with an NDK — ANDROID_NDK_ROOT/ANDROID_NDK_HOME, or
203
- * the newest ndk/<version> under ANDROID_HOME/ANDROID_SDK_ROOT
204
- * or the platform-default SDK location; compiles add the NDK
205
- * sysroot's generic and per-triple include directories.
206
- *
207
- * Library archives never link, so the sysroot's LIBRARIES are the
208
- * embedder's side of the contract: Xcode links iOS archives against the
209
- * selected SDK, and Gradle/NDK builds link Android archives against the
210
- * API-26+ bionic stubs. */
211
- /** The Apple SDK root for one mobile platform, discovered through xcrun the
212
- * way Xcode's own build system selects it. Memoized per SDK name and
213
- * selection environment: production rediscovers per process, and the two
214
- * selection variables (DEVELOPER_DIR/SDKROOT) are already mutable-input
215
- * keys that disable persistent caching. */
216
- const appleSdkMemos = new Map();
217
- function appleSdkRoot(sdk, env) {
218
- const key = [sdk, env["PATH"] ?? "", env["DEVELOPER_DIR"] ?? "", env["SDKROOT"] ?? ""].join("\0");
219
- const memo = appleSdkMemos.get(key);
220
- if (memo !== undefined)
221
- return memo;
222
- const probe = spawnSync("xcrun", ["--sdk", sdk, "--show-sdk-path"], {
223
- encoding: "utf8",
224
- env,
225
- });
226
- const path = probe.status === 0 ? (probe.stdout ?? "").trim() : "";
227
- if (path === "" || !existsSync(join(path, "usr", "include"))) {
228
- throw new Error(`the ${sdk} SDK was not found (xcrun --sdk ${sdk} --show-sdk-path failed) — ` +
229
- `iOS targets need Xcode with the ${sdk === "iphoneos" ? "iPhoneOS" : "iPhoneSimulator"} SDK installed`);
230
- }
231
- appleSdkMemos.set(key, path);
232
- return path;
233
- }
234
- /** Compare dotted-numeric NDK version directory names, newest first. */
235
- function compareNdkVersionsDesc(a, b) {
236
- const as = a.split(".").map((s) => Number.parseInt(s, 10));
237
- const bs = b.split(".").map((s) => Number.parseInt(s, 10));
238
- for (let i = 0; i < Math.max(as.length, bs.length); i++) {
239
- const d = (bs[i] ?? 0) - (as[i] ?? 0);
240
- if (d !== 0 && Number.isFinite(d))
241
- return d;
242
- }
243
- return a < b ? 1 : a > b ? -1 : 0;
244
- }
245
- /** The Android NDK sysroot for the selected environment: an explicit
246
- * ANDROID_NDK_ROOT/ANDROID_NDK_HOME wins; otherwise the newest ndk/<version>
247
- * under ANDROID_HOME, ANDROID_SDK_ROOT, or the platform-default SDK
248
- * location. The prebuilt host directory is discovered rather than guessed —
249
- * the NDK ships exactly one per host OS. Memoized per selection
250
- * environment. */
251
- const ndkSysrootMemos = new Map();
252
- function androidNdkSysroot(env) {
253
- const key = ["ANDROID_NDK_ROOT", "ANDROID_NDK_HOME", "ANDROID_HOME", "ANDROID_SDK_ROOT"]
254
- .map((name) => env[name] ?? "")
255
- .join("\0");
256
- const memo = ndkSysrootMemos.get(key);
257
- if (memo !== undefined)
258
- return memo;
259
- const ndkRoots = [];
260
- const explicit = [env["ANDROID_NDK_ROOT"], env["ANDROID_NDK_HOME"]]
261
- .find((root) => root !== undefined && root !== "");
262
- if (explicit !== undefined) {
263
- ndkRoots.push(explicit);
264
- }
265
- else {
266
- const sdkRoots = [
267
- env["ANDROID_HOME"],
268
- env["ANDROID_SDK_ROOT"],
269
- process.platform === "darwin"
270
- ? join(homedir(), "Library", "Android", "sdk")
271
- : process.platform === "win32"
272
- ? join(env["LOCALAPPDATA"] ?? join(homedir(), "AppData", "Local"), "Android", "Sdk")
273
- : join(homedir(), "Android", "Sdk"),
274
- ].filter((root) => root !== undefined && root !== "");
275
- for (const root of sdkRoots) {
276
- let versions = [];
277
- try {
278
- versions = readdirSync(join(root, "ndk")).filter((name) => /^\d/.test(name));
279
- }
280
- catch {
281
- continue;
282
- }
283
- versions.sort(compareNdkVersionsDesc);
284
- ndkRoots.push(...versions.map((version) => join(root, "ndk", version)));
285
- }
286
- }
287
- for (const ndk of ndkRoots) {
288
- const prebuilt = join(ndk, "toolchains", "llvm", "prebuilt");
289
- let hosts = [];
290
- try {
291
- hosts = readdirSync(prebuilt).sort();
292
- }
293
- catch {
294
- continue;
295
- }
296
- for (const host of hosts) {
297
- const sysroot = join(prebuilt, host, "sysroot");
298
- if (existsSync(join(sysroot, "usr", "include", "aarch64-linux-android"))) {
299
- ndkSysrootMemos.set(key, sysroot);
300
- return sysroot;
301
- }
302
- }
303
- }
304
- throw new Error("no Android NDK sysroot was found — install an NDK (sdkmanager 'ndk;<version>') and/or set " +
305
- "ANDROID_NDK_ROOT to it (ANDROID_HOME with an ndk/ directory also works). " +
306
- "aarch64-linux-android compiles against the NDK's bionic headers.");
307
- }
308
- /** Resolve native platform flags independently of the machine running tests,
309
- * so the host-Linux contract remains pinned on every development host. */
310
- function nativePlatformArgs(platform) {
311
- return platform === "linux"
312
- ? { targetArgs: ["-D_GNU_SOURCE"], linkArgs: ["-lm"] }
313
- : { targetArgs: [], linkArgs: [] };
314
- }
315
- export function resolveCc(env = process.env, hostPlatform = process.platform) {
316
- const cc = env["SCRIPTC_CC"] ?? "";
317
- const target = env["SCRIPTC_TARGET"] ?? "";
318
- const hostArgs = nativePlatformArgs(hostPlatform);
319
- if (cc === "" || cc === "clang") {
320
- if (target !== "") {
321
- throw new Error(`SCRIPTC_TARGET=${target} requires SCRIPTC_CC=zigcc — the default clang path has no cross-target sysroots.`);
322
- }
323
- return { argv: ["clang"], target: null, zigTarget: null, ...hostArgs };
324
- }
325
- if (cc !== "zigcc") {
326
- throw new Error(`unknown SCRIPTC_CC '${cc}' (supported: clang, zigcc)`);
327
- }
328
- if (target === "")
329
- return { argv: ["zig", "cc"], target: null, zigTarget: null, ...hostArgs };
330
- // Validate the target spelling before any SDK/sysroot discovery. Source
331
- // emission uses the same pure classifier without resolving this driver.
332
- configuredTargetPlatform(env, hostPlatform);
333
- const mobileRefusal = mobileTargetRefusal(target, hostPlatform);
334
- if (mobileRefusal !== null)
335
- throw new Error(mobileRefusal);
336
- if (isIosTarget(target)) {
337
- // Library-mode-only target (compile()/compileC own the executable-lane
338
- // refusal). Zig bundles no Apple libc: the compile rides the selected
339
- // SDK sysroot, with the libc header directory spelled explicitly
340
- // because zig's driver manages libc search itself and consults no
341
- // -isysroot for it. The zig spelling pins the iOS 15.0 floor into
342
- // every object's LC_BUILD_VERSION minos.
343
- const simulator = target === "aarch64-apple-ios-simulator";
344
- const sdk = appleSdkRoot(simulator ? "iphonesimulator" : "iphoneos", env);
345
- const zigTarget = `aarch64-ios.${IPHONEOS_MIN_VERSION}${simulator ? "-simulator" : ""}`;
346
- return {
347
- argv: ["zig", "cc"],
348
- target,
349
- zigTarget,
350
- targetArgs: ["-target", zigTarget, "-isysroot", sdk, "-isystem", join(sdk, "usr", "include")],
351
- linkArgs: [],
352
- };
353
- }
354
- if (isAndroidTarget(target)) {
355
- // Library-mode-only target. Zig bundles no bionic: compiles ride the
356
- // NDK sysroot's generic and per-triple include directories. Bionic
357
- // supports _GNU_SOURCE like glibc (and hides some POSIX declarations
358
- // without it); the zig spelling pins the API 26 floor, which the NDK's
359
- // versioned stub libraries enforce at the embedder's link. API 26
360
- // bionic carries everything the library-lane units call (arc4random_buf
361
- // included), so no shim TU joins the archive.
362
- const sysroot = androidNdkSysroot(env);
363
- const zigTarget = `aarch64-linux-android.${ANDROID_MIN_API}`;
364
- return {
365
- argv: ["zig", "cc"],
366
- target,
367
- zigTarget,
368
- targetArgs: [
369
- "-target",
370
- zigTarget,
371
- "-D_GNU_SOURCE",
372
- "-isystem",
373
- join(sysroot, "usr", "include"),
374
- "-isystem",
375
- join(sysroot, "usr", "include", "aarch64-linux-android"),
376
- ],
377
- linkArgs: ["-lm"],
378
- };
379
- }
380
- const linux = target.includes("linux");
381
- const wasi = target.includes("wasi");
382
- const musl = target.includes("linux-musl");
383
- return {
384
- argv: ["zig", "cc"],
385
- target,
386
- zigTarget: target,
387
- targetArgs: [
388
- "-target",
389
- target,
390
- ...(linux || wasi ? ["-D_GNU_SOURCE"] : []),
391
- ...(musl ? ["-DSCR_MUSL"] : []),
392
- ...(wasi ? ["-D_WASI_EMULATED_SIGNAL", "-D_WASI_EMULATED_PROCESS_CLOCKS"] : []),
393
- ],
394
- linkArgs: linux
395
- ? ["-lm"]
396
- : wasi
397
- ? ["-lwasi-emulated-signal", "-lwasi-emulated-process-clocks"]
398
- : [],
399
- };
400
- }
401
- /** Musl intentionally has no predefined libc macro. The explicit Zig target
402
- * is therefore the source of truth for selecting its small runtime shim. */
403
- function isMuslTarget(driver) {
404
- return driver.target?.includes("linux-musl") ?? false;
405
- }
406
- /** The OS the produced binary runs on: the triple's OS under SCRIPTC_TARGET,
407
- * the host's otherwise — so platform-conditional link flags follow the
408
- * TARGET, not the machine running the compiler. Exported for compile()/
409
- * analyze(): the FRONTEND consults it too (path.sep / os.EOL literals and
410
- * the path-module binding follow the target — a win32 triple compiles
411
- * Node-on-Windows semantics, path.win32 backing the bare module). */
412
- export function targetPlatform(driver) {
413
- if (driver.target === null)
414
- return process.platform;
415
- return configuredTargetPlatform({ SCRIPTC_TARGET: driver.target });
416
- }
417
- /** Architecture identity for host-native cache entries. Explicit cross targets
418
- * already name their complete target triple; native builds need the process
419
- * architecture too because one per-user cache can serve both native and
420
- * emulated processes (arm64 and Rosetta on macOS, for example). */
421
- export function cacheTargetIdentity(driver, hostPlatform = process.platform, hostArch = process.arch) {
422
- return driver.target === null ? `native:${hostPlatform}:${hostArch}` : `cross:${driver.target}`;
423
- }
424
- /* ── library mode: the static-archive artifact ────────────────────────────
425
- * One `scriptc build --lib` invocation produces <name>.lib.a: the program TU
426
- * object plus exactly the runtime objects the program's IR gates in, every
427
- * TU compiled with -DSCR_LIB (the per-flavor discipline that keeps library
428
- * objects apart from executable-lane objects). Persistent builds cache the
429
- * completed archive by program-TU content and cache runtime objects separately,
430
- * so an edit recompiles only the changed program object before re-archiving.
431
- * Large LLVM dev TUs split further into stable symbol-hash shards: compile
432
- * those in parallel, cache each object independently, then relocatably merge
433
- * them back into the archive's one canonical program member. A localized edit
434
- * recompiles only the changed buckets; exact repeats use the merged-object or
435
- * completed-archive tiers and never repeat the merge.
436
- * The base set narrows from the executable lane's unconditional sources:
437
- * scr_async.c (fibers, timers, the loop) and scr_child.c drop — the
438
- * async_free refusal already guarantees nothing references them — and
439
- * scr_library.c (sink, arena, reset registry, library funnel) joins. The gated
440
- * units a library may reach are the pure-data ones (regex + the vendored matcher, assert,
441
- * inspect, symbol, searchParams, emitter+dyn_handle, zlib); every
442
- * loop-hooked or ambient unit was refused at SC4005 before emission.
443
- * External-symbol contract: undefined references only to the target's C/math
444
- * runtime and system APIs. Windows embedders additionally link advapi32,
445
- * iphlpapi, and ws2_32; the platform driver supplies its ordinary CRT and
446
- * kernel imports. Zlib rides the VENDORED per-flavor objects here even on
447
- * hosts because the executable lane's system `-lz` cannot ride inside an
448
- * archive. */
449
- /** The library base: the executable lane's unconditional sources minus the
450
- * fiber/loop and child-process units, plus the library-mode TU. */
451
- const LIB_RUNTIME_SOURCES = [
452
- ...EXECUTABLE_RUNTIME_SOURCES.filter((f) => f !== "scr_async.c" && f !== "scr_crypto_async.c" && f !== "scr_child.c" && f !== "scr_ffi.c"),
453
- "scr_library.c",
454
- ];
455
- function updateProgramShardCacheIdentity(hash, shards, publicSymbols, mergeIdentity) {
456
- hash.update("\0program-shards\0");
457
- if (shards === undefined) {
458
- hash.update("<none>\0");
459
- }
460
- else {
461
- hash.update("<present>\0");
462
- for (const shard of shards) {
463
- hash.update(shard.name).update("\0").update(shard.source).update("\0");
464
- }
465
- }
466
- hash.update("\0program-public-symbols\0");
467
- if (publicSymbols === undefined) {
468
- hash.update("<none>\0");
469
- }
470
- else {
471
- hash.update("<present>\0");
472
- for (const symbol of publicSymbols)
473
- hash.update(symbol).update("\0");
474
- }
475
- hash.update("\0program-shard-merge\0");
476
- hash.update(mergeIdentity === undefined ? "<none>\0" : `<present>\0${mergeIdentity}\0`);
477
- }
478
- /** Identity of the machinery that turns LLVM shard objects back into the
479
- * canonical program member, or null when the target cannot do so. Sharding is
480
- * only a build optimization: a missing host tool or unsupported object class
481
- * retains the ordinary single-TU compile. The identity joins every cache tier
482
- * that contains merged bytes; raw shard-object keys deliberately omit it. */
483
- async function resolveProgramShardMergeIdentity(driver) {
484
- const platform = targetPlatform(driver);
485
- // Mach-O merging uses the host's ld64. A Darwin target produced from a
486
- // non-Darwin host can still compile as one canonical Zig TU, but the host's
487
- // ELF/COFF linker cannot combine those objects.
488
- if (platform === "darwin") {
489
- if (process.platform !== "darwin")
490
- return null;
491
- const ld = await resolvedTool("ld");
492
- return ld === null
493
- ? null
494
- : rememberFingerprintDependencies(`program-shard-merge-darwin-v1\0${ld.cacheIdentity}`, [ld.canonicalPath]);
495
- }
496
- if (platform === "linux") {
497
- if (driver.target === null) {
498
- const [ld, objcopy] = await Promise.all([
499
- resolvedTool("ld"),
500
- resolvedTool("objcopy"),
501
- ]);
502
- return ld === null || objcopy === null
503
- ? null
504
- : rememberFingerprintDependencies(`program-shard-merge-linux-v1\0${ld.cacheIdentity}\0${objcopy.cacheIdentity}`, [ld.canonicalPath, objcopy.canonicalPath]);
505
- }
506
- const arch = driver.target.split("-", 1)[0];
507
- if (arch !== "x86_64" && arch !== "aarch64")
508
- return null;
509
- const compiler = await resolvedTool(driver.argv[0] ?? "zig");
510
- return compiler === null
511
- ? null
512
- : rememberFingerprintDependencies(`program-shard-merge-cross-elf-v1\0${arch}\0${compiler.cacheIdentity}`, [compiler.canonicalPath]);
513
- }
514
- if (platform === "win32") {
515
- const arch = driver.target?.split("-", 1)[0] ?? process.arch;
516
- return arch === "x86_64" || arch === "x64"
517
- ? `program-shard-merge-coff-v1\0${arch}`
518
- : null;
519
- }
520
- return null;
521
- }
522
- export async function compileLibArchive(opts) {
523
- clearCcCaches();
524
- const rtDir = runtimeSrcDir();
525
- const driver = resolveCc();
526
- const shardNames = new Set();
527
- const programShardsValid = opts.programShards?.every((shard) => {
528
- if (basename(shard.name) !== shard.name || !shard.name.endsWith(".ll") ||
529
- shardNames.has(shard.name))
530
- return false;
531
- shardNames.add(shard.name);
532
- return true;
533
- }) === true;
534
- const programShardsRequested = opts.cPath.endsWith(".ll") &&
535
- programShardsValid && opts.programShards !== undefined && opts.programShards.length > 1 &&
536
- opts.programPublicSymbols !== undefined
537
- ? opts.programShards
538
- : null;
539
- const programShardMergeIdentity = programShardsRequested === null
540
- ? null
541
- : await resolveProgramShardMergeIdentity(driver);
542
- const programShards = programShardMergeIdentity === null ? null : programShardsRequested;
543
- const programPublicSymbols = programShards === null ? undefined : opts.programPublicSymbols;
544
- const sanitize = opts.sanitize ?? false;
545
- const optimization = opts.optimization ?? "release";
546
- const regex = opts.regex ?? false;
547
- const sources = [
548
- ...LIB_RUNTIME_SOURCES,
549
- // win32 targets compile the libc-shim TU into the archive (stpcpy,
550
- // arc4random_buf — scr_number.c/scr_lib.c/scr_bytes_io.c call them and
551
- // mingw's CRT has neither), exactly like compileC's unconditional win32
552
- // arm. The system-DLL imports the shim and scr_lib.c reference
553
- // (advapi32's CSPRNG/GetUserNameA, iphlpapi's GetAdaptersAddresses,
554
- // ws2_32's inet_ntop/htonl) stay the EMBEDDER's link line — an archive
555
- // carries no -l flags. Never present off win32, so host archives
556
- // cannot change by a byte.
557
- ...(targetPlatform(driver) === "win32" ? ["scr_win.c"] : []),
558
- // Zig's musl sysroot does not provide arc4random_buf. Keep the fallback
559
- // inside the archive so library embedders need no extra system library.
560
- ...(isMuslTarget(driver) ? ["scr_musl.c"] : []),
561
- ...(regex ? ["scr_regex.c"] : []),
562
- ...(opts.assert || regex || opts.symbol ? ["scr_assert.c"] : []),
563
- ...(opts.inspect ? ["scr_inspect.c", "scr_console_native.c"] : []),
564
- ...(opts.symbol ? ["scr_symbol.c"] : []),
565
- ...(opts.assert && opts.bigint ? ["scr_bigint_assert.c"] : []),
566
- ...(opts.emitter ? ["scr_events_emitter.c", "scr_dyn_handle.c"] : []),
567
- ...(opts.dynInvoke ? ["scr_dyn_invoke.c"] : []),
568
- ...(opts.zlib ? ["scr_zlib.c"] : []),
569
- ...(opts.copying ? ["scr_copying.c"] : []),
570
- ];
571
- const cflags = [
572
- "-std=c11",
573
- ...driver.targetArgs,
574
- ...(sanitize
575
- ? ["-O1", "-fsanitize=address", "-DSCR_RC_AUDIT"]
576
- : [optimization === "dev" ? "-O0" : "-O2"]),
577
- ...executableSectionEliminationFlags(targetPlatform(driver)).compile,
578
- "-fno-math-errno",
579
- "-fno-strict-aliasing", // the emitted object model type-puns — see compileC's buildArgs
580
- "-Wno-deprecated-declarations",
581
- "-DSCR_LIB",
582
- ...(opts.threadInstances ? ["-DSCR_THREAD_INSTANCES"] : []),
583
- ...(opts.textDecoderLegacy ? ["-DSCR_TEXT_DECODER_LEGACY"] : []),
584
- "-I", rtDir,
585
- ...(regex ? ["-I", vendorEngineDir()] : []),
586
- ...(opts.zlib ? ["-I", vendorZlibDir()] : []),
587
- ];
588
- const programCompilerArgs = opts.cPath.endsWith(".ll")
589
- ? [...cflags, "-Wno-override-module"]
590
- : cflags;
591
- const programSourceExtension = opts.cPath.endsWith(".ll") ? ".ll" : ".c";
592
- const arArgv = isZigDriver(driver) ? [driver.argv[0], "ar"] : ["ar"];
593
- const cachePolicy = toolchainEnvironmentCachePolicy();
594
- const configuredCacheRoot = cacheRootDir();
595
- const toolchainEnv = toolchainEnvironmentFingerprint();
596
- const persistentDriverCache = cachePolicy.runtimeObjects &&
597
- configuredCacheRoot !== null &&
598
- await compilerDriverSupportsPersistentCache(driver, toolchainEnv);
599
- // A library archive is compile-only from clang's perspective. Link-only
600
- // search variables cannot affect it, but any mutable compilation input or
601
- // opaque compiler wrapper makes every persistent tier unsafe to reuse. An
602
- // opaque archiver narrows only the completed-archive tier below.
603
- const cacheIdentity = opts.cacheIdentity;
604
- let persistentCache = cacheIdentity === undefined || configuredCacheRoot === null || !persistentDriverCache
605
- ? null
606
- : { root: configuredCacheRoot, identity: cacheIdentity };
607
- if (persistentCache !== null) {
608
- try {
609
- await ensurePrivateCacheRoot(persistentCache.root, process.env["SCRIPTC_CACHE_DIR"] === undefined);
610
- }
611
- catch {
612
- persistentCache = null;
613
- }
614
- }
615
- let implicitToolchain = null;
616
- let implicitCompileToolchain = null;
617
- let runtimeCompilerInvocation = null;
618
- let programCompilerInvocation = null;
619
- if (persistentDriverCache) {
620
- try {
621
- const fingerprints = await implicitToolchainFingerprints(driver, toolchainEnv);
622
- implicitToolchain = fingerprints.complete;
623
- implicitCompileToolchain = fingerprints.compile;
624
- }
625
- catch {
626
- // An identity probe is cache machinery, never a reason a valid native
627
- // compile should fail. Disable every persistent tier for this invocation.
628
- persistentCache = null;
629
- }
630
- }
631
- if (persistentCache !== null) {
632
- try {
633
- runtimeCompilerInvocation = await effectiveCompilerInvocationFingerprint(driver, toolchainEnv, cflags);
634
- programCompilerInvocation = programSourceExtension === ".ll"
635
- ? await effectiveCompilerInvocationFingerprint(driver, toolchainEnv, programCompilerArgs, programSourceExtension)
636
- : runtimeCompilerInvocation;
637
- }
638
- catch {
639
- // A wrapper that cannot expose its effective invocation can still build,
640
- // but its outputs cannot safely participate in a persistent cache.
641
- persistentCache = null;
642
- }
643
- }
644
- const vendorBuildIdentity = await currentVendorCacheBuildIdentity(driver, `${toolchainEnv}\0${implicitToolchain ?? "<uncached>"}`);
645
- // Runtime-localized archives skip the completed-archive tier: their bytes
646
- // additionally depend on the localization toolchain's identity (host ld/
647
- // objcopy or the cross driver's lld), which the archive key does not
648
- // fingerprint. The runtime-object tier still serves them (localization
649
- // consumes the same per-flavor objects).
650
- const cacheCompleteArchive = opts.localizeSymbols === undefined &&
651
- persistentCache !== null && await archiverSupportsPersistentCache(arArgv, driver);
652
- let cachedArchive = null;
653
- let compilerVersion = "";
654
- let archiverVersion = "";
655
- let runtimeHash = "";
656
- let programDependencyHash = "";
657
- let cachedProgramBytes = opts.programSource === undefined
658
- ? null
659
- : Buffer.from(opts.programSource, "utf8");
660
- const identityBytes = opts.identityLlvmSource === undefined
661
- ? null
662
- : Buffer.from(opts.identityLlvmSource, "utf8");
663
- if (persistentCache !== null) {
664
- try {
665
- const [cv, fingerprint, programBytes] = await Promise.all([
666
- ccVersion(driver.argv, toolchainEnv, true),
667
- runtimeFingerprint(rtDir),
668
- cachedProgramBytes === null ? readFile(opts.cPath) : Promise.resolve(cachedProgramBytes),
669
- ]);
670
- compilerVersion = cv;
671
- runtimeHash = fingerprint;
672
- cachedProgramBytes = programBytes;
673
- programDependencyHash = await translationUnitDependencyFingerprint(driver, cflags, opts.cPath, programBytes, toolchainEnv);
674
- if (cacheCompleteArchive) {
675
- const av = await toolVersionOnce(arArgv, toolchainEnv, true);
676
- archiverVersion = av;
677
- const key = createHash("sha256")
678
- // v10 adds the shard-merge implementation/tool identity. The
679
- // canonical TU still keys source semantics; shard, keep, and merge
680
- // bytes key the exact merged program object so ABI projections,
681
- // tool replacements, and single-/multi-TU producers never collide.
682
- .update("lib-v10\0")
683
- .update(cacheTargetIdentity(driver)).update("\0")
684
- .update(toolchainEnv).update("\0")
685
- .update(implicitToolchain).update("\0")
686
- .update(runtimeCompilerInvocation).update("\0")
687
- .update(programCompilerInvocation).update("\0")
688
- .update(programDependencyHash).update("\0")
689
- .update(persistentCache.identity).update("\0")
690
- .update(driver.argv.join("\x1f")).update("\0")
691
- .update(cv).update("\0")
692
- .update(fingerprint).update("\0")
693
- .update(arArgv.join("\x1f")).update("\0")
694
- .update(av).update("\0")
695
- .update(cflags.join("\x1f")).update("\0")
696
- .update(sources.join("\x1f")).update("\0")
697
- // The compiler-visible spelling and resolved location are both inputs:
698
- // __FILE__ observes the former, while relative includes follow the
699
- // latter. Archive members also inherit the TU's basename.
700
- .update(opts.cPath).update("\0")
701
- .update(resolve(opts.cPath)).update("\0")
702
- .update(programBytes);
703
- updateProgramShardCacheIdentity(key, programShards ?? undefined, programPublicSymbols, programShardMergeIdentity ?? undefined);
704
- const keyHex = key
705
- .update("\0identity\0")
706
- .update(identityBytes === null ? "<none>" : "<generated>").update("\0")
707
- .update(identityBytes ?? Buffer.alloc(0))
708
- .digest("hex");
709
- cachedArchive = join(persistentCache.root, "lib", keyHex);
710
- const tmpOut = privateSiblingPath(opts.outPath, "lib-hit");
711
- try {
712
- await mkdir(dirname(opts.outPath), { recursive: true });
713
- if (!(await copyValidCachedFile(cachedArchive, tmpOut))) {
714
- throw new Error("invalid cached library archive");
715
- }
716
- // Match a fresh `ar` output under the caller's current umask. Cache
717
- // entries may have been populated by a less restrictive shell.
718
- await chmod(tmpOut, 0o666 & ~process.umask());
719
- await rename(tmpOut, opts.outPath);
720
- return;
721
- }
722
- catch {
723
- await rm(tmpOut, { force: true }).catch(() => undefined);
724
- // Miss (or unreadable cache): compile below and publish best-effort.
725
- }
726
- }
727
- }
728
- catch {
729
- // Cache identity trouble is never a build failure. The fresh path below
730
- // retains the historical compile-everything behavior.
731
- cachedArchive = null;
732
- }
733
- }
734
- const transientVendorRoot = persistentCache !== null && implicitToolchain !== null
735
- ? null
736
- : join(tmpdir(), `scriptc-lib-vendor-${process.pid}-${Math.random().toString(36).slice(2)}`);
737
- const vendorCacheRoot = transientVendorRoot ?? vendorBuildCacheRoot(persistentCache?.root);
738
- try {
739
- const buildDir = await mkdtemp(join(tmpdir(), "scriptc-lib-"));
740
- try {
741
- const lreObjects = regex
742
- ? await stageVendorInputs(() => ensureLreObjects(sanitize, driver, vendorBuildIdentity, vendorCacheRoot), join(buildDir, "vendor-lre"))
743
- : [];
744
- const zlibObjects = opts.zlib
745
- ? await stageVendorInputs(() => ensureZlibObjects(sanitize, driver, vendorBuildIdentity, vendorCacheRoot), join(buildDir, "vendor-zlib"))
746
- : [];
747
- const compileOne = async (src, objName, compilerVisibleSource) => {
748
- const obj = join(buildDir, objName);
749
- const args = [
750
- ...driver.argv.slice(1),
751
- ...cflags,
752
- ...(compilerVisibleSource !== undefined
753
- ? [
754
- `-ffile-prefix-map=${src}=${compilerVisibleSource}`,
755
- "-iquote",
756
- dirname(resolve(compilerVisibleSource)),
757
- ]
758
- : []),
759
- ...(src.endsWith(".ll") ? ["-Wno-override-module"] : []),
760
- "-c", src,
761
- "-o", obj,
762
- ];
763
- try {
764
- await execFileAsync(driver.argv[0] ?? "clang", args);
765
- }
766
- catch (err) {
767
- const stderr = subprocessFailureDetail(err);
768
- throw new Error(`${driver.argv.join(" ")} failed compiling ${src} for the library archive.\n` +
769
- `This is a scriptc bug (generated/runtime C should always compile) unless the compiler itself is missing/broken.\n\n${stderr}`);
770
- }
771
- return obj;
772
- };
773
- const stem = basename(opts.cPath).replace(/\.(c|ll)$/, "");
774
- const programSource = cachedProgramBytes === null
775
- ? opts.cPath
776
- : join(buildDir, `program${opts.cPath.endsWith(".ll") ? ".ll" : ".c"}`);
777
- if (cachedProgramBytes !== null && programShards === null) {
778
- await writeFile(programSource, cachedProgramBytes);
779
- }
780
- let cachedProgramObject = null;
781
- if (persistentCache !== null && cachedProgramBytes !== null && compilerVersion !== "" &&
782
- implicitToolchain !== null && programCompilerInvocation !== null) {
783
- const programKey = createHash("sha256")
784
- .update("lib-program-obj-v3\0")
785
- .update(cacheTargetIdentity(driver)).update("\0")
786
- .update(toolchainEnv).update("\0")
787
- .update(implicitToolchain).update("\0")
788
- .update(programCompilerInvocation).update("\0")
789
- .update(persistentCache.identity).update("\0")
790
- .update(driver.argv.join("\x1f")).update("\0")
791
- .update(compilerVersion).update("\0")
792
- .update(runtimeHash).update("\0")
793
- .update(programDependencyHash).update("\0")
794
- .update(programCompilerArgs.join("\x1f")).update("\0")
795
- .update(opts.cPath).update("\0")
796
- .update(resolve(opts.cPath)).update("\0")
797
- .update(cachedProgramBytes);
798
- updateProgramShardCacheIdentity(programKey, programShards ?? undefined, programPublicSymbols, programShardMergeIdentity ?? undefined);
799
- const programKeyHex = programKey.digest("hex");
800
- cachedProgramObject = join(persistentCache.root, "program-obj", programKeyHex);
801
- }
802
- const stagedProgramObject = join(buildDir, `${stem}.program.o`);
803
- let programObject;
804
- let programShardFallback = false;
805
- if (cachedProgramObject !== null &&
806
- await copyValidCachedFile(cachedProgramObject, stagedProgramObject)) {
807
- programObject = stagedProgramObject;
808
- }
809
- else if (programShards !== null) {
810
- try {
811
- const shardEntries = programShards.map((shard, index) => {
812
- const sourcePath = join(buildDir, shard.name);
813
- const staged = join(buildDir, `${stem}.program-${index.toString().padStart(3, "0")}.o`);
814
- let cachePath = null;
815
- if (persistentCache !== null && compilerVersion !== "" &&
816
- implicitCompileToolchain !== null && programCompilerInvocation !== null) {
817
- const key = createHash("sha256")
818
- // v2 removes the broad implicit-toolchain fingerprint: it
819
- // includes the linker selected by the driver, but raw shard
820
- // objects are compile-only outputs. The compile-only toolchain
821
- // identity retains compiler/config/header/assembler inputs;
822
- // the effective program invocation pins this exact flag lane.
823
- // Merge-tool identity belongs only to the merged-object and
824
- // completed-archive tiers.
825
- .update("lib-program-shard-v2\0")
826
- .update(cacheTargetIdentity(driver)).update("\0")
827
- .update(toolchainEnv).update("\0")
828
- .update(implicitCompileToolchain).update("\0")
829
- .update(programCompilerInvocation).update("\0")
830
- .update(persistentCache.identity).update("\0")
831
- .update(driver.argv.join("\x1f")).update("\0")
832
- .update(compilerVersion).update("\0")
833
- .update(runtimeHash).update("\0")
834
- .update(programDependencyHash).update("\0")
835
- .update(programCompilerArgs.join("\x1f")).update("\0")
836
- .update(opts.cPath).update("\0")
837
- .update(resolve(opts.cPath)).update("\0")
838
- .update(shard.name).update("\0")
839
- .update(shard.source)
840
- .digest("hex");
841
- cachePath = join(persistentCache.root, "program-shard", key);
842
- }
843
- return { ...shard, sourcePath, staged, cachePath, missed: false };
844
- });
845
- const shardWidth = Math.min(8, availableParallelism());
846
- for (let i = 0; i < shardEntries.length; i += shardWidth) {
847
- await Promise.all(shardEntries.slice(i, i + shardWidth).map(async (entry) => {
848
- await writeFile(entry.sourcePath, entry.source);
849
- if (entry.cachePath !== null &&
850
- await copyValidCachedFile(entry.cachePath, entry.staged))
851
- return;
852
- entry.missed = true;
853
- await compileOne(entry.sourcePath, basename(entry.staged), opts.cPath);
854
- }));
855
- }
856
- const publishable = shardEntries.filter((entry) => entry.missed && entry.cachePath !== null);
857
- const mergedProgramObject = await localizeLibraryObjects(driver, arArgv, buildDir, shardEntries.map((entry) => entry.staged), [], programPublicSymbols, `${stem}.program`);
858
- // Keep the canonical archive member spelling. The fact that native
859
- // compilation used shards is an implementation detail; consumers and
860
- // deterministic cache tests continue to see `<stem>.program.o`.
861
- await rename(mergedProgramObject, stagedProgramObject);
862
- programObject = stagedProgramObject;
863
- if (cachedProgramObject !== null || publishable.length > 0) {
864
- try {
865
- const [currentRuntime, currentInvocation, currentDependencies, currentCompiler] = await Promise.all([
866
- runtimeFingerprint(rtDir),
867
- effectiveCompilerInvocationFingerprint(driver, toolchainEnv, programCompilerArgs, programSourceExtension),
868
- translationUnitDependencyFingerprint(driver, cflags, opts.cPath, cachedProgramBytes, toolchainEnv),
869
- ccVersion(driver.argv, toolchainEnv, true),
870
- ]);
871
- const shardInputsStillMatch = currentRuntime === runtimeHash &&
872
- currentInvocation === programCompilerInvocation &&
873
- currentDependencies === programDependencyHash && currentCompiler === compilerVersion;
874
- const currentFingerprints = shardInputsStillMatch
875
- ? await implicitToolchainFingerprints(driver, toolchainEnv)
876
- : null;
877
- const compileInputsStillMatch = shardInputsStillMatch &&
878
- currentFingerprints?.compile === implicitCompileToolchain;
879
- let mergedInputsStillMatch = false;
880
- if (compileInputsStillMatch && cachedProgramObject !== null) {
881
- const currentMerge = await resolveProgramShardMergeIdentity(driver).catch(() => null);
882
- mergedInputsStillMatch =
883
- currentFingerprints?.complete === implicitToolchain &&
884
- currentMerge === programShardMergeIdentity;
885
- }
886
- if (compileInputsStillMatch) {
887
- await Promise.all([
888
- ...(mergedInputsStillMatch
889
- ? [publishCachedFile(programObject, cachedProgramObject)]
890
- : []),
891
- ...publishable.map((entry) => publishCachedFile(entry.staged, entry.cachePath)),
892
- ]);
893
- }
894
- }
895
- catch {
896
- // Best-effort: the merged program object is already valid.
897
- }
898
- }
899
- }
900
- catch {
901
- // Sharding is only an optimization. A present but incompatible or
902
- // failing merge tool (or a shard-only compiler failure) must not
903
- // turn a valid canonical LLVM TU into a failed library build. Do not
904
- // publish this retry under shard-derived object/archive cache keys.
905
- programShardFallback = true;
906
- if (cachedProgramBytes !== null)
907
- await writeFile(programSource, cachedProgramBytes);
908
- programObject = await compileOne(programSource, `${stem}.program.o`, cachedProgramBytes === null ? undefined : opts.cPath);
909
- }
910
- }
911
- else {
912
- programObject = await compileOne(programSource, `${stem}.program.o`, cachedProgramBytes === null ? undefined : opts.cPath);
913
- if (cachedProgramObject !== null) {
914
- try {
915
- const [currentRuntime, currentImplicit, currentInvocation, currentDependencies, currentCompiler] = await Promise.all([
916
- runtimeFingerprint(rtDir),
917
- implicitToolchainFingerprint(driver, toolchainEnv),
918
- effectiveCompilerInvocationFingerprint(driver, toolchainEnv, programCompilerArgs, programSourceExtension),
919
- translationUnitDependencyFingerprint(driver, cflags, opts.cPath, cachedProgramBytes, toolchainEnv),
920
- ccVersion(driver.argv, toolchainEnv, true),
921
- ]);
922
- if (currentRuntime === runtimeHash &&
923
- currentImplicit === implicitToolchain &&
924
- currentInvocation === programCompilerInvocation &&
925
- currentDependencies === programDependencyHash &&
926
- currentCompiler === compilerVersion) {
927
- await publishCachedFile(programObject, cachedProgramObject);
928
- }
929
- }
930
- catch {
931
- // Best-effort: the archive build already owns a valid object.
932
- }
933
- }
934
- }
935
- const identityObject = identityBytes === null
936
- ? null
937
- : await (async () => {
938
- const source = join(buildDir, "identity.ll");
939
- await writeFile(source, identityBytes);
940
- return compileOne(source, `${stem}.identity.o`);
941
- })();
942
- let runtimeObjects = null;
943
- let cacheInputsStable = true;
944
- let objectImplicitVerification = null;
945
- const objectImplicitToolchainStillMatches = () => {
946
- objectImplicitVerification ??= Promise.all([
947
- implicitToolchainFingerprint(driver, toolchainEnv),
948
- effectiveCompilerInvocationFingerprint(driver, toolchainEnv, cflags),
949
- ]).then(([currentImplicit, currentInvocation]) => currentImplicit === implicitToolchain &&
950
- currentInvocation === runtimeCompilerInvocation, () => false);
951
- return objectImplicitVerification;
952
- };
953
- if (persistentCache !== null && compilerVersion !== "" && runtimeHash !== "") {
954
- try {
955
- const sourcePaths = sources.map((f) => join(rtDir, f));
956
- const cached = await ensureRuntimeObjects(persistentCache.root, driver.argv, cflags, sourcePaths, `lib-obj-v5\0${cacheTargetIdentity(driver)}\0${toolchainEnv}\0${implicitToolchain}\0${runtimeCompilerInvocation}\0${driver.argv.join(" ")}\0${compilerVersion}\0${runtimeHash}\0`, async () => (await runtimeFingerprint(rtDir)) === runtimeHash &&
957
- (await objectImplicitToolchainStillMatches()));
958
- const staged = await stageRuntimeObjects(cached, join(buildDir, "cached-runtime"));
959
- runtimeObjects = sourcePaths.map((path) => staged.get(path));
960
- }
961
- catch (err) {
962
- if (err instanceof CacheInputsChangedError)
963
- cacheInputsStable = false;
964
- runtimeObjects = null;
965
- }
966
- }
967
- if (runtimeObjects === null) {
968
- runtimeObjects = [];
969
- const width = Math.min(4, availableParallelism());
970
- for (let i = 0; i < sources.length; i += width) {
971
- runtimeObjects.push(...(await Promise.all(sources.slice(i, i + width).map((f) => compileOne(join(rtDir, f), f.replace(/\.c$/, ".o"))))));
972
- }
973
- }
974
- const objects = [programObject, ...(identityObject === null ? [] : [identityObject]), ...runtimeObjects, ...lreObjects, ...zlibObjects];
975
- // Multi-instance library mode: the archive's one member becomes the
976
- // combined, symbol-localized object (cached vendor/runtime objects
977
- // are read-only inputs here — the combine step never mutates them).
978
- const archiveMembers = opts.localizeSymbols === undefined
979
- ? objects
980
- : [
981
- await localizeLibraryObjects(driver, arArgv, buildDir, [programObject, ...(identityObject === null ? [] : [identityObject])], [...runtimeObjects, ...lreObjects, ...zlibObjects], opts.localizeSymbols, stem),
982
- ];
983
- // A cacheable or runtime-localized build owns a private archive from
984
- // `ar` through publication. Localized archives deliberately bypass the
985
- // completed-artifact cache, but still need atomic installation so two
986
- // invocations sharing a caller-visible output cannot race `rm`/`ar` on
987
- // that path.
988
- const archiveOutput = cachedArchive === null && opts.localizeSymbols === undefined
989
- ? opts.outPath
990
- : join(buildDir, "artifact.lib.a");
991
- await rm(archiveOutput, { force: true }); // `ar r` would append into a stale archive
992
- await mkdir(dirname(archiveOutput), { recursive: true });
993
- await execFileAsync(arArgv[0] ?? "ar", [
994
- ...arArgv.slice(1),
995
- "rcs",
996
- archiveOutput,
997
- ...archiveMembers,
998
- ]);
999
- if (archiveOutput !== opts.outPath)
1000
- await installArtifact(archiveOutput, opts.outPath);
1001
- let runtimeStillMatchesKey = false;
1002
- if (cachedArchive !== null &&
1003
- persistentCache !== null &&
1004
- runtimeHash !== "" &&
1005
- programDependencyHash !== "" &&
1006
- compilerVersion !== "" &&
1007
- archiverVersion !== "") {
1008
- const [currentRuntime, currentImplicit, currentRuntimeInvocation, currentProgramInvocation, currentProgramDependencies, currentCompiler, currentArchiver, currentProgramShardMerge] = await Promise.all([
1009
- runtimeFingerprint(rtDir).catch(() => null),
1010
- implicitToolchainFingerprint(driver, toolchainEnv).catch(() => null),
1011
- effectiveCompilerInvocationFingerprint(driver, toolchainEnv, cflags).catch(() => null),
1012
- effectiveCompilerInvocationFingerprint(driver, toolchainEnv, programCompilerArgs, programSourceExtension).catch(() => null),
1013
- translationUnitDependencyFingerprint(driver, cflags, opts.cPath, cachedProgramBytes, toolchainEnv).catch(() => null),
1014
- ccVersion(driver.argv, toolchainEnv, true).catch(() => null),
1015
- toolVersionOnce(arArgv, toolchainEnv, true).catch(() => null),
1016
- programShards === null
1017
- ? Promise.resolve(null)
1018
- : resolveProgramShardMergeIdentity(driver).catch(() => null),
1019
- ]);
1020
- runtimeStillMatchesKey =
1021
- cacheInputsStable &&
1022
- !programShardFallback &&
1023
- currentRuntime === runtimeHash &&
1024
- currentImplicit === implicitToolchain &&
1025
- currentRuntimeInvocation === runtimeCompilerInvocation &&
1026
- currentProgramInvocation === programCompilerInvocation &&
1027
- currentProgramDependencies === programDependencyHash &&
1028
- currentCompiler === compilerVersion &&
1029
- currentArchiver === archiverVersion &&
1030
- currentProgramShardMerge === programShardMergeIdentity;
1031
- }
1032
- if (cachedArchive !== null && persistentCache !== null && runtimeStillMatchesKey) {
1033
- try {
1034
- await publishCachedFile(archiveOutput, cachedArchive);
1035
- }
1036
- catch {
1037
- // Publishing is best-effort; the requested archive is already valid.
1038
- }
1039
- }
1040
- }
1041
- finally {
1042
- await rm(buildDir, { recursive: true, force: true });
1043
- }
1044
- }
1045
- finally {
1046
- if (transientVendorRoot !== null) {
1047
- await rm(transientVendorRoot, { recursive: true, force: true }).catch(() => undefined);
1048
- }
1049
- }
1050
- if (persistentCache !== null) {
1051
- await pruneCache(persistentCache.root).catch(() => undefined);
1052
- }
1053
- }
1054
- /* Multi-instance library mode's localization step: combine the program
1055
- * object with exactly the runtime/vendor members it reaches into ONE
1056
- * relocatable object, then demote every scriptc external definition except
1057
- * the profile-declared symbols to a local symbol. The internals are not
1058
- * renamed apart — they stop being visible to the embedder's linker at all,
1059
- * so a second archive built under a different prefix brings its own private
1060
- * copy of the whole runtime (allocator, collector, arena, panic sink) into
1061
- * the same process. Undefined references (the target C/math runtime and
1062
- * system APIs, plus sanitizer ABI in instrumented builds) keep their global
1063
- * binding: those platform services and the sanitizer are the embedder's,
1064
- * shared by design. Windows embedders additionally link advapi32, iphlpapi,
1065
- * and ws2_32.
1066
- *
1067
- * The generated program and optional identity objects are mandatory roots;
1068
- * support-member selection still matters. A classic archive's unused members (and their
1069
- * undefined references to units library mode excludes, like the
1070
- * fs-promises unit's fiber symbols) never reach an embedder's link. A
1071
- * blind merge of every object would carry those references into the one
1072
- * combined member. Staging the support objects into an intermediate
1073
- * archive keeps the linker's own member semantics: `ld -r` pulls only the
1074
- * members the program object transitively needs (the COFF arm implements
1075
- * the same member semantics in process).
1076
- *
1077
- * Mach-O — one host-ld64 invocation: -r merges roots + needed members,
1078
- * -exported_symbols_list demotes every unlisted global to
1079
- * private extern, and -r without -keep_private_externs writes
1080
- * private externs out as non-external symbols. Apple ASan's
1081
- * image-registration COMMON remains shared so the final Mach-O
1082
- * image registers its globals once. ld64 reads every Apple
1083
- * platform's objects — macOS architectures and the iOS/
1084
- * iOS-simulator triples alike (LC_BUILD_VERSION platform and
1085
- * minos survive the merge) — so darwin-host macos AND ios
1086
- * targets ride the same arm; compileLibrary refuses those
1087
- * targets elsewhere.
1088
- * ELF, native linux host — ld -r merges with --force-group-allocation
1089
- * (ASan's instrumented globals ride ELF section groups whose
1090
- * signatures repeat across archives sharing runtime objects;
1091
- * resolving the groups into the combined member keeps a later
1092
- * multi-archive link from discarding one archive's copies),
1093
- * then binutils objcopy --keep-global-symbols localizes every
1094
- * other DEFINED global (objcopy leaves undefined symbols
1095
- * global by its own rule). The exact historical recipe.
1096
- * ELF, cross triples from any host — `zig cc -target <triple> -r`
1097
- * merges (zig is already the cross driver's hard requirement),
1098
- * then localizeElfObject demotes in process and resolves
1099
- * section groups the way --force-group-allocation does, with
1100
- * no host binutils/llvm-objcopy dependency.
1101
- * COFF, native win32 hosts and windows cross triples from any host —
1102
- * mergeAndLocalizeCoffObjects performs member selection, the
1103
- * merge, cross-object symbol resolution, and demotion in
1104
- * process: no linker offers a COFF relocatable mode (lld-link
1105
- * mirrors MSVC link.exe; zig's COFF driver refuses multi-object
1106
- * merges) and llvm-objcopy rejects symbol-scope flags for
1107
- * COFF, so no tool pairing exists to shell out to. */
1108
- export async function localizeLibraryObjects(driver, arArgv, buildDir, rootObjects, supportObjects, keepSymbols, stem, platform = targetPlatform(driver)) {
1109
- const combined = join(buildDir, `${stem}.localized.o`);
1110
- const staging = join(buildDir, `${stem}.localize-staging.a`);
1111
- const keepFile = join(buildDir, "localize-keep.syms");
1112
- const run = async (argv) => {
1113
- try {
1114
- await execFileAsync(argv[0], [...argv.slice(1)]);
1115
- }
1116
- catch (err) {
1117
- const stderr = subprocessFailureDetail(err);
1118
- throw new Error(`${argv[0]} failed while localizing the library archive's runtime symbols (abi.localize_runtime).\n` +
1119
- `Runtime symbol localization needs the ${platform === "darwin" ? "host toolchain's ld" : driver.target === null ? "host toolchain's ld and objcopy" : "cross driver's relocatable link"} beside the C compiler.\n\n${stderr}`);
1120
- }
1121
- };
1122
- if (platform === "win32") {
1123
- // COFF has no relocatable-link tool to stage through; the member
1124
- // selection and combine+demote happen in process over the object bytes.
1125
- const [roots, support] = await Promise.all([
1126
- Promise.all(rootObjects.map((path) => readFile(path))),
1127
- Promise.all(supportObjects.map((path) => readFile(path))),
1128
- ]);
1129
- try {
1130
- await writeFile(combined, mergeAndLocalizeCoffObjects(roots, support, new Set(keepSymbols), {
1131
- roots: rootObjects.map((path) => basename(path)),
1132
- support: supportObjects.map((path) => basename(path)),
1133
- }));
1134
- }
1135
- catch (err) {
1136
- throw new Error(`COFF symbol localization failed while localizing the library archive's runtime symbols (abi.localize_runtime).\n\n${err.message}`);
1137
- }
1138
- return combined;
1139
- }
1140
- const supportArgs = supportObjects.length === 0 ? [] : [staging];
1141
- if (supportObjects.length > 0) {
1142
- await run([arArgv[0] ?? "ar", ...arArgv.slice(1), "rcs", staging, ...supportObjects]);
1143
- }
1144
- if (platform === "darwin") {
1145
- await writeFile(keepFile, keepSymbols.map((s) => `_${s}\n`).join(""));
1146
- await run(["ld", "-r", ...rootObjects, ...supportArgs, "-o", combined, "-exported_symbols_list", keepFile]);
1147
- }
1148
- else if (platform === "linux" && driver.target === null) {
1149
- await writeFile(keepFile, keepSymbols.map((s) => `${s}\n`).join(""));
1150
- await run(["ld", "-r", "--force-group-allocation", ...rootObjects, ...supportArgs, "-o", combined]);
1151
- await run(["objcopy", `--keep-global-symbols=${keepFile}`, combined]);
1152
- }
1153
- else if (platform === "linux") {
1154
- // Cross ELF: the cross driver's own lld performs the relocatable merge
1155
- // (with the staging archive's member semantics); demotion and section-
1156
- // group resolution happen in process. -nostdlib keeps zig from feeding
1157
- // libc/compiler-rt inputs into the merge. Android rides this arm
1158
- // unchanged: bionic archives are ordinary aarch64 ELF64, and the merge
1159
- // uses the driver's zig spelling (which pins the API floor).
1160
- await run([
1161
- driver.argv[0] ?? "zig",
1162
- ...driver.argv.slice(1),
1163
- "-target", driver.zigTarget ?? driver.target,
1164
- "-nostdlib",
1165
- "-r", ...rootObjects, ...supportArgs,
1166
- "-o", combined,
1167
- ]);
1168
- try {
1169
- await writeFile(combined, localizeElfObject(await readFile(combined), new Set(keepSymbols)));
1170
- }
1171
- catch (err) {
1172
- throw new Error(`ELF symbol localization failed while localizing the library archive's runtime symbols (abi.localize_runtime).\n\n${err.message}`);
1173
- }
1174
- }
1175
- else {
1176
- throw new InternalCompilerError(`runtime symbol localization (abi.localize_runtime) has no ${platform} arm; compileLibrary admits darwin, linux, and win32 builds only`);
1177
- }
1178
- return combined;
1179
- }
1180
- /* -------------------------- persistent build cache ---------------------------
1181
- * Content-addressed caches that let repeat builds of unchanged programs skip
1182
- * payload code generation/linking — the test lanes' dominant cost. Executable
1183
- * lookups still run lightweight dependency and link-input metadata probes.
1184
- * Principal keyspaces under the cache root:
1185
- *
1186
- * bin/<key> — whole program binaries. key = sha256(resolved clang
1187
- * identity/version, target + compiler/linker environment,
1188
- * effective driver invocations for the real build flags,
1189
- * implicit system-header and resolved linker-input bytes,
1190
- * linker/assembler identities, runtime fingerprint
1191
- * (every .c/.h in the runtime src dir plus the vendor pin
1192
- * QJS_COMMIT), the caller's dependency identity, the
1193
- * compiler-visible TU path, Darwin output basename, the
1194
- * FULL normalized command line, and the emitted LLVM bytes).
1195
- * Emitted LLVM is
1196
- * deterministic, so unchanged programs
1197
- * hit; any flag difference — e.g. the sanitized lane's
1198
- * -O1/-fsanitize=address/-DSCR_RC_AUDIT — lands in a
1199
- * naturally distinct key. On a hit the cached binary is
1200
- * copied and atomically renamed onto outPath (never an
1201
- * in-place overwrite — see the hit path) after its digest
1202
- * is verified; the binary is still EXECUTED live by whoever
1203
- * asked for it, so no comparison or sanitizer coverage
1204
- * is ever skipped.
1205
- *
1206
- * lib/<key> — whole library archives. The identity covers the resolved
1207
- * compiler and archiver identities/versions, compiler/linker
1208
- * environment, effective build-flavor driver invocations,
1209
- * implicit toolchain inputs, runtime fingerprint,
1210
- * target/flags, gated source set, caller dependency
1211
- * identity, TU path, and program-TU bytes.
1212
- * Checksum-verified hits skip native code generation and ar.
1213
- *
1214
- * program-obj/<key> — the canonical library program object, after any LLVM
1215
- * shard merge. Exact TU repeats reuse it directly.
1216
- *
1217
- * program-shard/<key> — stable LLVM dev-library buckets keyed by their IR
1218
- * text and complete toolchain/TU identity. Local edits
1219
- * retain every bucket whose definitions/declarations did
1220
- * not change.
1221
- *
1222
- * obj/<set>/<f>.o — per-flavor runtime objects for cache-miss builds. The
1223
- * historical single invocation recompiles every runtime
1224
- * TU per program (~1.3s at -O2); with cached objects a
1225
- * miss compiles only the program's LLVM and links (~0.15s).
1226
- * Library-mode -DSCR_LIB objects use a distinct flavor.
1227
- * The clang driver hands every input the same option set,
1228
- * so per-TU `-c` compiles with those options plus a final
1229
- * link reproduce the single invocation exactly; the
1230
- * driver's effective invocation under that flavor also
1231
- * joins the object-set identity. Every
1232
- * cached object carries a verified digest. Object
1233
- * compiles go through ccache when it is installed (silent
1234
- * fallback when not).
1235
- *
1236
- * Frontend-generated production builds supply a dependency identity and use a
1237
- * per-user platform cache by default. Arbitrary low-level TUs omit the identity
1238
- * and bypass this cache because their include graph is caller-owned.
1239
- * Compiler wrappers also bypass every persistent tier: a wrapper can branch on
1240
- * the real source/object topology and inject inputs no synthetic probe sees.
1241
- * Direct Clang/Zig drivers and Apple's immutable /usr/bin/clang handoff retain
1242
- * caching; wrapper-driven builds use private, invocation-local vendor outputs.
1243
- * Opaque archiver wrappers bypass completed library archives for the same
1244
- * reason while retaining safely keyed runtime objects.
1245
- * Builds with caller-supplied native link inputs (archive/object paths or
1246
- * `-l<name>` libraries) also bypass the whole binary cache: a thin archive,
1247
- * linker script, or ambient resolution can change transitively without
1248
- * changing the named input's bytes or spelling. Their runtime objects remain
1249
- * cached, and every invocation performs the final link against current inputs.
1250
- * SCRIPTC_CACHE_DIR overrides the root (the test lanes use this to stay
1251
- * repo-local); an explicitly empty value or SCRIPTC_NO_CACHE=1 disables reads
1252
- * and writes. With caching disabled compileC issues the exact historical
1253
- * command line.
1254
- *
1255
- * Eviction: size-capped LRU over the whole cache root (SCRIPTC_CACHE_MAX_MB,
1256
- * default 4096). Explicit caps are checked after every successful write; the
1257
- * large default is swept on the first and every 64th write so corpus/watch
1258
- * loops do not repeatedly walk a growing tree. Reads bump mtimes. The harness's
1259
- * oracle cache lives under the same root and is swept by the same pass. Cache
1260
- * trouble is never a build failure — every cache error falls back to a real
1261
- * compile. */
1262
- const ccVersionMemos = new Map();
1263
- /** Identity of the compiler implementation and configuration selected by a
1264
- * fresh driver invocation. In particular, Darwin's stable /usr/bin/clang shim
1265
- * exposes the currently selected Xcode clang only in its `-###` trace. The
1266
- * normalized trace also covers output-affecting default driver configuration
1267
- * that can change while argv[0] and PATH retain the same spelling. */
1268
- async function effectiveCompilerEnvironmentIdentity(driver, env) {
1269
- const compiler = driver.argv[0] ?? "clang";
1270
- const resolvedDriver = await resolvedTool(compiler, env);
1271
- if (resolvedDriver === null)
1272
- return `<unresolved:${compiler}>`;
1273
- const probeDir = await mkdtemp(join(tmpdir(), "scriptc-early-cc-probe-"));
1274
- try {
1275
- const source = join(probeDir, "empty.c");
1276
- const object = join(probeDir, "empty.o");
1277
- await writeFile(source, "int scriptc_early_driver_probe;\n");
1278
- const trace = await execFileAsync(compiler, [
1279
- ...driver.argv.slice(1),
1280
- ...driver.targetArgs,
1281
- "-###",
1282
- "-std=c11",
1283
- "-c",
1284
- source,
1285
- "-o",
1286
- object,
1287
- ], { cwd: probeDir, env, maxBuffer: 16 * 1024 * 1024 });
1288
- const effectiveSpellings = [];
1289
- for (const line of `${trace.stdout}\n${trace.stderr}`.split(/\r?\n/)) {
1290
- const tokens = driverTraceCandidates(line);
1291
- const cc1 = tokens.indexOf("-cc1");
1292
- if (cc1 > 0)
1293
- effectiveSpellings.push(tokens[cc1 - 1]);
1294
- }
1295
- const effective = effectiveSpellings.length === 1
1296
- ? await resolvedTool(effectiveSpellings[0], env)
1297
- : null;
1298
- return createHash("sha256")
1299
- .update("effective-compiler-environment-v1\0")
1300
- .update(resolvedDriver.cacheIdentity).update("\0")
1301
- .update(normalizedProbeInvocation(trace, probeDir)).update("\0")
1302
- .update(effective?.cacheIdentity ?? `<unresolved-effective:${effectiveSpellings.join("\x1f")}>`)
1303
- .digest("hex");
1304
- }
1305
- finally {
1306
- await rm(probeDir, { recursive: true, force: true }).catch(() => undefined);
1307
- }
1308
- }
1309
- /** Resolve the executable the OS will select for an argv[0] spelling. The
1310
- * path and inode metadata join the version output below: two PATH postures
1311
- * must not share cache entries merely because both drivers call themselves
1312
- * `clang` or print the same upstream version. ctime catches an in-place tool
1313
- * replacement even when a package manager preserves its size and mtime. */
1314
- async function resolvedTool(command, env = process.env) {
1315
- const hasSeparator = command.includes("/") || command.includes("\\");
1316
- const configuredPath = (env["PATH"] ?? (process.platform === "win32" ? "" : "/usr/bin:/bin"))
1317
- .split(delimiter);
1318
- const pathEntries = hasSeparator
1319
- ? [""]
1320
- : process.platform === "win32"
1321
- ? ["", dirname(process.execPath), ...configuredPath]
1322
- : configuredPath;
1323
- const windowsExtensions = process.platform === "win32" && extname(command) === ""
1324
- ? (env["PATHEXT"] ?? ".COM;.EXE;.BAT;.CMD").split(";").filter((extension) => extension !== "")
1325
- : [""];
1326
- for (const entry of pathEntries) {
1327
- const directory = entry.startsWith('"') && entry.endsWith('"') ? entry.slice(1, -1) : entry;
1328
- const base = hasSeparator
1329
- ? isAbsolute(command) ? command : resolve(command)
1330
- : join(directory === "" ? process.cwd() : directory, command);
1331
- for (const extension of windowsExtensions) {
1332
- const candidate = `${base}${extension}`;
1333
- try {
1334
- await access(candidate, process.platform === "win32" ? fsConstants.F_OK : fsConstants.X_OK);
1335
- const [canonical, info] = await Promise.all([realpath(candidate), stat(candidate)]);
1336
- if (!info.isFile())
1337
- continue;
1338
- const fileIdentity = [
1339
- canonical,
1340
- info.dev,
1341
- info.ino,
1342
- info.size,
1343
- info.mtimeMs,
1344
- info.ctimeMs,
1345
- ].join("\0");
1346
- return {
1347
- canonicalPath: canonical,
1348
- fileIdentity,
1349
- cacheIdentity: [resolve(candidate), fileIdentity].join("\0"),
1350
- };
1351
- }
1352
- catch {
1353
- // Keep searching PATH/PATHEXT exactly as process spawning would.
1354
- }
1355
- }
1356
- }
1357
- return null;
1358
- }
1359
- async function resolvedToolIdentity(command, env = process.env) {
1360
- return (await resolvedTool(command, env))?.cacheIdentity ?? null;
1361
- }
1362
- const directCompilerDriverMemos = new Map();
1363
- const directCompilerSelections = new Map();
1364
- function compilerDriverProbeKey(driver, environmentFingerprint) {
1365
- return [
1366
- environmentFingerprint,
1367
- driver.argv.join("\x1f"),
1368
- driver.target ?? "<native>",
1369
- driver.targetArgs.join("\x1f"),
1370
- ].join("\0");
1371
- }
1372
- /** `/usr/bin/clang` on Darwin is Apple's immutable driver shim: its `-###`
1373
- * trace names the selected Xcode/CommandLineTools clang rather than the shim
1374
- * itself. The ordinary implicit-toolchain fingerprint below captures that
1375
- * selected executable and its dependencies, so this trusted system handoff is
1376
- * the one intentional exception to the same-executable rule. */
1377
- function isAppleSystemClangHandoff(driver, effectiveCompiler) {
1378
- return process.platform === "darwin" &&
1379
- driver.canonicalPath === "/usr/bin/clang" &&
1380
- basename(effectiveCompiler.canonicalPath) === "clang";
1381
- }
1382
- /** Persistent caches require an inspectable compiler driver. A general
1383
- * wrapper can branch on the real source/object paths or argument topology and
1384
- * inject inputs only into the final invocation; no synthetic metadata probe
1385
- * can safely represent that behavior. Accept direct Clang/Zig drivers (plus
1386
- * Apple's system shim) and conservatively keep wrapper-driven builds on the
1387
- * uncached path. */
1388
- export async function compilerDriverSupportsPersistentCache(driver, environmentFingerprint) {
1389
- // Cache-race tests exercise publication below an intentionally instrumented
1390
- // wrapper. This is deliberately undocumented and test-scoped.
1391
- if (process.env["SCRIPTC_TEST_TRUST_COMPILER_WRAPPER"] === "1")
1392
- return true;
1393
- const driverKey = compilerDriverProbeKey(driver, environmentFingerprint);
1394
- const compiler = driver.argv[0] ?? "clang";
1395
- const resolvedDriver = await resolvedTool(compiler);
1396
- // A prior dependency list cannot prove that name resolution is unchanged:
1397
- // a new header in an earlier search directory leaves every previously
1398
- // resolved file untouched. Require the driver to be present so each cache
1399
- // invocation can rediscover its complete dependency graph.
1400
- if (resolvedDriver === null)
1401
- return false;
1402
- const probeKey = `${driverKey}\0${resolvedDriver.fileIdentity}`;
1403
- const memoized = directCompilerDriverMemos.get(probeKey);
1404
- if (memoized !== undefined)
1405
- return memoized;
1406
- const probeDir = await mkdtemp(join(tmpdir(), "scriptc-driver-probe-"));
1407
- let direct = false;
1408
- try {
1409
- const source = join(probeDir, "empty.c");
1410
- const object = join(probeDir, "empty.o");
1411
- await writeFile(source, "int scriptc_driver_probe;\n");
1412
- const trace = await execFileAsync(compiler, [
1413
- ...driver.argv.slice(1),
1414
- ...driver.targetArgs,
1415
- "-###",
1416
- "-std=c11",
1417
- "-c",
1418
- source,
1419
- "-o",
1420
- object,
1421
- ], { cwd: probeDir, maxBuffer: 16 * 1024 * 1024 });
1422
- const effectiveSpellings = [];
1423
- for (const line of `${trace.stdout}\n${trace.stderr}`.split(/\r?\n/)) {
1424
- const tokens = driverTraceCandidates(line);
1425
- const cc1 = tokens.indexOf("-cc1");
1426
- if (cc1 > 0)
1427
- effectiveSpellings.push(tokens[cc1 - 1]);
1428
- }
1429
- if (effectiveSpellings.length === 1) {
1430
- const effectiveCompiler = await resolvedTool(effectiveSpellings[0]);
1431
- direct = effectiveCompiler !== null &&
1432
- (effectiveCompiler.fileIdentity === resolvedDriver.fileIdentity ||
1433
- isAppleSystemClangHandoff(resolvedDriver, effectiveCompiler));
1434
- if (direct)
1435
- directCompilerSelections.set(driverKey, effectiveCompiler);
1436
- }
1437
- }
1438
- catch {
1439
- direct = false;
1440
- }
1441
- finally {
1442
- await rm(probeDir, { recursive: true, force: true }).catch(() => undefined);
1443
- }
1444
- directCompilerDriverMemos.set(probeKey, direct);
1445
- if (!direct)
1446
- directCompilerSelections.delete(driverKey);
1447
- return direct;
1448
- }
1449
- /** Complete library archives may skip `ar`, so the selected archiver must be
1450
- * as inspectable as the compiler. `zig ar` is the already-validated Zig
1451
- * executable. For the host spelling, accept only the immutable platform
1452
- * tool locations; a PATH wrapper can branch on the real member topology or
1453
- * inject mutable inputs that `ar --version` cannot expose. Other archivers
1454
- * retain runtime-object reuse but rebuild the program member and archive. */
1455
- async function archiverSupportsPersistentCache(arArgv, driver) {
1456
- if (arArgv.length === 2 &&
1457
- arArgv[0] === driver.argv[0] &&
1458
- arArgv[1] === "ar" &&
1459
- driver.argv[0] === "zig") {
1460
- return true;
1461
- }
1462
- if (arArgv.length !== 1)
1463
- return false;
1464
- const archiver = await resolvedTool(arArgv[0] ?? "ar");
1465
- if (archiver === null || !/(?:^|-)ar$/.test(basename(archiver.canonicalPath))) {
1466
- return false;
1467
- }
1468
- if (archiver.canonicalPath.startsWith("/usr/bin/") || archiver.canonicalPath.startsWith("/bin/")) {
1469
- return true;
1470
- }
1471
- return process.platform === "darwin" &&
1472
- /^\/Applications\/Xcode[^/]*\.app\/Contents\/Developer\/Toolchains\/[^/]+\.xctoolchain\/usr\/bin\/[^/]*ar$/.test(archiver.canonicalPath);
1473
- }
1474
- export async function ccVersion(argv, environmentFingerprint = toolchainEnvironmentFingerprint(), fresh = false) {
1475
- const spellingKey = `${environmentFingerprint}\0${argv.join("\x1f")}`;
1476
- const executableIdentity = await resolvedToolIdentity(argv[0] ?? "clang");
1477
- const key = `${spellingKey}\0${executableIdentity ?? "<unresolved>"}`;
1478
- const probe = () =>
1479
- // `zig cc --version` (zig 0.16) drops an empty a.o in its cwd. A private
1480
- // probe directory avoids both caller pollution and the cross-process /
1481
- // cross-user collision a fixed tmpdir()/a.o would create on Linux.
1482
- (async () => {
1483
- const probeDir = await mkdtemp(join(tmpdir(), "scriptc-cc-version-"));
1484
- try {
1485
- const r = await execFileAsync(argv[0] ?? "clang", [...argv.slice(1), "--version"], { cwd: probeDir });
1486
- return `${executableIdentity ?? "<unresolved>"}\0${`${r.stdout}\n${r.stderr}`.trim()}`;
1487
- }
1488
- finally {
1489
- await rm(probeDir, { recursive: true, force: true }).catch(() => undefined);
1490
- }
1491
- })();
1492
- const requireFreshProbe = fresh && !stableTestToolchainSession();
1493
- let memo = requireFreshProbe && executableIdentity !== null ? probe() : ccVersionMemos.get(key);
1494
- if (memo === undefined) {
1495
- memo = probe();
1496
- ccVersionMemos.set(key, memo);
1497
- }
1498
- else if (requireFreshProbe) {
1499
- ccVersionMemos.set(key, memo);
1500
- }
1501
- return memo;
1502
- }
1503
- const toolVersionMemos = new Map();
1504
- const toolVersionFallbacks = new Map();
1505
- async function toolVersionOnce(argv, environmentFingerprint = toolchainEnvironmentFingerprint(), fresh = false) {
1506
- const spellingKey = `${environmentFingerprint}\0${argv.join("\x1f")}`;
1507
- const executableIdentity = await resolvedToolIdentity(argv[0] ?? "ar");
1508
- if (executableIdentity === null) {
1509
- const fallback = toolVersionFallbacks.get(spellingKey);
1510
- if (fallback !== undefined)
1511
- return fallback;
1512
- }
1513
- const key = `${spellingKey}\0${executableIdentity ?? "<unresolved>"}`;
1514
- const probe = () => execFileAsync(argv[0] ?? "ar", [...argv.slice(1), "--version"]).then((r) => `${executableIdentity ?? "<unresolved>"}\0${`${r.stdout}\n${r.stderr}`.trim()}`, (err) => `${executableIdentity ?? "<unresolved>"}\0${`${err.stdout ?? ""}\n${err.stderr ?? ""}`.trim() || err.message || key}`);
1515
- let memo = fresh && executableIdentity !== null ? probe() : toolVersionMemos.get(key);
1516
- if (memo === undefined) {
1517
- memo = probe();
1518
- toolVersionMemos.set(key, memo);
1519
- }
1520
- else if (fresh) {
1521
- toolVersionMemos.set(key, memo);
1522
- }
1523
- if (executableIdentity !== null)
1524
- toolVersionFallbacks.set(spellingKey, memo);
1525
- return memo;
1526
- }
1527
- /** Dependency paths discovered while computing one strict fingerprint. The
1528
- * output-local cache stamp snapshots these exact files/directories after a
1529
- * validated build, then can prove a later same-output no-op without spawning
1530
- * clang again. The content identity closes the gap between hashing and that
1531
- * metadata snapshot: a file changed in the gap cannot make new bytes ride an
1532
- * old key. Keep the map bounded for long-lived corpus/test processes. */
1533
- const fingerprintDependencies = new Map();
1534
- function rememberFingerprintDependencies(fingerprint, paths, contentPaths = [], contentFingerprint = null) {
1535
- fingerprintDependencies.set(fingerprint, {
1536
- paths: [...new Set(paths)].sort(),
1537
- contentPaths: [...new Set(contentPaths)].sort(),
1538
- contentFingerprint,
1539
- });
1540
- if (fingerprintDependencies.size > 256) {
1541
- const oldest = fingerprintDependencies.keys().next().value;
1542
- if (oldest !== undefined)
1543
- fingerprintDependencies.delete(oldest);
1544
- }
1545
- return fingerprint;
1546
- }
1547
- function fingerprintDependencyPaths(fingerprint) {
1548
- return fingerprintDependencies.get(fingerprint)?.paths ?? [];
1549
- }
1550
- function parseMakeDependencies(output, cwd = process.cwd()) {
1551
- const flattened = output.replace(/\\\r?\n/g, " ");
1552
- const separator = flattened.indexOf(": ");
1553
- if (separator < 0)
1554
- throw new Error("compiler dependency probe returned no make rule");
1555
- const input = flattened.slice(separator + 2);
1556
- const paths = [];
1557
- let current = "";
1558
- let escaped = false;
1559
- for (const char of input) {
1560
- if (escaped) {
1561
- current += char;
1562
- escaped = false;
1563
- }
1564
- else if (char === "\\") {
1565
- escaped = true;
1566
- }
1567
- else if (/\s/.test(char)) {
1568
- if (current !== "") {
1569
- paths.push(current.replace(/\$\$/g, "$"));
1570
- current = "";
1571
- }
1572
- }
1573
- else {
1574
- current += char;
1575
- }
1576
- }
1577
- if (escaped)
1578
- current += "\\";
1579
- if (current !== "")
1580
- paths.push(current.replace(/\$\$/g, "$"));
1581
- return [...new Set(paths.map((path) => resolve(cwd, path)))].sort();
1582
- }
1583
- function normalizedProbeInvocation(result, probeDir) {
1584
- return `${result.stdout}\n${result.stderr}`
1585
- // Probe-local paths vary on every invocation and carry no toolchain
1586
- // identity. Both ordinary and shell-escaped Windows spellings can appear
1587
- // in a driver's quoted trace.
1588
- .split(probeDir).join("<probe>")
1589
- .split(probeDir.replace(/\\/g, "\\\\")).join("<probe>")
1590
- .trim();
1591
- }
1592
- /** The effective cc1 invocation and injected dependencies for the flags used
1593
- * by real runtime/program compiles. The broad implicit-toolchain probe below
1594
- * intentionally uses a target-wide synthetic TU so it can discover every
1595
- * owned system header, but that generic command is not sufficient identity for
1596
- * a wrapper that injects flags or preincluded files only for a particular build
1597
- * flavor (for example, only when it sees -O2 or -DSCR_DYNAMIC). */
1598
- async function effectiveCompilerInvocationFingerprintFresh(driver, environmentFingerprint, compileArgs, sourceExtension = ".c") {
1599
- const compiler = driver.argv[0] ?? "clang";
1600
- const compilerIdentity = await resolvedToolIdentity(compiler);
1601
- if (compilerIdentity === null) {
1602
- throw new Error("compiler unavailable before effective invocation identity was established");
1603
- }
1604
- let probe;
1605
- {
1606
- const probeDir = await mkdtemp(join(tmpdir(), "scriptc-effective-cc-probe-"));
1607
- try {
1608
- const source = join(probeDir, `program${sourceExtension}`);
1609
- const output = join(probeDir, "program.o");
1610
- await writeFile(source, sourceExtension === ".ll"
1611
- ? "define i32 @scriptc_effective_probe() { ret i32 0 }\n"
1612
- : "int scriptc_effective_probe(void) { return 0; }\n");
1613
- const prefix = [...driver.argv.slice(1), ...compileArgs];
1614
- const [invocation, dependencyResult] = await Promise.all([
1615
- execFileAsync(compiler, [...prefix, "-###", "-c", source, "-o", output], { cwd: probeDir, maxBuffer: 16 * 1024 * 1024 }),
1616
- sourceExtension === ".c"
1617
- ? execFileAsync(compiler, [...prefix, "-M", source], {
1618
- cwd: probeDir,
1619
- maxBuffer: 16 * 1024 * 1024,
1620
- })
1621
- : Promise.resolve(null),
1622
- ]);
1623
- const dependencies = dependencyResult === null
1624
- ? []
1625
- : parseMakeDependencies(dependencyResult.stdout, probeDir).filter((path) => path !== resolve(source));
1626
- probe = {
1627
- compilerIdentity,
1628
- invocation: normalizedProbeInvocation(invocation, probeDir),
1629
- dependencies,
1630
- dependencyFingerprint: await fingerprintDependencyFiles(dependencies),
1631
- invocationPaths: await existingDriverTracePaths(`${invocation.stdout}\n${invocation.stderr}`, probeDir, probeDir),
1632
- };
1633
- }
1634
- finally {
1635
- await rm(probeDir, { recursive: true, force: true }).catch(() => undefined);
1636
- }
1637
- }
1638
- const fingerprint = createHash("sha256")
1639
- .update("effective-compiler-invocation-v2\0")
1640
- .update(environmentFingerprint)
1641
- .update("\0")
1642
- .update(probe.compilerIdentity)
1643
- .update("\0")
1644
- .update(driver.argv.join("\x1f"))
1645
- .update("\0")
1646
- .update(compileArgs.join("\x1f"))
1647
- .update("\0")
1648
- .update(sourceExtension)
1649
- .update("\0")
1650
- .update(probe.invocation)
1651
- .update("\0")
1652
- .update(probe.dependencies.join("\x1f"))
1653
- .update("\0")
1654
- .update(probe.dependencyFingerprint)
1655
- .digest("hex");
1656
- return rememberFingerprintDependencies(fingerprint, [...probe.dependencies, ...probe.invocationPaths], probe.dependencies, probe.dependencyFingerprint);
1657
- }
1658
- const stableEffectiveCompilerInvocationMemos = new Map();
1659
- function effectiveCompilerInvocationFingerprint(driver, environmentFingerprint, compileArgs, sourceExtension = ".c") {
1660
- const key = [
1661
- environmentFingerprint,
1662
- driver.argv.join("\x1f"),
1663
- compileArgs.join("\x1f"),
1664
- sourceExtension,
1665
- ].join("\0");
1666
- return stableTestMemo(stableEffectiveCompilerInvocationMemos, key, () => effectiveCompilerInvocationFingerprintFresh(driver, environmentFingerprint, compileArgs, sourceExtension));
1667
- }
1668
- async function nativeSourceFiles(directory, recursive, include = (name) => name.endsWith(".c") || name.endsWith(".h")) {
1669
- const files = [];
1670
- const walk = async (current, ancestors) => {
1671
- const canonical = await realpath(current).catch(() => resolve(current));
1672
- if (ancestors.has(canonical))
1673
- return;
1674
- const nestedAncestors = new Set(ancestors).add(canonical);
1675
- const entries = await readdir(current, { withFileTypes: true }).catch(() => []);
1676
- for (const entry of entries) {
1677
- const path = join(current, entry.name);
1678
- if (entry.isDirectory() && recursive) {
1679
- await walk(path, nestedAncestors);
1680
- }
1681
- else if (entry.isSymbolicLink()) {
1682
- const target = await stat(path).catch(() => null);
1683
- if (target?.isDirectory() && recursive)
1684
- await walk(path, nestedAncestors);
1685
- else if (target?.isFile() && include(entry.name))
1686
- files.push(path);
1687
- }
1688
- else if (entry.isFile() && include(entry.name)) {
1689
- files.push(path);
1690
- }
1691
- }
1692
- };
1693
- await walk(directory, new Set());
1694
- return files.sort();
1695
- }
1696
- /** Every system-header spelling consumed by a source tree scriptc owns. The
1697
- * dependency probe preprocesses these spellings with the selected driver and
1698
- * hashes the resolved files. Runtime-local and vendored source/header bytes
1699
- * have their own content/version identities; scanning every owned file for
1700
- * angle includes closes the system-header gap in separately built QuickJS,
1701
- * libregexp, mbedTLS, zlib, curl, and Ryū translation units. */
1702
- export async function implicitDependencyProbeIncludes(rtDir) {
1703
- const vendor = join(rtDir, "..", "vendor");
1704
- const quickjsSources = new Set([...QJS_ENGINE_SOURCES, ...LRE_SOURCES]);
1705
- const zlibSources = new Set(ZLIB_SOURCES);
1706
- const fileGroups = await Promise.all([
1707
- nativeSourceFiles(rtDir, false),
1708
- nativeSourceFiles(join(vendor, "ryu"), false),
1709
- nativeSourceFiles(join(vendor, "quickjs-ng"), false, (name) => name.endsWith(".h") || quickjsSources.has(name)),
1710
- nativeSourceFiles(join(vendor, "mbedtls", "include"), true),
1711
- nativeSourceFiles(join(vendor, "mbedtls", "library"), true),
1712
- nativeSourceFiles(join(vendor, "zlib"), false, (name) => name.endsWith(".h") || zlibSources.has(name)),
1713
- nativeSourceFiles(join(vendor, "curl", "include"), true, (name) => name.endsWith(".h")),
1714
- ]);
1715
- const includes = new Set();
1716
- for (const path of fileGroups.flat()) {
1717
- const source = await readFile(path, "utf8");
1718
- for (const match of source.matchAll(/^\s*#\s*include\s*<([^>]+)>/gm)) {
1719
- includes.add(`<${match[1]}>`);
1720
- }
1721
- }
1722
- return [...includes].sort();
1723
- }
1724
- function implicitDependencyIncludeDirective(include) {
1725
- const targetCondition = include === "<cpuid.h>" || include === "<immintrin.h>"
1726
- ? " && (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64))"
1727
- : include === "<intrin.h>"
1728
- ? " && defined(_WIN32)"
1729
- : include === "<arm64_neon.h>" || include === "<arm_acle.h>" || include === "<arm_neon.h>"
1730
- ? " && (defined(__arm__) || defined(__aarch64__) || defined(_M_ARM) || defined(_M_ARM64))"
1731
- : "";
1732
- return `#if __has_include(${include})${targetCondition}\n#include ${include}\n#endif\n`;
1733
- }
1734
- async function fingerprintDependencyFiles(paths) {
1735
- const hash = createHash("sha256").update("implicit-dependencies-v1\0");
1736
- for (let i = 0; i < paths.length; i += 128) {
1737
- const batch = paths.slice(i, i + 128);
1738
- const contents = await Promise.all(batch.map((path) => readFile(path)));
1739
- for (let j = 0; j < batch.length; j++) {
1740
- hash.update(batch[j]).update("\0").update(contents[j]).update("\0");
1741
- }
1742
- }
1743
- return hash.digest("hex");
1744
- }
1745
- async function fingerprintDependenciesStillMatch(fingerprints) {
1746
- const distinct = [...new Set(fingerprints)];
1747
- const identities = distinct
1748
- .map((fingerprint) => fingerprintDependencies.get(fingerprint))
1749
- // A restored native-metadata stamp carries and revalidates the dependency
1750
- // snapshot from the process that minted this fingerprint. Only identities
1751
- // computed in this process have an additional content hash to recheck here.
1752
- .filter((identity) => identity !== undefined);
1753
- return (await Promise.all(identities.map(async (identity) => identity.contentFingerprint === null ||
1754
- await fingerprintDependencyFiles(identity.contentPaths).catch(() => null) ===
1755
- identity.contentFingerprint))).every(Boolean);
1756
- }
1757
- /** Exact headers selected while preprocessing the caller's translation unit.
1758
- * The shared toolchain probe covers the runtime/vendor trees, but compileC is
1759
- * also a public API: an opted-in caller can include a system or header-only SDK
1760
- * surface that no runtime source names. Probe an invocation-private snapshot
1761
- * of the keyed bytes with the real compile flags, preserving the original
1762
- * quote-include directory and compiler-visible source spelling. */
1763
- async function translationUnitDependencyFingerprintFresh(driver, cflags, sourcePath, sourceBytes, environmentFingerprint) {
1764
- if (sourcePath.endsWith(".ll")) {
1765
- return rememberFingerprintDependencies(createHash("sha256").update("translation-unit-dependencies-v1\0llvm-ir").digest("hex"), []);
1766
- }
1767
- const compiler = driver.argv[0] ?? "clang";
1768
- const compilerIdentity = await resolvedToolIdentity(compiler);
1769
- if (compilerIdentity === null) {
1770
- throw new Error("compiler unavailable before translation-unit dependencies were established");
1771
- }
1772
- let probe;
1773
- {
1774
- const probeDir = await mkdtemp(join(tmpdir(), "scriptc-tu-probe-"));
1775
- try {
1776
- const snapshot = join(probeDir, "program.c");
1777
- await writeFile(snapshot, sourceBytes);
1778
- const result = await execFileAsync(compiler, [
1779
- ...driver.argv.slice(1),
1780
- // The real source directory is searched before every caller-supplied
1781
- // -iquote/-I directory. Put its surrogate first to preserve that
1782
- // precedence after moving the keyed bytes into the probe directory.
1783
- "-iquote",
1784
- dirname(resolve(sourcePath)),
1785
- ...cflags,
1786
- `-ffile-prefix-map=${snapshot}=${sourcePath}`,
1787
- "-M",
1788
- snapshot,
1789
- ], { cwd: probeDir, maxBuffer: 16 * 1024 * 1024 });
1790
- const ownPaths = new Set([resolve(snapshot), resolve(sourcePath)]);
1791
- const dependencies = parseMakeDependencies(result.stdout, probeDir).filter((path) => !ownPaths.has(path));
1792
- probe = {
1793
- compilerIdentity,
1794
- dependencies,
1795
- dependencyFingerprint: await fingerprintDependencyFiles(dependencies),
1796
- };
1797
- }
1798
- finally {
1799
- await rm(probeDir, { recursive: true, force: true }).catch(() => undefined);
1800
- }
1801
- }
1802
- const fingerprint = createHash("sha256")
1803
- .update("translation-unit-dependencies-v1\0")
1804
- .update(environmentFingerprint)
1805
- .update("\0")
1806
- .update(probe.compilerIdentity)
1807
- .update("\0")
1808
- .update(probe.dependencies.join("\x1f"))
1809
- .update("\0")
1810
- .update(probe.dependencyFingerprint)
1811
- .digest("hex");
1812
- return rememberFingerprintDependencies(fingerprint, probe.dependencies, probe.dependencies, probe.dependencyFingerprint);
1813
- }
1814
- const stableTranslationUnitDependencyMemos = new Map();
1815
- function translationUnitDependencyFingerprint(driver, cflags, sourcePath, sourceBytes, environmentFingerprint) {
1816
- const key = createHash("sha256")
1817
- .update(environmentFingerprint)
1818
- .update("\0")
1819
- .update(driver.argv.join("\x1f"))
1820
- .update("\0")
1821
- .update(cflags.join("\x1f"))
1822
- .update("\0")
1823
- .update(sourcePath)
1824
- .update("\0")
1825
- .update(resolve(sourcePath))
1826
- .update("\0")
1827
- .update(sourceBytes)
1828
- .digest("hex");
1829
- return stableTestMemo(stableTranslationUnitDependencyMemos, key, () => translationUnitDependencyFingerprintFresh(driver, cflags, sourcePath, sourceBytes, environmentFingerprint));
1830
- }
1831
- /** Identity of implicit compiler inputs that do not appear in buildArgs:
1832
- * default SDK/system headers and the assembler/linker selected by the driver.
1833
- * Small preprocessor dependency probes include every header spelling used by
1834
- * the runtime when it is available for the selected target (and therefore the
1835
- * vendored headers those TUs consume), then hash the exact dependency bytes.
1836
- * Vendored source snapshots remain keyed by their version pins. When the
1837
- * compiler is available, dependency discovery runs afresh so an SDK/config
1838
- * change that redirects includes cannot hide behind an unchanged old path
1839
- * list. Dependency discovery must succeed on every cache-enabled invocation;
1840
- * a prior path list cannot reveal a new higher-priority header. */
1841
- async function implicitToolchainFingerprintsFresh(driver, environmentFingerprint) {
1842
- let probe;
1843
- const compiler = driver.argv[0] ?? "clang";
1844
- const compilerIdentity = await resolvedToolIdentity(compiler);
1845
- if (compilerIdentity === null) {
1846
- throw new Error("compiler unavailable before implicit toolchain identity was established");
1847
- }
1848
- {
1849
- const probeDir = await mkdtemp(join(tmpdir(), "scriptc-toolchain-probe-"));
1850
- try {
1851
- const dependencyIncludes = await implicitDependencyProbeIncludes(runtimeSrcDir());
1852
- // Clang's GNU cpuid.h and Windows intrin.h both define `__cpuid` with
1853
- // incompatible signatures. Real TUs select only one context; preserve
1854
- // that isolation while still discovering both targets' dependency sets.
1855
- const sourceGroups = [
1856
- dependencyIncludes.filter((include) => include !== "<intrin.h>"),
1857
- dependencyIncludes.filter((include) => include === "<intrin.h>"),
1858
- ].filter((group) => group.length > 0);
1859
- const sources = sourceGroups.map((_, index) => join(probeDir, `empty-${index}.c`));
1860
- const driverSource = join(probeDir, "driver-empty.c");
1861
- const driverOutput = join(probeDir, "driver-output.o");
1862
- await Promise.all([
1863
- ...sources.map((source, index) => writeFile(source, sourceGroups[index].map(implicitDependencyIncludeDirective).join(""))),
1864
- writeFile(driverSource, "int scriptc_driver_probe;\n"),
1865
- ]);
1866
- const prefix = [...driver.argv.slice(1), ...driver.targetArgs];
1867
- const probeArgs = [
1868
- ...prefix,
1869
- "-std=c11",
1870
- "-D_GNU_SOURCE",
1871
- "-D_XOPEN_SOURCE=700",
1872
- "-I", runtimeSrcDir(),
1873
- "-I", vendorEngineDir(),
1874
- "-I", join(vendorTlsDir(), "include"),
1875
- "-I", join(vendorTlsDir(), "library"),
1876
- "-I", vendorZlibDir(),
1877
- "-I", join(vendorCurlDir(), "include"),
1878
- "-M",
1879
- ];
1880
- const [dependencyResults, linker, assembler, compilerInvocation] = await Promise.all([
1881
- Promise.all(sources.map((source) => execFileAsync(compiler, [...probeArgs, source], {
1882
- cwd: probeDir,
1883
- maxBuffer: 16 * 1024 * 1024,
1884
- }))),
1885
- execFileAsync(compiler, [...prefix, "-print-prog-name=ld"], { cwd: probeDir }),
1886
- execFileAsync(compiler, [...prefix, "-print-prog-name=as"], { cwd: probeDir }),
1887
- // `-###` exposes the effective cc1 invocation after compiler-driver
1888
- // config and ordinary wrappers have injected their implicit flags. A
1889
- // wrapper can read environment variables unknown to scriptc; hashing
1890
- // this trace keeps those flags from hiding behind an unchanged wrapper
1891
- // executable/version and dependency set.
1892
- execFileAsync(compiler, [...prefix, "-std=c11", "-###", "-c", driverSource, "-o", driverOutput], { cwd: probeDir, maxBuffer: 16 * 1024 * 1024 }),
1893
- ]);
1894
- const assemblerSpelling = assembler.stdout.trim();
1895
- const toolSpellings = [linker.stdout.trim(), assemblerSpelling].filter((value, index, all) => value !== "" && all.indexOf(value) === index);
1896
- const sourceSet = new Set(sources);
1897
- const dependencyPaths = [
1898
- ...new Set(dependencyResults
1899
- .flatMap((dependencies) => parseMakeDependencies(dependencies.stdout))
1900
- .filter((path) => !sourceSet.has(path))),
1901
- ].sort();
1902
- probe = {
1903
- compilerIdentity: compilerIdentity ?? `<unresolved>\0${compiler}`,
1904
- compilerInvocation: normalizedProbeInvocation(compilerInvocation, probeDir),
1905
- dependencies: dependencyPaths,
1906
- dependencyFingerprint: await fingerprintDependencyFiles(dependencyPaths),
1907
- invocationPaths: await existingDriverTracePaths(`${compilerInvocation.stdout}\n${compilerInvocation.stderr}`, probeDir, probeDir),
1908
- tools: await Promise.all(toolSpellings.map(async (spelling) => {
1909
- const resolved = await resolvedTool(spelling);
1910
- return {
1911
- spelling,
1912
- identity: resolved?.cacheIdentity ?? null,
1913
- path: resolved?.canonicalPath ?? null,
1914
- };
1915
- })),
1916
- compileToolSpellings: assemblerSpelling === "" ? [] : [assemblerSpelling],
1917
- };
1918
- }
1919
- finally {
1920
- await rm(probeDir, { recursive: true, force: true }).catch(() => undefined);
1921
- }
1922
- }
1923
- const tools = await Promise.all(probe.tools.map(async (tool) => ({
1924
- ...tool,
1925
- currentIdentity: await resolvedToolIdentity(tool.spelling),
1926
- })));
1927
- const fingerprint = (domain, selectedTools) => {
1928
- const hash = createHash("sha256")
1929
- .update(domain)
1930
- .update(environmentFingerprint)
1931
- .update("\0")
1932
- .update(probe.compilerIdentity)
1933
- .update("\0")
1934
- .update(probe.compilerInvocation)
1935
- .update("\0")
1936
- .update(driver.argv.join("\x1f"))
1937
- .update("\0")
1938
- .update(driver.targetArgs.join("\x1f"))
1939
- .update("\0")
1940
- .update(probe.dependencies.join("\x1f"))
1941
- .update("\0")
1942
- .update(probe.dependencyFingerprint)
1943
- .update("\0");
1944
- for (const tool of selectedTools) {
1945
- hash
1946
- .update(tool.spelling)
1947
- .update("\0")
1948
- .update(tool.currentIdentity ?? tool.identity ?? "<unresolved>")
1949
- .update("\0");
1950
- }
1951
- return rememberFingerprintDependencies(hash.digest("hex"), [
1952
- ...probe.dependencies,
1953
- ...probe.invocationPaths,
1954
- ...selectedTools.flatMap((tool) => tool.path === null ? [] : [tool.path]),
1955
- ], probe.dependencies, probe.dependencyFingerprint);
1956
- };
1957
- const compileSpellingSet = new Set(probe.compileToolSpellings);
1958
- return {
1959
- // Preserve the established complete fingerprint domain and byte stream.
1960
- complete: fingerprint("implicit-toolchain-v2\0", tools),
1961
- compile: fingerprint("implicit-compile-toolchain-v1\0", tools.filter((tool) => compileSpellingSet.has(tool.spelling))),
1962
- };
1963
- }
1964
- const stableImplicitToolchainMemos = new Map();
1965
- function implicitToolchainFingerprints(driver, environmentFingerprint) {
1966
- const key = [
1967
- environmentFingerprint,
1968
- driver.argv.join("\x1f"),
1969
- driver.target ?? "<native>",
1970
- driver.targetArgs.join("\x1f"),
1971
- runtimeSrcDir(),
1972
- ].join("\0");
1973
- return stableTestMemo(stableImplicitToolchainMemos, key, () => implicitToolchainFingerprintsFresh(driver, environmentFingerprint));
1974
- }
1975
- function implicitToolchainFingerprint(driver, environmentFingerprint) {
1976
- return implicitToolchainFingerprints(driver, environmentFingerprint).then((fingerprints) => fingerprints.complete);
1977
- }
1978
- async function existingDriverTracePaths(output, cwd, excludedRoot) {
1979
- const candidates = new Set();
1980
- for (const line of output.split(/\r?\n/)) {
1981
- const tokens = driverTraceCandidates(line);
1982
- for (let index = 0; index < tokens.length; index++) {
1983
- const token = tokens[index];
1984
- const joinedPathOption = ["-I", "-L", "-F"].find((option) => token.startsWith(option) && token.length > option.length);
1985
- const equalsPathOption = ["--sysroot=", "-resource-dir="].find((option) => token.startsWith(option));
1986
- const separatePathOptions = [
1987
- "-I",
1988
- "-L",
1989
- "-F",
1990
- "--sysroot",
1991
- "-isysroot",
1992
- "-resource-dir",
1993
- "-isystem",
1994
- "-iquote",
1995
- "-internal-isystem",
1996
- "-internal-externc-isystem",
1997
- "-internal-iframework",
1998
- ];
1999
- const optionPath = joinedPathOption !== undefined
2000
- ? token.slice(joinedPathOption.length)
2001
- : equalsPathOption !== undefined
2002
- ? token.slice(equalsPathOption.length)
2003
- : separatePathOptions.includes(token)
2004
- ? tokens[index + 1] ?? ""
2005
- : token;
2006
- if (!isAbsolute(optionPath))
2007
- continue;
2008
- const path = resolve(cwd, optionPath);
2009
- if (path === excludedRoot ||
2010
- path.startsWith(`${excludedRoot}/`) ||
2011
- path.startsWith(`${excludedRoot}\\`)) {
2012
- continue;
2013
- }
2014
- candidates.add(path);
2015
- }
2016
- }
2017
- const existing = await Promise.all([...candidates].map(async (path) => [path, await lstat(path).catch(() => null)]));
2018
- return existing
2019
- .filter((entry) => entry[1] !== null)
2020
- .map(([path]) => path)
2021
- .sort();
2022
- }
2023
- export async function parseLinkTraceFiles(output, cwd, excludedRoot, driverDryRun = false) {
2024
- const files = new Set();
2025
- for (const line of output.split(/\r?\n/)) {
2026
- const candidates = driverDryRun ? driverTraceCandidates(line) : linkTraceCandidate(line);
2027
- for (const candidate of candidates) {
2028
- const path = isAbsolute(candidate) ? candidate : resolve(cwd, candidate);
2029
- if (path === excludedRoot || path.startsWith(`${excludedRoot}/`) || path.startsWith(`${excludedRoot}\\`)) {
2030
- continue;
2031
- }
2032
- const info = await stat(path).catch(() => null);
2033
- if (info?.isFile()) {
2034
- files.add(path);
2035
- // Traditional `-Wl,-t` output has one dependency per line, while
2036
- // Zig's COFF `-###` fallback prints the entire lld-link argv on one
2037
- // line. Keep scanning every dry-run token so CRT/import/runtime
2038
- // libraries after the first path also join the fingerprint.
2039
- if (!driverDryRun)
2040
- break;
2041
- }
2042
- }
2043
- }
2044
- return [...files].sort();
2045
- }
2046
- /** Exact files selected by the compiler driver's implicit link. A tiny
2047
- * target object plus the linker's trace mode resolves CRT objects, compiler
2048
- * runtimes, linker scripts, SDK stubs/import libraries, and every ambient
2049
- * default library without guessing platform search layouts. The caller adds
2050
- * build-flavor flags such as ASan and scriptc's own fixed `-l` arguments.
2051
- * Every cache-enabled invocation performs a fresh trace; a prior resolved path
2052
- * list cannot reveal a newly selected higher-priority linker input. */
2053
- async function implicitLinkerFingerprintFresh(driver, environmentFingerprint, linkArgs, effectiveInvocationArgs, traceInvocationArgs) {
2054
- const invocationArgs = effectiveInvocationArgs ?? [...driver.targetArgs, ...linkArgs];
2055
- const traceArgs = traceInvocationArgs ?? [...driver.targetArgs, ...linkArgs];
2056
- const compiler = driver.argv[0] ?? "clang";
2057
- const compilerIdentity = await resolvedToolIdentity(compiler);
2058
- if (compilerIdentity === null) {
2059
- throw new Error("compiler unavailable before implicit linker identity was established");
2060
- }
2061
- let probe;
2062
- {
2063
- const probeDir = await mkdtemp(join(tmpdir(), "scriptc-linker-probe-"));
2064
- try {
2065
- const source = join(probeDir, "empty.c");
2066
- const object = join(probeDir, "empty.o");
2067
- const output = join(probeDir, process.platform === "win32" ? "empty.exe" : "empty");
2068
- await writeFile(source, "int main(void) { return 0; }\n");
2069
- const prefix = [...driver.argv.slice(1), ...driver.targetArgs];
2070
- const [, linker] = await Promise.all([
2071
- execFileAsync(compiler, [...prefix, "-std=c11", "-c", source, "-o", object], { cwd: probeDir }),
2072
- execFileAsync(compiler, [...prefix, "-print-prog-name=ld"], { cwd: probeDir }),
2073
- ]);
2074
- // Unlike the compile-only toolchain trace, this exposes options a
2075
- // compiler wrapper/config injects only for link invocations (rpaths,
2076
- // subsystem/stack settings, --defsym, and peers). Resolved input files
2077
- // alone cannot represent those output-affecting flags.
2078
- const driverInvocation = await execFileAsync(compiler, [...driver.argv.slice(1), ...invocationArgs, object, "-###", "-o", output], { cwd: probeDir, maxBuffer: 32 * 1024 * 1024 });
2079
- // The dry run exposes absolute files a wrapper injects for this exact
2080
- // build flavor. Its unresolved -l spellings are supplemented by the
2081
- // real trace below, which runs with the same flavor flags but omits
2082
- // not-yet-materialized scriptc-owned vendor prerequisites.
2083
- const driverDependencies = await parseLinkTraceFiles(`${driverInvocation.stdout}\n${driverInvocation.stderr}`, probeDir, probeDir, true);
2084
- let tracedDependencies = [];
2085
- try {
2086
- const trace = await execFileAsync(compiler, [...driver.argv.slice(1), ...traceArgs, object, "-Wl,-t", "-o", output], { cwd: probeDir, maxBuffer: 32 * 1024 * 1024 });
2087
- tracedDependencies = await parseLinkTraceFiles(`${trace.stdout}\n${trace.stderr}`, probeDir, probeDir);
2088
- }
2089
- catch (error) {
2090
- // Zig's COFF linker deliberately rejects GNU ld's `-t`, but `zig cc
2091
- // -###` prints its fully resolved lld-link input list (CRT and every
2092
- // import/compiler-runtime library as absolute cache paths). Other
2093
- // drivers' dry runs commonly leave `-lc`/`-lSystem` unresolved, so
2094
- // they must not use this fallback as a complete artifact identity.
2095
- if (driver.argv[0] !== "zig" || driver.argv[1] !== "cc")
2096
- throw error;
2097
- }
2098
- const dependencies = [...new Set([...driverDependencies, ...tracedDependencies])].sort();
2099
- if (dependencies.length === 0) {
2100
- throw new Error("linker trace reported no resolved input files");
2101
- }
2102
- const linkerSpelling = linker.stdout.trim();
2103
- probe = {
2104
- compilerIdentity,
2105
- linkerInvocation: normalizedProbeInvocation(driverInvocation, probeDir),
2106
- dependencies,
2107
- dependencyFingerprint: await fingerprintDependencyFiles(dependencies),
2108
- invocationPaths: await existingDriverTracePaths(`${driverInvocation.stdout}\n${driverInvocation.stderr}`, probeDir, probeDir),
2109
- linker: {
2110
- spelling: linkerSpelling,
2111
- identity: linkerSpelling === ""
2112
- ? null
2113
- : (await resolvedTool(linkerSpelling))?.cacheIdentity ?? null,
2114
- path: linkerSpelling === ""
2115
- ? null
2116
- : (await resolvedTool(linkerSpelling))?.canonicalPath ?? null,
2117
- },
2118
- };
2119
- }
2120
- finally {
2121
- await rm(probeDir, { recursive: true, force: true }).catch(() => undefined);
2122
- }
2123
- }
2124
- const linkerIdentity = probe.linker.spelling === ""
2125
- ? null
2126
- : await resolvedToolIdentity(probe.linker.spelling);
2127
- const fingerprint = createHash("sha256")
2128
- .update("implicit-linker-v3\0")
2129
- .update(environmentFingerprint)
2130
- .update("\0")
2131
- .update(probe.compilerIdentity)
2132
- .update("\0")
2133
- .update(probe.linkerInvocation)
2134
- .update("\0")
2135
- .update(driver.argv.join("\x1f"))
2136
- .update("\0")
2137
- .update(driver.targetArgs.join("\x1f"))
2138
- .update("\0")
2139
- .update(linkArgs.join("\x1f"))
2140
- .update("\0")
2141
- .update(invocationArgs.join("\x1f"))
2142
- .update("\0")
2143
- .update(traceArgs.join("\x1f"))
2144
- .update("\0")
2145
- .update(probe.dependencies.join("\x1f"))
2146
- .update("\0")
2147
- .update(probe.dependencyFingerprint)
2148
- .update("\0")
2149
- .update(probe.linker.spelling)
2150
- .update("\0")
2151
- .update(linkerIdentity ?? probe.linker.identity ?? "<unresolved>")
2152
- .digest("hex");
2153
- return rememberFingerprintDependencies(fingerprint, [
2154
- ...probe.dependencies,
2155
- ...probe.invocationPaths,
2156
- ...(probe.linker.path === null ? [] : [probe.linker.path]),
2157
- ], probe.dependencies, probe.dependencyFingerprint);
2158
- }
2159
- const stableImplicitLinkerMemos = new Map();
2160
- function implicitLinkerFingerprint(driver, environmentFingerprint, linkArgs, effectiveInvocationArgs, traceInvocationArgs) {
2161
- const invocationArgs = effectiveInvocationArgs ?? [...driver.targetArgs, ...linkArgs];
2162
- const traceArgs = traceInvocationArgs ?? [...driver.targetArgs, ...linkArgs];
2163
- const key = [
2164
- environmentFingerprint,
2165
- driver.argv.join("\x1f"),
2166
- driver.target ?? "<native>",
2167
- driver.targetArgs.join("\x1f"),
2168
- linkArgs.join("\x1f"),
2169
- invocationArgs.join("\x1f"),
2170
- traceArgs.join("\x1f"),
2171
- ].join("\0");
2172
- return stableTestMemo(stableImplicitLinkerMemos, key, () => implicitLinkerFingerprintFresh(driver, environmentFingerprint, linkArgs, effectiveInvocationArgs, traceInvocationArgs));
2173
- }
2174
- /** Resolve the exact files consumed by one compiler-driver link invocation.
2175
- * Runtime packs reuse the native toolchain's strict dry-run plus real linker
2176
- * trace so a PATH-selected Clang carries its own linker, SDK, compiler
2177
- * runtime, and injected inputs into the executable cache proof. */
2178
- export async function nativeLinkerDependencyPaths(linker, linkArgs) {
2179
- const fingerprint = await implicitLinkerFingerprint({ argv: [linker], targetArgs: [], target: null }, toolchainEnvironmentFingerprint(), linkArgs);
2180
- return fingerprintDependencyPaths(fingerprint);
2181
- }
2182
- let ccacheMemo = null;
2183
- /** Reset process observations whose validity is bounded to one public native
2184
- * build. A long-lived caller may change PATH or install/remove ccache between
2185
- * invocations; the next build must probe that environment again. */
2186
- export function clearCcCaches() {
2187
- ccacheMemo = null;
2188
- }
2189
- function ccacheAvailable() {
2190
- ccacheMemo ??= execFileAsync("ccache", ["--version"]).then(() => true, () => false);
2191
- return ccacheMemo;
2192
- }
2193
- /** Content hash of every owned native source/header plus this backend's build
2194
- * recipe implementation. It keys complete artifacts, runtime objects, and the
2195
- * separately built vendor prerequisites, so two installed scriptc versions or
2196
- * worktrees can share a user cache without exchanging outputs produced from
2197
- * different vendored bytes or compile/archive recipes. Recursive enumeration
2198
- * also catches a newly added nested header that begins shadowing a system
2199
- * include, while content hashing catches same-size timestamp-preserving edits. */
2200
- async function runtimeFingerprintFresh(rtDir) {
2201
- const groups = await runtimeFingerprintInputGroups(rtDir);
2202
- const h = createHash("sha256")
2203
- .update("native-owned-inputs-v2\0")
2204
- .update(QJS_COMMIT).update(MBEDTLS_VERSION).update(ZLIB_VERSION)
2205
- .update("\0backend-recipe\0");
2206
- for (const path of NATIVE_RECIPE_IMPLEMENTATION_PATHS) {
2207
- h.update(basename(path)).update("\0").update(await readFile(path)).update("\0");
2208
- }
2209
- for (const group of groups) {
2210
- for (const n of group.names) {
2211
- h.update(group.label).update("/").update(n).update("\0").update(await readFile(join(group.dir, n))).update("\0");
2212
- }
2213
- }
2214
- return h.digest("hex");
2215
- }
2216
- async function runtimeFingerprintInputGroups(rtDir) {
2217
- return Promise.all([
2218
- { label: "runtime", dir: rtDir },
2219
- { label: "ryu", dir: join(rtDir, "..", "vendor", "ryu") },
2220
- { label: "quickjs-ng", dir: join(rtDir, "..", "vendor", "quickjs-ng") },
2221
- { label: "mbedtls", dir: join(rtDir, "..", "vendor", "mbedtls") },
2222
- { label: "zlib", dir: join(rtDir, "..", "vendor", "zlib") },
2223
- { label: "curl", dir: join(rtDir, "..", "vendor", "curl") },
2224
- ].map(async (group) => {
2225
- const names = (await nativeSourceFiles(group.dir, true))
2226
- .map((path) => relative(group.dir, path))
2227
- .sort();
2228
- return { ...group, names };
2229
- }));
2230
- }
2231
- async function runtimeFingerprintInputPaths(rtDir) {
2232
- return [
2233
- ...(await runtimeFingerprintInputGroups(rtDir)).flatMap((group) => group.names.map((name) => join(group.dir, name))),
2234
- ...NATIVE_RECIPE_IMPLEMENTATION_PATHS,
2235
- ];
2236
- }
2237
- const stableRuntimeFingerprintMemos = new Map();
2238
- export function runtimeFingerprint(rtDir) {
2239
- const key = resolve(rtDir);
2240
- return stableTestMemo(stableRuntimeFingerprintMemos, key, () => runtimeFingerprintFresh(rtDir));
2241
- }
2242
- const { vendorEngineDir, vendorTlsDir, vendorCurlDir, vendorBuildCacheRoot, vendorCacheTargetFlavor, vendorCacheBuildIdentity, currentVendorCacheBuildIdentity, engineArchivePath, stageVendorInputs, ensureEngineArchive, lreObjectPaths, ensureLreObjects, vendorZlibDir, zlibObjectPaths, ensureZlibObjects, curlStubDirPath, ensureCurlStub, tlsArchivePath, ensureTlsArchive, QJS_ENGINE_SOURCES, LRE_SOURCES, ZLIB_SOURCES, } = createVendorArchives({
2243
- runtimeSrcDir,
2244
- targetPlatform,
2245
- isZigDriver,
2246
- resolvedToolIdentity,
2247
- runtimeFingerprint,
2248
- });
2249
- export { vendorCacheBuildIdentity, vendorCacheTargetFlavor };
2250
- class CacheInputsChangedError extends Error {
2251
- constructor() {
2252
- super("runtime inputs changed while populating the native object cache");
2253
- this.name = "CacheInputsChangedError";
2254
- }
2255
- }
2256
- async function directoryTreeDigest(root, excludedPaths = []) {
2257
- const hash = createHash("sha256").update("native-dependency-tree-v1\0");
2258
- const visited = new Set();
2259
- const excluded = excludedPaths.map((path) => resolve(path));
2260
- const walk = async (directory, relative) => {
2261
- const canonical = await realpath(directory);
2262
- if (visited.has(canonical)) {
2263
- hash.update(relative).update("\0cycle\0").update(canonical).update("\0");
2264
- return;
2265
- }
2266
- visited.add(canonical);
2267
- const entries = await readdir(directory, { withFileTypes: true });
2268
- entries.sort((a, b) => a.name.localeCompare(b.name));
2269
- for (const entry of entries) {
2270
- const path = join(directory, entry.name);
2271
- const absolute = resolve(path);
2272
- if (excluded.some((candidate) => absolute === candidate ||
2273
- absolute.startsWith(`${candidate}/`) ||
2274
- absolute.startsWith(`${candidate}\\`)))
2275
- continue;
2276
- const child = relative === "" ? entry.name : `${relative}/${entry.name}`;
2277
- const info = await lstat(path);
2278
- const kind = info.isDirectory()
2279
- ? "directory"
2280
- : info.isFile()
2281
- ? "file"
2282
- : info.isSymbolicLink()
2283
- ? "symlink"
2284
- : "other";
2285
- hash.update(child).update("\0").update(kind).update("\0");
2286
- if (kind === "symlink") {
2287
- const target = await realpath(path).catch(() => "<missing>");
2288
- hash.update(target).update("\0");
2289
- const targetInfo = await stat(path).catch(() => null);
2290
- if (targetInfo?.isDirectory())
2291
- await walk(path, child);
2292
- }
2293
- if (kind === "directory")
2294
- await walk(path, child);
2295
- }
2296
- visited.delete(canonical);
2297
- };
2298
- await walk(root, "");
2299
- return hash.digest("hex");
2300
- }
2301
- function localDependencyKind(info) {
2302
- return info.isFile()
2303
- ? "file"
2304
- : info.isDirectory()
2305
- ? "directory"
2306
- : info.isSymbolicLink()
2307
- ? "symlink"
2308
- : null;
2309
- }
2310
- async function snapshotLocalArtifactDependency(path, treeExclusions = null) {
2311
- const info = await lstat(path);
2312
- const kind = localDependencyKind(info);
2313
- if (kind === null)
2314
- throw new Error(`unsupported local artifact dependency: ${path}`);
2315
- const dependency = {
2316
- path,
2317
- kind,
2318
- dev: info.dev,
2319
- ino: info.ino,
2320
- size: info.size,
2321
- mtimeMs: info.mtimeMs,
2322
- ctimeMs: info.ctimeMs,
2323
- };
2324
- if (kind === "directory" && treeExclusions !== null) {
2325
- dependency.treeExclusions = [...new Set(treeExclusions.map((entry) => resolve(entry)))].sort();
2326
- dependency.treeDigest = await directoryTreeDigest(path, dependency.treeExclusions);
2327
- }
2328
- if (kind === "symlink") {
2329
- const targetPath = await realpath(path);
2330
- const target = await stat(path);
2331
- const targetKind = target.isFile() ? "file" : target.isDirectory() ? "directory" : null;
2332
- if (targetKind === null)
2333
- throw new Error(`unsupported symlink target dependency: ${path}`);
2334
- dependency.targetPath = targetPath;
2335
- dependency.targetKind = targetKind;
2336
- dependency.targetDev = target.dev;
2337
- dependency.targetIno = target.ino;
2338
- dependency.targetSize = target.size;
2339
- dependency.targetMtimeMs = target.mtimeMs;
2340
- dependency.targetCtimeMs = target.ctimeMs;
2341
- if (targetKind === "directory" && treeExclusions !== null) {
2342
- dependency.treeExclusions = [...new Set(treeExclusions.map((entry) => resolve(entry)))].sort();
2343
- dependency.treeDigest = await directoryTreeDigest(path, dependency.treeExclusions);
2344
- }
2345
- }
2346
- return dependency;
2347
- }
2348
- async function snapshotLocalArtifactDependencies(dependencyPaths, recursiveDirectories = [], recursiveExclusions = []) {
2349
- const recursive = new Set(recursiveDirectories.map((path) => resolve(path)));
2350
- return Promise.all([...new Set(dependencyPaths)].sort().map((path) => snapshotLocalArtifactDependency(path, recursive.has(resolve(path)) ? recursiveExclusions : null)));
2351
- }
2352
- /** Capture exact filesystem identities for inputs produced outside the C
2353
- * toolchain but consumed by its cache proofs. Callers carry this snapshot
2354
- * forward so later stages can prove the same inputs remained installed. */
2355
- export async function snapshotNativeArtifactDependencies(dependencyPaths) {
2356
- return snapshotLocalArtifactDependencies(dependencyPaths);
2357
- }
2358
- export async function nativeArtifactDependenciesStillMatch(dependencies) {
2359
- if (!dependencies.every((dependency) => dependency !== null && typeof dependency === "object" &&
2360
- typeof dependency.path === "string" &&
2361
- (dependency.kind === "file" || dependency.kind === "directory" || dependency.kind === "symlink") &&
2362
- typeof dependency.dev === "number" && typeof dependency.ino === "number" &&
2363
- typeof dependency.size === "number" && typeof dependency.mtimeMs === "number" &&
2364
- typeof dependency.ctimeMs === "number" &&
2365
- (dependency.treeDigest === undefined || typeof dependency.treeDigest === "string") &&
2366
- (dependency.treeExclusions === undefined || (Array.isArray(dependency.treeExclusions) &&
2367
- dependency.treeExclusions.every((path) => typeof path === "string"))) &&
2368
- (dependency.kind !== "symlink" || (typeof dependency.targetPath === "string" &&
2369
- (dependency.targetKind === "file" || dependency.targetKind === "directory") &&
2370
- typeof dependency.targetDev === "number" && typeof dependency.targetIno === "number" &&
2371
- typeof dependency.targetSize === "number" && typeof dependency.targetMtimeMs === "number" &&
2372
- typeof dependency.targetCtimeMs === "number"))))
2373
- return false;
2374
- return (await Promise.all(dependencies.map(async (dependency) => {
2375
- const current = await snapshotLocalArtifactDependency(dependency.path, dependency.treeDigest === undefined ? null : dependency.treeExclusions ?? []).catch(() => null);
2376
- return current !== null && JSON.stringify(current) === JSON.stringify(dependency);
2377
- }))).every(Boolean);
2378
- }
2379
- function nativeMetadataStampPath(root, key) {
2380
- return join(root, "meta", createHash("sha256").update(key).digest("hex"));
2381
- }
2382
- function nativeMetadataStampIntegrity(stamp) {
2383
- return createHash("sha256")
2384
- .update("native-metadata-stamp-v2\0")
2385
- .update(JSON.stringify(stamp))
2386
- .digest("hex");
2387
- }
2388
- async function readNativeMetadataStamp(root, key) {
2389
- try {
2390
- const stamp = JSON.parse(await readFile(nativeMetadataStampPath(root, key), "utf8"));
2391
- if (stamp.version !== 2 ||
2392
- stamp.key !== key ||
2393
- stamp.values === null ||
2394
- typeof stamp.values !== "object" ||
2395
- !Array.isArray(stamp.dependencies) ||
2396
- !/^[0-9a-f]{64}$/.test(stamp.integrity) ||
2397
- nativeMetadataStampIntegrity({
2398
- version: stamp.version,
2399
- key: stamp.key,
2400
- values: stamp.values,
2401
- dependencies: stamp.dependencies,
2402
- }) !== stamp.integrity ||
2403
- !(await nativeArtifactDependenciesStillMatch(stamp.dependencies))) {
2404
- return null;
2405
- }
2406
- return stamp;
2407
- }
2408
- catch {
2409
- return null;
2410
- }
2411
- }
2412
- async function publishNativeMetadataStamp(root, key, values, dependencyPaths, fingerprints = []) {
2413
- const destination = nativeMetadataStampPath(root, key);
2414
- await mkdir(dirname(destination), { recursive: true });
2415
- const dependencies = await snapshotLocalArtifactDependencies(dependencyPaths);
2416
- if (!(await fingerprintDependenciesStillMatch(fingerprints))) {
2417
- throw new CacheInputsChangedError();
2418
- }
2419
- const unsigned = { version: 2, key, values, dependencies };
2420
- const stamp = {
2421
- ...unsigned,
2422
- integrity: nativeMetadataStampIntegrity(unsigned),
2423
- };
2424
- const tmp = `${destination}.tmp-${process.pid}-${Math.random().toString(36).slice(2)}`;
2425
- try {
2426
- await writeFile(tmp, `${JSON.stringify(stamp)}\n`, { mode: 0o600 });
2427
- await rename(tmp, destination);
2428
- }
2429
- finally {
2430
- await rm(tmp, { force: true }).catch(() => undefined);
2431
- }
2432
- return stamp;
2433
- }
2434
- function nativeMetadataKey(kind, parts) {
2435
- const hash = createHash("sha256").update(`native-metadata-${kind}-v2\0`);
2436
- for (const part of parts) {
2437
- hash.update(typeof part === "string" ? part : part.join("\x1f")).update("\0");
2438
- }
2439
- return `${kind}-${hash.digest("hex")}`;
2440
- }
2441
- /** The caller-visible output is itself the cheapest safe cache tier. Once a
2442
- * generated TU has produced this exact binary, an unchanged rebuild need not
2443
- * rediscover every SDK header and linker input merely to copy equivalent bytes
2444
- * back onto the same path. This tier is deliberately narrower than the CAS:
2445
- * only frontend-generated programs with no caller-owned native inputs opt in.
2446
- * The generated TU bytes, every scriptc runtime source, the selected direct
2447
- * compiler inode, target/options/environment, and the output path all join the
2448
- * key. A digest rejects a modified/truncated output before the no-op hit. */
2449
- function localArtifactIdentity(opts, driver, environmentFingerprint, compilerIdentity, runtimeHash, programBytes, programShardMerge) {
2450
- const normalizedOptions = Object.fromEntries(Object.entries(opts)
2451
- // Shard source can be tens of megabytes. Hash it incrementally below
2452
- // instead of materializing a second giant JSON string solely for this
2453
- // output-local fast-path identity.
2454
- .filter(([key, value]) => value !== undefined && key !== "programShards" && key !== "programPublicSymbols")
2455
- .sort(([a], [b]) => a.localeCompare(b)));
2456
- const executableSectionFlags = executableSectionEliminationFlags(targetPlatform(driver));
2457
- const executableOptimizationFlags = executableOptimizationLinkerArgs(targetPlatform(driver), opts.optimization ?? "release");
2458
- const hash = createHash("sha256")
2459
- .update("local-artifact-v2\0")
2460
- .update(cacheTargetIdentity(driver)).update("\0")
2461
- .update(environmentFingerprint).update("\0")
2462
- .update(compilerIdentity).update("\0")
2463
- .update(runtimeHash).update("\0")
2464
- .update(driver.argv.join("\x1f")).update("\0")
2465
- .update(driver.targetArgs.join("\x1f")).update("\0")
2466
- .update(driver.linkArgs.join("\x1f")).update("\0")
2467
- .update(executableSectionFlags.compile.join("\x1f")).update("\0")
2468
- .update(executableSectionFlags.link.join("\x1f")).update("\0");
2469
- // Only release WASI currently adds an optimization-specific link flag.
2470
- // Salt that identity so a pre-fix DWARF-bearing output cannot hit, without
2471
- // invalidating unchanged native and dev artifacts on upgrade.
2472
- if (executableOptimizationFlags.length > 0) {
2473
- hash.update("optimization-linker-flags\0")
2474
- .update(executableOptimizationFlags.join("\x1f")).update("\0");
2475
- }
2476
- if (opts.sanitize && opts.optimization === "dev")
2477
- hash.update("sanitized-runtime-o1-v1\0");
2478
- if (programShardMerge !== null) {
2479
- updateProgramShardCacheIdentity(hash, opts.programShards, opts.programPublicSymbols, programShardMerge);
2480
- }
2481
- return hash
2482
- .update(process.env["SCRIPTC_FETCH_CURL"] === "1" ? "fetch-curl" : "fetch-native").update("\0")
2483
- .update(JSON.stringify(normalizedOptions)).update("\0")
2484
- .update(resolve(opts.cPath)).update("\0")
2485
- .update(resolve(opts.outPath)).update("\0")
2486
- .update(programBytes)
2487
- .digest("hex");
2488
- }
2489
- function localArtifactStampPath(root, outPath) {
2490
- const outputKey = createHash("sha256").update(resolve(outPath)).digest("hex");
2491
- return join(root, "local", outputKey);
2492
- }
2493
- function localArtifactStampIntegrity(stamp) {
2494
- return createHash("sha256")
2495
- .update("local-artifact-stamp-v2\0")
2496
- .update(JSON.stringify(stamp))
2497
- .digest("hex");
2498
- }
2499
- async function localArtifactHit(stampPath, outPath, key, darwinDebugSymbols = false) {
2500
- try {
2501
- const stamp = JSON.parse(await readFile(stampPath, "utf8"));
2502
- const output = await lstat(outPath);
2503
- const expectedMode = 0o777 & ~process.umask();
2504
- if (stamp.version !== 2 ||
2505
- stamp.key !== key ||
2506
- !/^[0-9a-f]{64}$/.test(stamp.digest ?? "") ||
2507
- (darwinDebugSymbols !== (stamp.debugSymbolsDigest !== undefined)) ||
2508
- (stamp.debugSymbolsDigest !== undefined && !/^[0-9a-f]{64}$/.test(stamp.debugSymbolsDigest)) ||
2509
- !Array.isArray(stamp.dependencies) ||
2510
- !/^[0-9a-f]{64}$/.test(stamp.integrity ?? "") ||
2511
- localArtifactStampIntegrity({
2512
- version: stamp.version,
2513
- key: stamp.key,
2514
- digest: stamp.digest,
2515
- dependencies: stamp.dependencies,
2516
- ...(stamp.debugSymbolsDigest === undefined ? {} : { debugSymbolsDigest: stamp.debugSymbolsDigest }),
2517
- }) !== stamp.integrity ||
2518
- !output.isFile() ||
2519
- (output.mode & 0o777) !== expectedMode ||
2520
- stamp.dependencies.some((dependency) => dependency === null ||
2521
- typeof dependency !== "object" ||
2522
- typeof dependency.path !== "string" ||
2523
- dependency.kind !== "file" &&
2524
- dependency.kind !== "directory" &&
2525
- dependency.kind !== "symlink" ||
2526
- typeof dependency.dev !== "number" ||
2527
- typeof dependency.ino !== "number" ||
2528
- typeof dependency.size !== "number" ||
2529
- typeof dependency.mtimeMs !== "number" ||
2530
- typeof dependency.ctimeMs !== "number" ||
2531
- dependency.treeDigest !== undefined && typeof dependency.treeDigest !== "string" ||
2532
- dependency.kind === "symlink" && (typeof dependency.targetPath !== "string" ||
2533
- dependency.targetKind !== "file" && dependency.targetKind !== "directory" ||
2534
- typeof dependency.targetDev !== "number" ||
2535
- typeof dependency.targetIno !== "number" ||
2536
- typeof dependency.targetSize !== "number" ||
2537
- typeof dependency.targetMtimeMs !== "number" ||
2538
- typeof dependency.targetCtimeMs !== "number")) ||
2539
- !(await nativeArtifactDependenciesStillMatch(stamp.dependencies)) ||
2540
- await fileDigest(outPath) !== stamp.digest ||
2541
- darwinDebugSymbols && createHash("sha256").update(await readDarwinDebugSymbols(outPath)).digest("hex") !== stamp.debugSymbolsDigest) {
2542
- return null;
2543
- }
2544
- const now = new Date();
2545
- await utimes(stampPath, now, now).catch(() => undefined);
2546
- return stamp;
2547
- }
2548
- catch {
2549
- return null;
2550
- }
2551
- }
2552
- async function publishLocalArtifactStamp(stampPath, outPath, key, dependencyPaths, recursiveDirectories = [], recursiveExclusions = [], darwinDebugSymbols = false) {
2553
- await mkdir(dirname(stampPath), { recursive: true });
2554
- const tmp = `${stampPath}.tmp-${process.pid}-${Math.random().toString(36).slice(2)}`;
2555
- try {
2556
- const dependencies = await snapshotLocalArtifactDependencies(dependencyPaths, recursiveDirectories, recursiveExclusions);
2557
- const unsigned = {
2558
- version: 2,
2559
- key,
2560
- digest: await fileDigest(outPath),
2561
- dependencies,
2562
- ...(darwinDebugSymbols
2563
- ? { debugSymbolsDigest: createHash("sha256").update(await readDarwinDebugSymbols(outPath)).digest("hex") }
2564
- : {}),
2565
- };
2566
- const stamp = {
2567
- ...unsigned,
2568
- integrity: localArtifactStampIntegrity(unsigned),
2569
- };
2570
- await writeFile(tmp, `${JSON.stringify(stamp)}\n`, { mode: 0o600 });
2571
- await rename(tmp, stampPath);
2572
- return stamp;
2573
- }
2574
- finally {
2575
- await rm(tmp, { force: true }).catch(() => undefined);
2576
- }
2577
- }
2578
- /** The cached .o set for one flag flavor, compiled on first need. Concurrent
2579
- * first builds (parallel test workers on a cold cache) may duplicate work;
2580
- * per-file atomic renames make every winner equivalent. Publication is held
2581
- * until verifyInputs confirms that the source/header fingerprint used by the
2582
- * key still describes the bytes clang just read. */
2583
- async function ensureRuntimeObjects(root, ccArgv, cflags, sources, keyPrefix, verifyInputs, protectedPaths) {
2584
- const setKey = createHash("sha256")
2585
- .update(keyPrefix)
2586
- .update(cflags.join("\x1f"))
2587
- .digest("hex")
2588
- .slice(0, 24);
2589
- const objDir = join(root, "obj", setKey);
2590
- const objOf = (src) => join(objDir, `${basename(src, ".c")}.o`);
2591
- if (protectedPaths !== undefined) {
2592
- for (const source of sources) {
2593
- const object = objOf(source);
2594
- protectedPaths.add(object);
2595
- protectedPaths.add(cacheDigestPath(object));
2596
- }
2597
- }
2598
- const present = await Promise.all(sources.map((s) => validCachedFile(objOf(s))));
2599
- const missing = sources.filter((_, i) => !present[i]);
2600
- if (missing.length > 0) {
2601
- // ccache wraps only the default clang driver — multi-word drivers
2602
- // (`zig cc`) run bare; their object sets are keyed apart anyway.
2603
- const useCcache = process.env["SCRIPTC_TEST_DISABLE_CCACHE"] !== "1" &&
2604
- ccArgv.length === 1 &&
2605
- ccArgv[0] === "clang" &&
2606
- (await ccacheAvailable());
2607
- await mkdir(objDir, { recursive: true });
2608
- const tmpDir = await mkdtemp(join(tmpdir(), "scriptc-cache-obj-"));
2609
- try {
2610
- const compiled = new Map();
2611
- // Modest parallelism: a flavor's objects build once, but several cold
2612
- // workers can race here — keep each build's CPU footprint small.
2613
- const width = 4;
2614
- for (let i = 0; i < missing.length; i += width) {
2615
- await Promise.all(missing.slice(i, i + width).map(async (src) => {
2616
- const tmpObj = join(tmpDir, `${basename(src, ".c")}.o`);
2617
- const argv = [...(useCcache ? ["ccache"] : []), ...ccArgv, ...cflags, "-c", src, "-o", tmpObj];
2618
- await execFileAsync(argv[0] ?? "clang", argv.slice(1), useCcache
2619
- ? {
2620
- // ccache direct mode remembers only the headers selected by
2621
- // its previous manifest and can miss a newly created,
2622
- // higher-priority header. The scriptc object-set key already
2623
- // includes the recursive runtime namespace fingerprint, so
2624
- // carry it into ccache's own keyspace as well.
2625
- env: {
2626
- ...process.env,
2627
- CCACHE_NAMESPACE: [
2628
- process.env["CCACHE_NAMESPACE"],
2629
- `scriptc-${setKey}`,
2630
- ].filter((value) => value !== undefined && value !== "").join(":"),
2631
- },
2632
- }
2633
- : undefined);
2634
- compiled.set(src, tmpObj);
2635
- }));
2636
- }
2637
- // The fingerprint was computed before these subprocesses started. Do
2638
- // not place their outputs under that key if a checkout/package update
2639
- // changed any runtime source or included header while clang was reading.
2640
- if (!(await verifyInputs()))
2641
- throw new CacheInputsChangedError();
2642
- for (const [src, built] of compiled) {
2643
- const destination = objOf(src);
2644
- await publishCachedFile(built, destination);
2645
- }
2646
- }
2647
- finally {
2648
- await rm(tmpDir, { recursive: true, force: true });
2649
- }
2650
- }
2651
- if (!(await verifyInputs()))
2652
- throw new CacheInputsChangedError();
2653
- const objects = new Map(sources.map((s) => [s, objOf(s)]));
2654
- if (!(await Promise.all([...objects.values()].map(validCachedFile))).every(Boolean)) {
2655
- throw new Error("native object cache integrity check failed");
2656
- }
2657
- return objects;
2658
- }
2659
- /** Give one active link/archive operation private names for its cached
2660
- * runtime objects. A hard link keeps the inode alive if another process's LRU
2661
- * sweep unlinks the cache entry; filesystems that cannot hard-link across the
2662
- * cache/tmp boundary fall back to a copy. If eviction wins before staging,
2663
- * the caller catches the read failure and performs a fully fresh compile. */
2664
- export async function stageRuntimeObjects(objects, stageDir) {
2665
- await mkdir(stageDir, { recursive: true });
2666
- const now = new Date();
2667
- const staged = await Promise.all([...objects].map(async ([source, object]) => {
2668
- const destination = join(stageDir, basename(object));
2669
- try {
2670
- await link(object, destination);
2671
- }
2672
- catch {
2673
- await copyFile(object, destination);
2674
- }
2675
- // Object files participate in the same mtime-based LRU as complete
2676
- // artifacts. A successful stage is a cache read, so promote the source
2677
- // name best-effort (it may have raced an eviction after the hard link).
2678
- await utimes(object, now, now).catch(() => undefined);
2679
- return [source, destination];
2680
- }));
2681
- return new Map(staged);
2682
- }
2683
- /** Compiles one C program together with the runtime sources.
2684
- * With caching disabled, the runtime (a dozen small files) is recompiled on
2685
- * every build — no cached-archive staleness bugs. Sanitized dev builds compile
2686
- * the program separately so its O0 setting does not slow the O1 runtime.
2687
- * Other builds use one clang invocation. --dynamic additionally compiles
2688
- * scr_island.c under SCR_DYNAMIC and links the cached engine archive (built
2689
- * lazily, see above); regex-using programs additionally compile scr_regex.c
2690
- * and link libregexp (the cached objects, or the archive's own copy under
2691
- * --dynamic). Executable links use the target's section-elimination recipe
2692
- * independently of those feature gates.
2693
- *
2694
- * With a caller-supplied dependency identity and an enabled cache root,
2695
- * unchanged programs skip payload code generation/linking via the binary
2696
- * cache after lightweight metadata probes, and misses link the program's own
2697
- * TU against cached per-flavor runtime objects. */
2698
- async function compileCInternal(opts, cacheWarmOnly, cacheWarmPaths) {
2699
- const rtDir = runtimeSrcDir();
2700
- const sanitize = opts.sanitize ?? false;
2701
- const optimization = opts.optimization ?? "release";
2702
- const dynamic = opts.dynamic ?? false;
2703
- const regex = opts.regex ?? false;
2704
- // fetch's implementation switch: the default is the NATIVE bridge
2705
- // (scr_fetch.c over scr_net + scr_tls + scr_http's client parser +
2706
- // zlib — no libcurl anywhere), which implies the socket units into the
2707
- // link. SCRIPTC_FETCH_CURL=1 keeps the retired curl reference
2708
- // (scr_fetch_curl.c + system libcurl / the linux soname stub)
2709
- // compilable for one release as the flip's reference.
2710
- const fetchOn = opts.fetch ?? false;
2711
- // The retired curl bridge has only a SCR_DYNAMIC implementation.
2712
- // Static fetch always keeps the native runtime even when a developer
2713
- // has the comparison switch exported in their shell.
2714
- const curlFetch = dynamic && fetchOn && process.env["SCRIPTC_FETCH_CURL"] === "1";
2715
- const nativeFetch = fetchOn && !curlFetch;
2716
- // The island's node:http/https client bridge: embedded graphs that
2717
- // import those builtins get working clients over the same socket units
2718
- // (native-fetch builds always carry it — scr_fetch_install registers it).
2719
- const netIsland = dynamic && ((opts.netIsland ?? false) || nativeFetch);
2720
- const net = (opts.net ?? false) || nativeFetch || netIsland;
2721
- const http = (opts.http ?? false) || nativeFetch || netIsland;
2722
- const tls = (opts.tls ?? false) || nativeFetch || netIsland;
2723
- const tlsCa = (opts.tlsCa ?? false) || tls;
2724
- const driver = resolveCc();
2725
- const darwinDebugSymbols = needsDarwinDebugSymbols(targetPlatform(driver), optimization, opts.strip);
2726
- if (opts.frameworks?.length && targetPlatform(driver) !== "darwin")
2727
- throw new Error("FFI frameworks require a Darwin target");
2728
- if (opts.frameworks?.some(name => !/^[A-Za-z][A-Za-z0-9_]*$/.test(name)))
2729
- throw new Error("Invalid FFI framework name");
2730
- const debugFlags = optimization === "dev" && !opts.strip
2731
- ? ["-gline-tables-only", ...(opts.cPath.endsWith(".ll") ? [] : ["-gno-column-info"])]
2732
- : [];
2733
- const shardNames = new Set();
2734
- const programShardsValid = opts.programShards?.every((shard) => {
2735
- if (basename(shard.name) !== shard.name || !shard.name.endsWith(".ll") ||
2736
- shardNames.has(shard.name))
2737
- return false;
2738
- shardNames.add(shard.name);
2739
- return true;
2740
- }) === true;
2741
- const programShardsRequested = optimization === "dev" && !sanitize && opts.cPath.endsWith(".ll") &&
2742
- programShardsValid && opts.programShards !== undefined && opts.programShards.length > 1 &&
2743
- opts.programPublicSymbols !== undefined
2744
- ? opts.programShards
2745
- : null;
2746
- const programShardMergeIdentity = programShardsRequested === null
2747
- ? null
2748
- : await resolveProgramShardMergeIdentity(driver);
2749
- const programShards = programShardMergeIdentity === null ? null : programShardsRequested;
2750
- const programPublicSymbols = programShards === null ? undefined : opts.programPublicSymbols;
2751
- // Mobile triples produce library archives, never standalone executables:
2752
- // the executable-lane runtime (event loop, sockets, child processes) is
2753
- // not verified on those device classes. compile() reports the SC3002
2754
- // diagnostic first; this is the backstop for direct compileC callers.
2755
- if (isMobileTarget(driver.target)) {
2756
- throw new Error(`SCRIPTC_TARGET=${driver.target} builds library-mode static archives only — ` +
2757
- `compile with a library profile (SCRIPTC_CC=zigcc scriptc build --lib --profile <profile.json>) and link the archive from the app project.`);
2758
- }
2759
- const runtimeSources = targetPlatform(driver) === "wasi"
2760
- ? EXECUTABLE_RUNTIME_SOURCES.filter((source) => source !== "scr_child.c")
2761
- : EXECUTABLE_RUNTIME_SOURCES;
2762
- const executableSectionFlags = executableSectionEliminationFlags(targetPlatform(driver));
2763
- const windowsSubsystemArgs = windowsSubsystemLinkerArgs(targetPlatform(driver), opts.windowsSubsystem);
2764
- const executableLinkFlags = [
2765
- ...executableSectionFlags.link,
2766
- ...executableOptimizationLinkerArgs(targetPlatform(driver), optimization),
2767
- ...executableStripLinkerArgs(targetPlatform(driver), opts.strip ?? false),
2768
- ...windowsSubsystemArgs,
2769
- ];
2770
- // scr_async.c submits callback-style filesystem work to a native worker.
2771
- // POSIX drivers need the thread compile/link mode; win32 uses CreateThread.
2772
- const threadArgs = targetPlatform(driver) === "win32" || targetPlatform(driver) === "wasi"
2773
- ? []
2774
- : ["-pthread"];
2775
- if (driver.target !== null) {
2776
- // See the resolveCc block: these inputs are built on and for the HOST
2777
- // (vendored archives, system libs). Regex, zlib, and the engine archive
2778
- // are NOT here: their vendored sources are plain C that ensureLreObjects
2779
- // / ensureZlibObjects / buildEngineArchiveDirect compile per target with
2780
- // the driver itself — win32 included (the Windows lane runs the
2781
- // @dynamic corpus and the zlib program against the box's Node). The
2782
- // NATIVE fetch rides the socket units and cross-compiles with them —
2783
- // no gate; only the retired curl REFERENCE (SCRIPTC_FETCH_CURL=1)
2784
- // keeps a linux-only arm (the vendored curl headers + the generated
2785
- // soname stub, ensureCurlStub — win32 has no system libcurl contract
2786
- // to bind at load time). The event-loop units, tls, and dgram cross-compile to Linux
2787
- // AND Windows (scr_platform.h poller + per-target mbedTLS; the
2788
- // loop's win32 arm is WSAPoll, scr_loop_wsapoll.c, and the socket
2789
- // units' win32 arms respell winsock behind POSIX-errno wrappers —
2790
- // scr_net.c/scr_dgram.c/scr_tls.c). The events unit cross-compiles
2791
- // everywhere: its win32 arm is CRT signal() +
2792
- // PeekNamedPipe/WaitForSingleObject probes (scr_events.c), served by
2793
- // the loop's capped win32 idle sleep (scr_async.c).
2794
- const unsupported = [
2795
- // The NATIVE fetch cross-compiles wherever the socket units do
2796
- // (linux and win32 both); only the retired curl reference keeps
2797
- // its linux-only soname-stub arm.
2798
- ["fetch (SCRIPTC_FETCH_CURL)", curlFetch && targetPlatform(driver) !== "linux"],
2799
- ]
2800
- .filter(([, on]) => on)
2801
- .map(([name]) => name);
2802
- if (unsupported.length > 0) {
2803
- throw new Error(`SCRIPTC_TARGET=${driver.target}: ${unsupported.join(", ")} not supported under a cross target yet ` +
2804
- `(host-built vendor archives / system libs — see docs/linux-port.md).`);
2805
- }
2806
- }
2807
- const cachePolicy = toolchainEnvironmentCachePolicy();
2808
- const configuredCacheRoot = cacheRootDir();
2809
- const toolchainEnv = toolchainEnvironmentFingerprint();
2810
- const persistentDriverCache = cachePolicy.runtimeObjects &&
2811
- configuredCacheRoot !== null &&
2812
- await compilerDriverSupportsPersistentCache(driver, toolchainEnv);
2813
- // Only compiler-generated TUs opt in. Arbitrary `compileC` inputs
2814
- // inputs may include caller-owned headers whose contents are not otherwise
2815
- // represented in this key, so they retain the fully uncached historical
2816
- // path unless the caller supplies its own complete dependency identity.
2817
- const cacheIdentity = opts.cacheIdentity;
2818
- let persistentCache = cacheIdentity === undefined || configuredCacheRoot === null || !persistentDriverCache
2819
- ? null
2820
- : { root: configuredCacheRoot, identity: cacheIdentity };
2821
- if (cacheWarmOnly && persistentCache === null) {
2822
- throw new Error("native cache warming requires a persistently cacheable compiler environment");
2823
- }
2824
- if (persistentCache !== null) {
2825
- try {
2826
- await ensurePrivateCacheRoot(persistentCache.root, process.env["SCRIPTC_CACHE_DIR"] === undefined);
2827
- }
2828
- catch (error) {
2829
- if (cacheWarmOnly) {
2830
- throw new Error("native cache warming could not prepare the persistent cache root", {
2831
- cause: error,
2832
- });
2833
- }
2834
- persistentCache = null;
2835
- }
2836
- }
2837
- let localArtifact = null;
2838
- // Generated executable TUs are closed over scriptc's own runtime tree. A
2839
- // same-output rebuild can therefore check those bytes directly before the
2840
- // broader cross-output CAS performs its compiler/SDK/linker rediscovery.
2841
- // FFI/native-input builds and the public arbitrary-C cache API stay on the
2842
- // strict path because their dependency graphs are caller-owned.
2843
- if (!cacheWarmOnly &&
2844
- persistentCache !== null &&
2845
- cachePolicy.completeArtifacts &&
2846
- persistentCache.identity === "scriptc-generated-v1" &&
2847
- (opts.linkInputs?.length ?? 0) === 0 &&
2848
- (opts.frameworks?.length ?? 0) === 0 &&
2849
- (opts.systemLibraries?.length ?? 0) === 0 &&
2850
- process.env["SCRIPTC_TEST_TRUST_COMPILER_WRAPPER"] !== "1") {
2851
- try {
2852
- const [compiler, runtimeHash, programBytes] = await Promise.all([
2853
- resolvedTool(driver.argv[0] ?? "clang"),
2854
- runtimeFingerprint(rtDir),
2855
- readFile(opts.cPath),
2856
- ]);
2857
- if (compiler !== null) {
2858
- const effectiveCompiler = directCompilerSelections.get(compilerDriverProbeKey(driver, toolchainEnv)) ?? compiler;
2859
- const key = localArtifactIdentity(opts, driver, toolchainEnv, `${compiler.cacheIdentity}\0${effectiveCompiler.cacheIdentity}`, runtimeHash, programBytes, programShardMergeIdentity);
2860
- const stampPath = localArtifactStampPath(persistentCache.root, opts.outPath);
2861
- localArtifact = {
2862
- stampPath,
2863
- key,
2864
- runtimeHash,
2865
- programBytes,
2866
- compilerPath: effectiveCompiler.canonicalPath,
2867
- };
2868
- const hit = await localArtifactHit(stampPath, opts.outPath, key, darwinDebugSymbols);
2869
- if (hit !== null) {
2870
- await opts.onArtifactReady?.({ dependencies: hit.dependencies }).catch(() => undefined);
2871
- return;
2872
- }
2873
- }
2874
- }
2875
- catch {
2876
- // The output-local tier is only an optimization; the fully validated
2877
- // CAS below remains the source of truth on any metadata trouble.
2878
- localArtifact = null;
2879
- }
2880
- }
2881
- let implicitToolchain = null;
2882
- let implicitCompileToolchain = null;
2883
- let toolchainMetadataStamp = null;
2884
- const metadataCompiler = persistentCache === null
2885
- ? null
2886
- : await resolvedTool(driver.argv[0] ?? "clang");
2887
- const metadataEffectiveCompiler = directCompilerSelections.get(compilerDriverProbeKey(driver, toolchainEnv)) ?? metadataCompiler;
2888
- const toolchainMetadataKey = persistentCache === null ||
2889
- metadataCompiler === null ||
2890
- metadataEffectiveCompiler === null ||
2891
- process.env["SCRIPTC_TEST_TRUST_COMPILER_WRAPPER"] === "1"
2892
- ? null
2893
- : nativeMetadataKey("toolchain", [
2894
- cacheTargetIdentity(driver),
2895
- toolchainEnv,
2896
- driver.argv,
2897
- driver.targetArgs,
2898
- metadataCompiler.cacheIdentity,
2899
- metadataEffectiveCompiler.cacheIdentity,
2900
- rtDir,
2901
- ]);
2902
- if (persistentDriverCache) {
2903
- try {
2904
- toolchainMetadataStamp =
2905
- persistentCache === null || toolchainMetadataKey === null
2906
- ? null
2907
- : await readNativeMetadataStamp(persistentCache.root, toolchainMetadataKey);
2908
- implicitToolchain = toolchainMetadataStamp?.values["implicitToolchain"] ?? null;
2909
- implicitCompileToolchain =
2910
- toolchainMetadataStamp?.values["implicitCompileToolchain"] ?? null;
2911
- if (implicitToolchain === null ||
2912
- (programShards !== null && implicitCompileToolchain === null)) {
2913
- const fingerprints = await implicitToolchainFingerprints(driver, toolchainEnv);
2914
- implicitToolchain = fingerprints.complete;
2915
- implicitCompileToolchain = fingerprints.compile;
2916
- toolchainMetadataStamp = null;
2917
- }
2918
- let compilerVersion = toolchainMetadataStamp?.values["compilerVersion"];
2919
- if (compilerVersion === undefined) {
2920
- compilerVersion = await ccVersion(driver.argv, toolchainEnv, true);
2921
- }
2922
- if (toolchainMetadataStamp === null &&
2923
- persistentCache !== null &&
2924
- toolchainMetadataKey !== null) {
2925
- if (metadataCompiler !== null && metadataEffectiveCompiler !== null) {
2926
- toolchainMetadataStamp = await publishNativeMetadataStamp(persistentCache.root, toolchainMetadataKey, {
2927
- implicitToolchain,
2928
- ...(implicitCompileToolchain === null ? {} : { implicitCompileToolchain }),
2929
- compilerVersion,
2930
- }, [
2931
- metadataCompiler.canonicalPath,
2932
- metadataEffectiveCompiler.canonicalPath,
2933
- ...fingerprintDependencyPaths(implicitToolchain),
2934
- ...(implicitCompileToolchain === null
2935
- ? []
2936
- : fingerprintDependencyPaths(implicitCompileToolchain)),
2937
- ], [
2938
- implicitToolchain,
2939
- ...(implicitCompileToolchain === null ? [] : [implicitCompileToolchain]),
2940
- ]);
2941
- }
2942
- }
2943
- }
2944
- catch (error) {
2945
- // Cache discovery is best-effort. In particular, a compiler wrapper can
2946
- // compile successfully without implementing the metadata probes.
2947
- if (cacheWarmOnly) {
2948
- throw new Error("native cache warming could not validate the compiler toolchain", {
2949
- cause: error,
2950
- });
2951
- }
2952
- persistentCache = null;
2953
- }
2954
- }
2955
- const vendorBuildIdentity = await currentVendorCacheBuildIdentity(driver, `${toolchainEnv}\0${implicitToolchain ?? "<uncached>"}`);
2956
- // Mutable include/SDK/config inputs can change behind a stable environment
2957
- // spelling. The complete/runtime cache is disabled below; vendor objects
2958
- // must follow the same rule instead of silently surviving in the user cache.
2959
- // A private root gives this invocation the usual vendor build recipe
2960
- // without publishing or reusing those prerequisites.
2961
- const transientVendorRoot = persistentCache !== null && implicitToolchain !== null
2962
- ? null
2963
- : join(tmpdir(), `scriptc-vendor-${process.pid}-${Math.random().toString(36).slice(2)}`);
2964
- const vendorCacheRoot = transientVendorRoot ?? vendorBuildCacheRoot(persistentCache?.root);
2965
- // Every vendor output path is deterministic from pins, flags, driver, and
2966
- // target. Build the command/key from those paths now, but do not materialize
2967
- // them until a complete-binary lookup has missed.
2968
- let engineArchive = dynamic
2969
- ? engineArchivePath(sanitize, driver, vendorBuildIdentity, vendorCacheRoot)
2970
- : null;
2971
- let tlsArchive = tls
2972
- ? tlsArchivePath(sanitize, driver, vendorBuildIdentity, vendorCacheRoot)
2973
- : null;
2974
- // --dynamic + regex shares the archive's libregexp (its host hooks and
2975
- // ours would collide; see scr_regex.c) — the standalone objects are for
2976
- // static builds only.
2977
- let lreObjects = regex && !dynamic
2978
- ? lreObjectPaths(sanitize, driver, vendorBuildIdentity, vendorCacheRoot)
2979
- : [];
2980
- // Vendored zlib is the Zig story — default host-clang builds keep the exact
2981
- // historical `-lz` system link (see CcOptions.zlib). The native fetch's
2982
- // gzip decoder rides the same objects/link.
2983
- let zlibObjects = ((opts.zlib ?? false) || nativeFetch) && isZigDriver(driver)
2984
- ? zlibObjectPaths(sanitize, driver, vendorBuildIdentity, vendorCacheRoot)
2985
- : [];
2986
- // The libcurl import stub is likewise CROSS-only — host builds keep the
2987
- // exact historical system `-lcurl` link (see CcOptions.fetch). Curl
2988
- // reference builds only.
2989
- let curlStubDir = curlFetch && driver.target !== null
2990
- ? curlStubDirPath(driver, vendorBuildIdentity, vendorCacheRoot)
2991
- : null;
2992
- const materializeVendorPrerequisites = async (stageRoot, materializeCacheRoot = vendorCacheRoot) => {
2993
- // Preserve source order to avoid multiplying first-build resource
2994
- // pressure when several large vendor sets are cold simultaneously.
2995
- if (dynamic) {
2996
- const cachedArchive = engineArchivePath(sanitize, driver, vendorBuildIdentity, materializeCacheRoot);
2997
- protectCachedArtifact(cacheWarmPaths, cachedArchive);
2998
- const materialize = async () => [
2999
- await ensureEngineArchive(sanitize, driver, vendorBuildIdentity, materializeCacheRoot),
3000
- ];
3001
- const paths = stageRoot === undefined
3002
- ? await materialize()
3003
- : await stageVendorInputs(materialize, join(stageRoot, "engine"));
3004
- engineArchive = paths[0];
3005
- }
3006
- if (tls) {
3007
- const cachedArchive = tlsArchivePath(sanitize, driver, vendorBuildIdentity, materializeCacheRoot);
3008
- protectCachedArtifact(cacheWarmPaths, cachedArchive);
3009
- const materialize = async () => [
3010
- await ensureTlsArchive(sanitize, driver, vendorBuildIdentity, materializeCacheRoot),
3011
- ];
3012
- const paths = stageRoot === undefined
3013
- ? await materialize()
3014
- : await stageVendorInputs(materialize, join(stageRoot, "tls"));
3015
- tlsArchive = paths[0];
3016
- }
3017
- if (regex && !dynamic) {
3018
- for (const object of lreObjectPaths(sanitize, driver, vendorBuildIdentity, materializeCacheRoot))
3019
- protectCachedArtifact(cacheWarmPaths, object);
3020
- const materialize = async () => await ensureLreObjects(sanitize, driver, vendorBuildIdentity, materializeCacheRoot);
3021
- lreObjects = stageRoot === undefined
3022
- ? await materialize()
3023
- : await stageVendorInputs(materialize, join(stageRoot, "lre"));
3024
- }
3025
- if (zlibObjects.length > 0) {
3026
- for (const object of zlibObjectPaths(sanitize, driver, vendorBuildIdentity, materializeCacheRoot))
3027
- protectCachedArtifact(cacheWarmPaths, object);
3028
- const materialize = async () => await ensureZlibObjects(sanitize, driver, vendorBuildIdentity, materializeCacheRoot);
3029
- zlibObjects = stageRoot === undefined
3030
- ? await materialize()
3031
- : await stageVendorInputs(materialize, join(stageRoot, "zlib"));
3032
- }
3033
- if (curlStubDir !== null) {
3034
- protectCachedArtifact(cacheWarmPaths, join(curlStubDirPath(driver, vendorBuildIdentity, materializeCacheRoot), "libcurl.so"));
3035
- const materialize = async () => [
3036
- join(await ensureCurlStub(driver, vendorBuildIdentity, materializeCacheRoot), "libcurl.so"),
3037
- ];
3038
- const paths = stageRoot === undefined
3039
- ? await materialize()
3040
- : await stageVendorInputs(materialize, join(stageRoot, "curl"));
3041
- curlStubDir = dirname(paths[0]);
3042
- }
3043
- };
3044
- // rt() maps each runtime source's path on the command line: identity for
3045
- // the historical single invocation, cached-.o substitution on cache misses.
3046
- const buildArgs = (rt, build = {}) => [
3047
- "-std=c11",
3048
- ...debugFlags,
3049
- ...driver.targetArgs,
3050
- ...threadArgs,
3051
- ...(sanitize
3052
- ? ["-O1", "-fsanitize=address", "-DSCR_RC_AUDIT"]
3053
- : [optimization === "dev" ? "-O0" : "-O2"]),
3054
- ...executableSectionFlags.compile,
3055
- ...(opts.textDecoderLegacy ? ["-DSCR_TEXT_DECODER_LEGACY"] : []),
3056
- "-fno-math-errno",
3057
- // The runtime object model uses type-punned C: a hierarchy
3058
- // upcast is a raw pointer cast, so one object's header (rc, vt) and
3059
- // fields are read and written through BOTH the base and derived struct
3060
- // types (sc_retain_Derived vs sc_release_Base on the same object).
3061
- // C's effective-type rule calls that UB, and clang's TBAA at -O2
3062
- // reorders/elides the rc updates once everything inlines — an upcast
3063
- // identity compare frees the object while a global still owns it.
3064
- // The LLVM backend emits no TBAA metadata; this flag preserves
3065
- // matching memory semantics in the runtime. Mirrored in the
3066
- // cache-miss cflags below and compileLibArchive — the three option
3067
- // sets must stay in lockstep.
3068
- "-fno-strict-aliasing",
3069
- "-Wno-deprecated-declarations", // ucontext fibers (scr_async.c)
3070
- "-I", rtDir,
3071
- ...runtimeSources.map((f) => rt(join(rtDir, f))),
3072
- ...(opts.copying ? [rt(join(rtDir, "scr_copying.c"))] : []),
3073
- ...(opts.fileHandle ? [rt(join(rtDir, "scr_file_handle.c"))] : []),
3074
- // win32 targets compile the libc-shim TU (stpcpy, arc4random_buf,
3075
- // gmtime_r, strcasestr — the _WIN32 block in scr_runtime.h declares
3076
- // them) and link advapi32 (the CSPRNG RtlGenRandom/SystemFunction036,
3077
- // GetUserNameA), iphlpapi (GetAdaptersAddresses behind
3078
- // os.networkInterfaces), and ws2_32 (inet_ntop there; the socket
3079
- // units ride the same import). Never present on the default path, so
3080
- // the historical line cannot change.
3081
- ...(targetPlatform(driver) === "win32"
3082
- ? [rt(join(rtDir, "scr_win.c")), "-ladvapi32", "-liphlpapi", "-lws2_32"]
3083
- : []),
3084
- // musl deliberately has no libc-identification predefine; resolveCc's
3085
- // SCR_MUSL flag and this target-selected TU travel together.
3086
- ...(isMuslTarget(driver) ? [rt(join(rtDir, "scr_musl.c"))] : []),
3087
- ...(regex
3088
- ? ["-I", vendorEngineDir(), rt(join(rtDir, "scr_regex.c")), ...lreObjects]
3089
- : []),
3090
- ...(opts.assert || regex || opts.symbol ? [rt(join(rtDir, "scr_assert.c"))] : []),
3091
- ...(opts.inspect ? [rt(join(rtDir, "scr_inspect.c")), rt(join(rtDir, "scr_console_native.c"))] : []),
3092
- ...((opts.dynInvoke || nativeFetch) ? [rt(join(rtDir, "scr_dyn_invoke.c"))] : []),
3093
- ...(opts.dc ? [rt(join(rtDir, "scr_dc.c"))] : []),
3094
- ...(opts.dynAsync || opts.dynInvoke || opts.dc || opts.fileHandle || nativeFetch ? [rt(join(rtDir, "scr_async_dyn.c"))] : []),
3095
- // The zlib UNIT (scr_zlib.c) gates on zlib.* IR use; the LINK (system
3096
- // libz on the default host-clang build, vendored objects on Zig builds)
3097
- // also serves the native fetch's gzip decoder — spread exactly once.
3098
- ...(opts.zlib
3099
- ? isZigDriver(driver)
3100
- ? ["-I", vendorZlibDir(), rt(join(rtDir, "scr_zlib.c")), ...zlibObjects]
3101
- : [rt(join(rtDir, "scr_zlib.c"))]
3102
- : nativeFetch
3103
- ? isZigDriver(driver)
3104
- ? ["-I", vendorZlibDir(), ...zlibObjects]
3105
- : []
3106
- : []),
3107
- // The zlib ↔ island bridge: only when BOTH halves are in the build
3108
- // (the scr_inspect_island.c pattern) — the emitted main calls its
3109
- // installer exactly then.
3110
- ...(opts.zlib && opts.dynamic ? [rt(join(rtDir, "scr_zlib_island.c"))] : []),
3111
- ...(opts.events ? [rt(join(rtDir, "scr_events.c")), rt(join(rtDir, "scr_readline.c"))] : []),
3112
- ...(opts.emitter ? [rt(join(rtDir, "scr_events_emitter.c"))] : []),
3113
- // The checked-dynamic HANDLE support unit (listener gate + runtime
3114
- // adapter closures): every referencing unit is one of the emitter or
3115
- // net families (http implies net), so handle-free binaries keep
3116
- // their exact size class.
3117
- ...(opts.emitter || net ? [rt(join(rtDir, "scr_dyn_handle.c"))] : []),
3118
- ...(opts.symbol ? [rt(join(rtDir, "scr_symbol.c"))] : []),
3119
- ...(opts.assert && opts.bigint ? [rt(join(rtDir, "scr_bigint_assert.c"))] : []),
3120
- ...(opts.qs ? [rt(join(rtDir, "scr_qs.c"))] : []),
3121
- ...(opts.parseArgs ? [rt(join(rtDir, "scr_util.c"))] : []),
3122
- ...(opts.parseArgs && opts.symbol ? [rt(join(rtDir, "scr_util_compare.c"))] : []),
3123
- ...(opts.parseArgs && opts.inspect && opts.dynAsync ? [rt(join(rtDir, "scr_util_style.c"))] : []),
3124
- ...(opts.stream ? [rt(join(rtDir, "scr_stream.c"))] : []),
3125
- // The readiness-poller backends (scr_platform.h): kqueue on macOS/BSD,
3126
- // epoll on Linux, WSAPoll on Windows — each TU is empty off its
3127
- // platform, so all three link whenever a poller-using unit does and
3128
- // the others cost nothing (ws2_32 rides the unconditional win32 libs
3129
- // above).
3130
- ...(net || opts.dgram
3131
- ? [
3132
- rt(join(rtDir, "scr_loop_kqueue.c")),
3133
- rt(join(rtDir, "scr_loop_epoll.c")),
3134
- rt(join(rtDir, "scr_loop_wsapoll.c")),
3135
- ]
3136
- : []),
3137
- ...(net ? [rt(join(rtDir, "scr_net.c"))] : []),
3138
- ...(http ? [rt(join(rtDir, "scr_http.c"))] : []),
3139
- ...(opts.http2 ?? false ? [rt(join(rtDir, "scr_http2.c"))] : []),
3140
- ...(opts.dgram ? [rt(join(rtDir, "scr_dgram.c"))] : []),
3141
- ...(opts.watch ? [rt(join(rtDir, "scr_watch.c"))] : []),
3142
- ...(opts.foreignFfi ? [rt(join(rtDir, "scr_ffi_queue.c"))] : []),
3143
- ...(opts.nodeTest ? [rt(join(rtDir, "scr_test.c"))] : []),
3144
- // The CA-store unit rides its own gate OR the tls one: scr_tls.c
3145
- // references its default-set override unconditionally.
3146
- ...(tlsCa ? [rt(join(rtDir, "scr_tls_ca.c"))] : []),
3147
- ...(tlsArchive
3148
- ? [
3149
- "-I", join(vendorTlsDir(), "include"),
3150
- rt(join(rtDir, "scr_tls.c")),
3151
- tlsArchive,
3152
- // mbedTLS's win32 entropy poll is BCryptGenRandom (bcrypt.h).
3153
- // The unconditional win32 libs above do not carry it.
3154
- // Never present on the default path, so the historical TLS
3155
- // link line cannot change.
3156
- ...(targetPlatform(driver) === "win32" ? ["-lbcrypt"] : []),
3157
- ]
3158
- : []),
3159
- // scr_tls_ca.c enumerates and PEM-encodes Windows system-store entries.
3160
- // This is independent of the mbedTLS archive: getCACertificates-only
3161
- // programs need crypt32 too, while TLS programs imply the CA unit.
3162
- ...(tlsCa && targetPlatform(driver) === "win32" ? ["-lcrypt32"] : []),
3163
- // Static fetch is the engine-free half of scr_fetch.c. Dynamic builds
3164
- // compile the same source beside scr_island.c below, where its
3165
- // SCR_DYNAMIC half installs the full web surface.
3166
- ...(nativeFetch && !dynamic ? [rt(join(rtDir, "scr_fetch.c"))] : []),
3167
- ...(engineArchive
3168
- ? [
3169
- "-DSCR_DYNAMIC",
3170
- "-I", vendorEngineDir(),
3171
- rt(join(rtDir, "scr_island.c")),
3172
- rt(join(rtDir, "scr_web.c")),
3173
- // The one unit referencing BOTH the island and the inspect
3174
- // engine (insp.jsval): linked exactly when both halves are.
3175
- ...(opts.inspect ? [rt(join(rtDir, "scr_inspect_island.c"))] : []),
3176
- // fetch: the NATIVE bridge by default (its socket/tls/zlib
3177
- // dependencies joined the link above); the curl REFERENCE
3178
- // (SCRIPTC_FETCH_CURL=1) keeps the historical system -lcurl /
3179
- // linux soname-stub arms for one release.
3180
- ...(nativeFetch ? [rt(join(rtDir, "scr_fetch.c"))] : []),
3181
- // The island's node:http/https CLIENT bridge (scr_net_island.c):
3182
- // the one TU referencing both the socket units and the engine —
3183
- // compiled beside the native fetch (scr_fetch_install registers
3184
- // it) and whenever the embedded graph imports node:http/https
3185
- // (the emitted main calls scr_net_island_install exactly then).
3186
- ...(netIsland ? [rt(join(rtDir, "scr_net_island.c"))] : []),
3187
- ...(curlFetch
3188
- ? curlStubDir !== null
3189
- ? ["-I", join(vendorCurlDir(), "include"), rt(join(rtDir, "scr_fetch_curl.c")), `-L${curlStubDir}`, "-lcurl"]
3190
- : [rt(join(rtDir, "scr_fetch_curl.c")), "-lcurl"]
3191
- : []),
3192
- engineArchive,
3193
- // Linux's libm is appended after every input below for GNU ld's
3194
- // left-to-right archive resolution. Other dynamic targets keep
3195
- // the historical engine-adjacent spelling.
3196
- ...(driver.linkArgs.includes("-lm") ? [] : ["-lm"]),
3197
- // The PE stack reserve, pinned to the 8MB POSIX main-stack
3198
- // geometry ISL_MAIN_STACK_BUDGET is sized against (4MB engine
3199
- // budget + 4MB excursion margin) — quickjs-ng's own CMake makes
3200
- // the same 8MB choice on Windows. Not left to the driver:
3201
- // classic mingw ld defaults to 2MB (which the budget would blow
3202
- // straight past); zig's lld happens to default to 16MB today,
3203
- // but that is nobody's contract.
3204
- ...(targetPlatform(driver) === "win32" ? ["-Wl,--stack,8388608"] : []),
3205
- ]
3206
- : []),
3207
- // A .ll program TU (the LLVM backend) deliberately carries no target
3208
- // triple (byte-stable output; clang supplies the host/SCRIPTC_TARGET
3209
- // triple exactly as it does for .c) — silence the -Woverride-module
3210
- // note about that. Never present for .c inputs, so the historical C
3211
- // command line cannot change by a byte.
3212
- ...(opts.cPath.endsWith(".ll") ? ["-Wno-override-module"] : []),
3213
- ...(build.compilerVisibleSource !== undefined && build.programPath !== undefined
3214
- ? [
3215
- `-ffile-prefix-map=${build.programPath}=${build.compilerVisibleSource}`,
3216
- "-iquote",
3217
- dirname(resolve(build.compilerVisibleSource)),
3218
- ]
3219
- : []),
3220
- build.programPath ?? opts.cPath,
3221
- ...(opts.linkInputs ?? []),
3222
- ...(opts.systemLibraries ?? []).map((name) => `-l${name}`),
3223
- ...(opts.frameworks ?? []).flatMap(name => ["-framework", name]),
3224
- // GNU ld resolves libraries from left to right and commonly enables
3225
- // --as-needed: host-clang libz must follow scr_zlib.c/scr_fetch.c and every
3226
- // generated/native input that references inflate symbols. Cross
3227
- // and targetless Zig builds use vendored zlib objects in the input section above.
3228
- ...(((opts.zlib ?? false) || nativeFetch) && !isZigDriver(driver)
3229
- ? ["-lz"]
3230
- : []),
3231
- // glibc keeps libm separate from libc. This must trail the generated
3232
- // program and every native FFI input because GNU ld resolves archives
3233
- // from left to right.
3234
- ...driver.linkArgs,
3235
- ...executableLinkFlags,
3236
- "-o", build.outPath ?? opts.outPath,
3237
- ];
3238
- // Runtime-object flags. Program compilation and dependency discovery add
3239
- // the dev sanitizer override below so both cache identities match reality.
3240
- const cflags = [
3241
- "-std=c11",
3242
- ...debugFlags,
3243
- ...driver.targetArgs,
3244
- ...threadArgs,
3245
- ...(sanitize
3246
- ? ["-O1", "-fsanitize=address", "-DSCR_RC_AUDIT"]
3247
- : [optimization === "dev" ? "-O0" : "-O2"]),
3248
- ...executableSectionFlags.compile,
3249
- ...(opts.textDecoderLegacy ? ["-DSCR_TEXT_DECODER_LEGACY"] : []),
3250
- "-fno-math-errno",
3251
- "-fno-strict-aliasing", // the emitted object model type-puns — see buildArgs
3252
- "-Wno-deprecated-declarations",
3253
- "-I", rtDir,
3254
- ...(regex || dynamic ? ["-I", vendorEngineDir()] : []),
3255
- ...(zlibObjects.length > 0 ? ["-I", vendorZlibDir()] : []),
3256
- ...(curlStubDir !== null ? ["-I", join(vendorCurlDir(), "include")] : []),
3257
- ...(tlsArchive !== null ? ["-I", join(vendorTlsDir(), "include")] : []),
3258
- ...(dynamic ? ["-DSCR_DYNAMIC"] : []),
3259
- ];
3260
- // Keep sanitizer runtime objects optimized in both postures. Large dev
3261
- // programs still compile at O0, avoiding an expensive LLVM optimization
3262
- // pass while retaining ASan and reference-count checks in every runtime unit.
3263
- const separateSanitizedProgram = sanitize && optimization === "dev";
3264
- const programCompilerArgs = [
3265
- ...cflags,
3266
- ...(separateSanitizedProgram ? ["-O0"] : []),
3267
- ...(opts.cPath.endsWith(".ll") ? ["-Wno-override-module"] : []),
3268
- ];
3269
- const programSourceExtension = opts.cPath.endsWith(".ll") ? ".ll" : ".c";
3270
- const ccName = driver.argv.join(" ");
3271
- const runClang = async (args) => {
3272
- try {
3273
- await execFileAsync(driver.argv[0] ?? "clang", [...driver.argv.slice(1), ...args]);
3274
- }
3275
- catch (err) {
3276
- const stderr = subprocessFailureDetail(err);
3277
- const guidance = (opts.linkInputs?.length ?? 0) > 0 ||
3278
- (opts.frameworks?.length ?? 0) > 0 ||
3279
- (opts.systemLibraries?.length ?? 0) > 0
3280
- ? "This build includes native FFI link inputs. Check that every symbol and system library exists, " +
3281
- "that archive/object ordering is correct, and that each input matches the selected target."
3282
- : `Check the supplied native source and the selected ${ccName} toolchain.`;
3283
- throw new CcCompileError(ccName, stderr, `${ccName} failed compiling ${opts.cPath}.\n` +
3284
- `${guidance}\n\n${stderr}`);
3285
- }
3286
- };
3287
- const buildExecutable = async (runtimeInput, build = {}) => {
3288
- if (!separateSanitizedProgram) {
3289
- await runClang(buildArgs(runtimeInput, build));
3290
- return;
3291
- }
3292
- const stage = await mkdtemp(join(tmpdir(), "scriptc-sanitized-program-"));
3293
- try {
3294
- const object = join(stage, "program.o");
3295
- await runClang([
3296
- ...programCompilerArgs,
3297
- ...(build.compilerVisibleSource === undefined ? [] : [
3298
- `-ffile-prefix-map=${build.programPath}=${build.compilerVisibleSource}`,
3299
- "-iquote", dirname(resolve(build.compilerVisibleSource)),
3300
- ]),
3301
- "-c", build.programPath ?? opts.cPath, "-o", object,
3302
- ]);
3303
- await runClang(buildArgs(runtimeInput, { programPath: object, outPath: build.outPath ?? opts.outPath }));
3304
- if (darwinDebugSymbols)
3305
- await createDarwinDebugSymbols(build.outPath ?? opts.outPath);
3306
- }
3307
- finally {
3308
- await rm(stage, { recursive: true, force: true });
3309
- }
3310
- };
3311
- const runUncachedBuild = async () => {
3312
- const privateVendorRoot = transientVendorRoot ?? join(tmpdir(), `scriptc-vendor-fallback-${process.pid}-${Math.random().toString(36).slice(2)}`);
3313
- try {
3314
- await materializeVendorPrerequisites(undefined, privateVendorRoot);
3315
- await buildExecutable((p) => p);
3316
- }
3317
- finally {
3318
- await rm(privateVendorRoot, { recursive: true, force: true }).catch(() => undefined);
3319
- }
3320
- };
3321
- let runtimeCompilerInvocation = null;
3322
- let programCompilerInvocation = null;
3323
- let payloadMetadata = null;
3324
- let compileMetadataStamp = null;
3325
- const compileMetadataKey = persistentCache === null || process.env["SCRIPTC_TEST_TRUST_COMPILER_WRAPPER"] === "1"
3326
- ? null
3327
- : nativeMetadataKey("compile", [
3328
- cacheTargetIdentity(driver),
3329
- toolchainEnv,
3330
- implicitToolchain ?? "<uncached>",
3331
- driver.argv,
3332
- cflags,
3333
- programCompilerArgs,
3334
- programSourceExtension,
3335
- ]);
3336
- if (persistentCache !== null) {
3337
- try {
3338
- // These probes inspect disjoint inputs. Start the payload reads here as
3339
- // well so runtime hashing and clang's dry-run traces overlap instead of
3340
- // forming a serial prelude before every cache lookup.
3341
- payloadMetadata = Promise.all([
3342
- Promise.resolve(toolchainMetadataStamp?.values["compilerVersion"] ??
3343
- ccVersion(driver.argv, toolchainEnv, true)),
3344
- localArtifact === null
3345
- ? runtimeFingerprint(rtDir)
3346
- : Promise.resolve(localArtifact.runtimeHash),
3347
- localArtifact === null
3348
- ? readFile(opts.cPath)
3349
- : Promise.resolve(localArtifact.programBytes),
3350
- ]);
3351
- compileMetadataStamp = compileMetadataKey === null
3352
- ? null
3353
- : await readNativeMetadataStamp(persistentCache.root, compileMetadataKey);
3354
- if (compileMetadataStamp !== null) {
3355
- runtimeCompilerInvocation = compileMetadataStamp.values["runtimeInvocation"] ?? null;
3356
- programCompilerInvocation = compileMetadataStamp.values["programInvocation"] ?? null;
3357
- if (runtimeCompilerInvocation === null || programCompilerInvocation === null) {
3358
- compileMetadataStamp = null;
3359
- }
3360
- }
3361
- if (compileMetadataStamp === null) {
3362
- const [runtimeInvocation, programInvocation] = await Promise.all([
3363
- effectiveCompilerInvocationFingerprint(driver, toolchainEnv, cflags),
3364
- programSourceExtension === ".ll" || separateSanitizedProgram
3365
- ? effectiveCompilerInvocationFingerprint(driver, toolchainEnv, programCompilerArgs, programSourceExtension)
3366
- : Promise.resolve(null),
3367
- ]);
3368
- runtimeCompilerInvocation = runtimeInvocation;
3369
- programCompilerInvocation = programInvocation ?? runtimeInvocation;
3370
- if (compileMetadataKey !== null) {
3371
- compileMetadataStamp = await publishNativeMetadataStamp(persistentCache.root, compileMetadataKey, {
3372
- runtimeInvocation: runtimeCompilerInvocation,
3373
- programInvocation: programCompilerInvocation,
3374
- }, [
3375
- ...fingerprintDependencyPaths(runtimeCompilerInvocation),
3376
- ...fingerprintDependencyPaths(programCompilerInvocation),
3377
- ], [runtimeCompilerInvocation, programCompilerInvocation]);
3378
- }
3379
- }
3380
- }
3381
- catch (error) {
3382
- // Preserve the uncached build for wrappers that compile successfully but
3383
- // cannot provide a dry-run trace for the real build flavor.
3384
- if (cacheWarmOnly) {
3385
- throw new Error("native cache warming could not validate the compiler invocation", {
3386
- cause: error,
3387
- });
3388
- }
3389
- persistentCache = null;
3390
- }
3391
- }
3392
- if (persistentCache === null) {
3393
- // The direct uncached command is the source-of-truth executable recipe.
3394
- await runUncachedBuild();
3395
- return;
3396
- }
3397
- let cv;
3398
- let fingerprint;
3399
- let cBytes;
3400
- try {
3401
- [cv, fingerprint, cBytes] = await (payloadMetadata ?? Promise.all([
3402
- ccVersion(driver.argv, toolchainEnv, true),
3403
- runtimeFingerprint(rtDir),
3404
- readFile(opts.cPath),
3405
- ]));
3406
- }
3407
- catch (error) {
3408
- // A version/fingerprint probe is an optimization boundary. If the compiler
3409
- // itself can still compile, preserve the pre-cache behavior instead of
3410
- // surfacing a metadata command's failure as the build result.
3411
- if (cacheWarmOnly) {
3412
- throw new Error("native cache warming could not validate cache inputs", {
3413
- cause: error,
3414
- });
3415
- }
3416
- await runUncachedBuild();
3417
- return;
3418
- }
3419
- // Caller-supplied native inputs can all hide mutable dependencies: `-l`
3420
- // resolves through ambient search paths, while a thin archive or linker
3421
- // script can retain identical top-level bytes as its referenced files are
3422
- // rebuilt. Keep the safe runtime-object cache, but force a fresh final link
3423
- // whenever the caller supplies either form.
3424
- let cacheCompleteArtifact = !cacheWarmOnly &&
3425
- cachePolicy.completeArtifacts &&
3426
- (opts.linkInputs?.length ?? 0) === 0 &&
3427
- (opts.frameworks?.length ?? 0) === 0 &&
3428
- (opts.systemLibraries?.length ?? 0) === 0;
3429
- let programDependencies = null;
3430
- const linkProbeArgs = [
3431
- ...(sanitize ? ["-fsanitize=address"] : []),
3432
- ...threadArgs,
3433
- ...(targetPlatform(driver) === "win32"
3434
- ? ["-ladvapi32", "-liphlpapi", "-lws2_32"]
3435
- : []),
3436
- ...(tls && targetPlatform(driver) === "win32" ? ["-lbcrypt"] : []),
3437
- ...(tlsCa && targetPlatform(driver) === "win32" ? ["-lcrypt32"] : []),
3438
- ...(curlFetch && driver.target === null ? ["-lcurl"] : []),
3439
- ...(dynamic && !driver.linkArgs.includes("-lm") ? ["-lm"] : []),
3440
- ...(((opts.zlib ?? false) || nativeFetch) && !isZigDriver(driver) ? ["-lz"] : []),
3441
- ...driver.linkArgs,
3442
- ...executableLinkFlags,
3443
- ];
3444
- // Both the wrapper dry run and dependency trace need the real build's
3445
- // compile/link flag shape: wrappers commonly inject flags or native inputs
3446
- // conditionally on optimization, sanitizer, dynamic, or platform switches.
3447
- const effectiveLinkInvocationArgs = [
3448
- ...(separateSanitizedProgram ? cflags : programCompilerArgs),
3449
- ...(targetPlatform(driver) === "win32"
3450
- ? ["-ladvapi32", "-liphlpapi", "-lws2_32"]
3451
- : []),
3452
- ...(tls && targetPlatform(driver) === "win32" ? ["-lbcrypt"] : []),
3453
- ...(tlsCa && targetPlatform(driver) === "win32" ? ["-lcrypt32"] : []),
3454
- ...(curlStubDir !== null ? [`-L${curlStubDir}`] : []),
3455
- ...(curlFetch && driver.target === null ? ["-lcurl"] : []),
3456
- ...(dynamic && !driver.linkArgs.includes("-lm") ? ["-lm"] : []),
3457
- ...(dynamic && targetPlatform(driver) === "win32"
3458
- ? ["-Wl,--stack,8388608"]
3459
- : []),
3460
- ...(((opts.zlib ?? false) || nativeFetch) && !isZigDriver(driver) ? ["-lz"] : []),
3461
- ...driver.linkArgs,
3462
- ...executableLinkFlags,
3463
- ];
3464
- // A complete hit is checked before cross-target curl's generated import stub
3465
- // is materialized. Its -L spelling still joins the dry-run identity, while
3466
- // the real trace omits only that not-yet-existing scriptc-owned directory.
3467
- const linkTraceInvocationArgs = curlStubDir === null
3468
- ? effectiveLinkInvocationArgs
3469
- : effectiveLinkInvocationArgs.filter((arg) => arg !== `-L${curlStubDir}`);
3470
- let implicitLinker = null;
3471
- let preBuildDependencies = null;
3472
- let localArtifactDependencyPaths = null;
3473
- let linkMetadataStamp = null;
3474
- const linkMetadataKey = process.env["SCRIPTC_TEST_TRUST_COMPILER_WRAPPER"] === "1"
3475
- ? null
3476
- : nativeMetadataKey("link", [
3477
- cacheTargetIdentity(driver),
3478
- toolchainEnv,
3479
- implicitToolchain ?? "<uncached>",
3480
- runtimeCompilerInvocation ?? "<uncached>",
3481
- programCompilerInvocation ?? "<uncached>",
3482
- driver.argv,
3483
- linkProbeArgs,
3484
- effectiveLinkInvocationArgs,
3485
- linkTraceInvocationArgs,
3486
- ...(programShardMergeIdentity === null ? [] : [programShardMergeIdentity]),
3487
- ]);
3488
- if (cacheCompleteArtifact) {
3489
- try {
3490
- // Header discovery and linker tracing are independent subprocess trees.
3491
- // Running them together removes one complete probe round-trip from both
3492
- // cache hits and ordinary edit/build misses without changing either key.
3493
- linkMetadataStamp = linkMetadataKey === null
3494
- ? null
3495
- : await readNativeMetadataStamp(persistentCache.root, linkMetadataKey);
3496
- if (linkMetadataStamp !== null) {
3497
- implicitLinker = linkMetadataStamp.values["implicitLinker"] ?? null;
3498
- if (implicitLinker === null)
3499
- linkMetadataStamp = null;
3500
- }
3501
- [programDependencies, implicitLinker] = await Promise.all([
3502
- translationUnitDependencyFingerprint(driver, programCompilerArgs, opts.cPath, cBytes, toolchainEnv),
3503
- linkMetadataStamp === null
3504
- ? implicitLinkerFingerprint(driver, toolchainEnv, linkProbeArgs, effectiveLinkInvocationArgs, linkTraceInvocationArgs)
3505
- : Promise.resolve(implicitLinker),
3506
- ]);
3507
- if (linkMetadataStamp === null && linkMetadataKey !== null) {
3508
- linkMetadataStamp = await publishNativeMetadataStamp(persistentCache.root, linkMetadataKey, { implicitLinker }, fingerprintDependencyPaths(implicitLinker), [implicitLinker]);
3509
- }
3510
- preBuildDependencies = await snapshotLocalArtifactDependencies([
3511
- ...(await runtimeFingerprintInputPaths(rtDir)),
3512
- ...(toolchainMetadataStamp?.dependencies.map((dependency) => dependency.path) ??
3513
- fingerprintDependencyPaths(implicitToolchain)),
3514
- ...(compileMetadataStamp?.dependencies.map((dependency) => dependency.path) ?? []),
3515
- ...(linkMetadataStamp?.dependencies.map((dependency) => dependency.path) ??
3516
- fingerprintDependencyPaths(implicitLinker)),
3517
- ...fingerprintDependencyPaths(programDependencies),
3518
- ...(programShardMergeIdentity === null
3519
- ? []
3520
- : fingerprintDependencyPaths(programShardMergeIdentity)),
3521
- ]);
3522
- // Every content-bearing fingerprint was computed before this metadata
3523
- // snapshot. Re-read those exact files now so the snapshot cannot certify
3524
- // bytes that changed after hashing but before the final compile starts.
3525
- if (!(await fingerprintDependenciesStillMatch([
3526
- implicitToolchain,
3527
- runtimeCompilerInvocation,
3528
- programCompilerInvocation,
3529
- implicitLinker,
3530
- programDependencies,
3531
- ...(programShardMergeIdentity === null ? [] : [programShardMergeIdentity]),
3532
- ])) ||
3533
- await runtimeFingerprint(rtDir).catch(() => null) !== fingerprint ||
3534
- !(await Promise.all([toolchainMetadataStamp, compileMetadataStamp, linkMetadataStamp]
3535
- .filter((stamp) => stamp !== null)
3536
- .map((stamp) => nativeArtifactDependenciesStillMatch(stamp.dependencies)))).every(Boolean)) {
3537
- throw new CacheInputsChangedError();
3538
- }
3539
- if (localArtifact !== null) {
3540
- // Native metadata stamps persist their dependency paths across CLI
3541
- // processes; fingerprintDependencyPaths deliberately does not. Build
3542
- // the output-local stamp from this complete validated snapshot so a
3543
- // source edit in a fresh process cannot replace it with only the two
3544
- // process-local fallback paths.
3545
- localArtifactDependencyPaths = [
3546
- localArtifact.compilerPath,
3547
- dirname(resolve(opts.cPath)),
3548
- ...preBuildDependencies.map((dependency) => dependency.path),
3549
- ];
3550
- }
3551
- }
3552
- catch {
3553
- // Program-header discovery and linker tracing are both required for a
3554
- // complete hit. Runtime objects remain safely cacheable if either probe
3555
- // is unavailable.
3556
- cacheCompleteArtifact = false;
3557
- preBuildDependencies = null;
3558
- localArtifactDependencyPaths = null;
3559
- }
3560
- }
3561
- // Warm-only builds deliberately do not need linker/header identity for a
3562
- // complete executable, but they still need a stable runtime-object key.
3563
- // The ordinary complete-artifact path computes these values above.
3564
- if (cacheWarmOnly && preBuildDependencies === null) {
3565
- try {
3566
- const [dependencies, invocation] = await Promise.all([
3567
- translationUnitDependencyFingerprint(driver, programCompilerArgs, opts.cPath, cBytes, toolchainEnv),
3568
- effectiveCompilerInvocationFingerprint(driver, toolchainEnv, cflags),
3569
- ]);
3570
- programDependencies = dependencies;
3571
- if (runtimeCompilerInvocation === null)
3572
- runtimeCompilerInvocation = invocation;
3573
- }
3574
- catch (error) {
3575
- throw new Error("native cache warming could not validate runtime-object inputs", {
3576
- cause: error,
3577
- });
3578
- }
3579
- }
3580
- const binDir = join(persistentCache.root, "bin");
3581
- let keyHex = null;
3582
- let cachedBin = null;
3583
- if (cacheCompleteArtifact) {
3584
- // The key sees the full command line with the two program-specific paths
3585
- // normalized out. The C bytes are hashed separately; Darwin additionally
3586
- // keys the output basename because ld embeds it in the ad-hoc signature.
3587
- // Runtime and vendor paths stay verbatim — their contents are covered by
3588
- // the fingerprint and the pin.
3589
- const identityArgs = buildArgs((p) => p).map((a) => a === opts.cPath ? "<program.c>" : a === opts.outPath ? "<out>" : a);
3590
- const key = createHash("sha256")
3591
- // Sharded dev builds need the v10 identity below. Canonical single-TU
3592
- // builds retain v9 so adding the opt-in mode does not evict release
3593
- // binaries compiled by an earlier scriptc.
3594
- .update(programShards === null ? "bin-v9\0" : "bin-v10\0")
3595
- .update(cacheTargetIdentity(driver)).update("\0")
3596
- .update(toolchainEnv).update("\0")
3597
- .update(implicitToolchain).update("\0")
3598
- .update(runtimeCompilerInvocation).update("\0")
3599
- .update(programCompilerInvocation).update("\0")
3600
- .update(implicitLinker).update("\0")
3601
- .update(programDependencies).update("\0")
3602
- .update(persistentCache.identity).update("\0")
3603
- // Preserve both the spelling clang sees (__FILE__) and the location used
3604
- // to resolve relative includes. The top-level bytes are not sufficient.
3605
- .update(opts.cPath).update("\0")
3606
- .update(resolve(opts.cPath)).update("\0")
3607
- .update(targetPlatform(driver) === "darwin" ? basename(opts.outPath) : "<out>").update("\0")
3608
- // The driver spelling joins the version string: `zig cc --version`
3609
- // reports the clang underneath and could otherwise collide with a
3610
- // same-version host clang.
3611
- .update(ccName).update("\0")
3612
- .update(cv).update("\0")
3613
- .update(fingerprint).update("\0")
3614
- .update(identityArgs.join("\x1f")).update("\0")
3615
- .update(cBytes);
3616
- if (programShards !== null) {
3617
- updateProgramShardCacheIdentity(key, programShards, programPublicSymbols, programShardMergeIdentity ?? undefined);
3618
- }
3619
- keyHex = key.digest("hex");
3620
- cachedBin = join(binDir, keyHex);
3621
- const tmpOut = privateSiblingPath(opts.outPath, "bin-hit");
3622
- try {
3623
- // NEVER copy over outPath in place: overwriting an already-executed
3624
- // signed binary invalidates the kernel's per-vnode code-signature cache
3625
- // on macOS and the next exec dies with SIGKILL. Copy to a fresh inode
3626
- // and rename it into place instead.
3627
- if (!(await copyValidCachedFile(cachedBin, tmpOut))) {
3628
- throw new Error("invalid cached executable");
3629
- }
3630
- if (darwinDebugSymbols) {
3631
- const cachedSymbols = `${cachedBin}.dsym`;
3632
- const symbolsCopy = privateSiblingPath(opts.outPath, "dsym-hit");
3633
- try {
3634
- if (!(await copyValidCachedFile(cachedSymbols, symbolsCopy)))
3635
- throw new Error("invalid cached dSYM");
3636
- const bytes = await readFile(symbolsCopy);
3637
- // A concurrent publisher may replace either payload. The sidecar
3638
- // also names its binary digest so a mixed pair always misses.
3639
- if (bytes.subarray(0, 32).toString("hex") !== await fileDigest(tmpOut))
3640
- throw new Error("mismatched cached dSYM");
3641
- await installDarwinDebugSymbols(bytes.subarray(32), opts.outPath);
3642
- }
3643
- finally {
3644
- await rm(symbolsCopy, { force: true });
3645
- }
3646
- }
3647
- // Match a fresh linker output under the caller's current umask. Reusing a
3648
- // cache entry populated by a less restrictive shell must not widen access.
3649
- await chmod(tmpOut, 0o777 & ~process.umask());
3650
- await rename(tmpOut, opts.outPath);
3651
- if (localArtifact !== null && localArtifactDependencyPaths !== null) {
3652
- const stamp = await publishLocalArtifactStamp(localArtifact.stampPath, opts.outPath, localArtifact.key, localArtifactDependencyPaths, [dirname(resolve(opts.cPath))], [persistentCache.root], darwinDebugSymbols).catch(() => null);
3653
- if (stamp !== null) {
3654
- await opts.onArtifactReady?.({ dependencies: stamp.dependencies }).catch(() => undefined);
3655
- }
3656
- }
3657
- return; // hit: the program/runtime payload compile and link were skipped
3658
- }
3659
- catch {
3660
- await rm(tmpOut, { force: true }).catch(() => undefined);
3661
- /* miss — build below, then publish */
3662
- }
3663
- }
3664
- // Miss: link the program's own TU against cached per-flavor runtime objects.
3665
- // Collect the runtime sources this build actually compiles (the same
3666
- // conditionals as the command line, by construction).
3667
- const rtInputs = [];
3668
- buildArgs((p) => {
3669
- rtInputs.push(p);
3670
- return p;
3671
- });
3672
- const buildDir = await mkdtemp(join(tmpdir(), "scriptc-cache-build-"));
3673
- try {
3674
- await materializeVendorPrerequisites(join(buildDir, "vendor-inputs"));
3675
- // Freeze the exact bytes used for the key. Generated TUs live at stable
3676
- // paths under .scriptc/, so two builds can otherwise overwrite that path
3677
- // between hashing and clang and publish one invocation's code under the
3678
- // other's key. The prefix map preserves the original __FILE__/debug-file
3679
- // spelling while clang reads this invocation-private snapshot.
3680
- const programPath = join(buildDir, `program${programSourceExtension}`);
3681
- // Preserve the caller-visible basename while keeping Darwin builds on a
3682
- // private inode: ld uses this spelling as the embedded ad-hoc signing
3683
- // identifier. Other targets retain the basename-independent cache key.
3684
- const privateOut = join(buildDir, targetPlatform(driver) === "darwin"
3685
- ? basename(opts.outPath)
3686
- : process.platform === "win32"
3687
- ? "artifact.exe"
3688
- : "artifact");
3689
- await writeFile(programPath, cBytes);
3690
- let objects = null;
3691
- let cacheInputsStable = true;
3692
- let strictObjectVerification = null;
3693
- const objectImplicitToolchainStillMatches = () => {
3694
- if (preBuildDependencies !== null) {
3695
- return nativeArtifactDependenciesStillMatch(preBuildDependencies);
3696
- }
3697
- // Complete-artifact caching can be disabled by caller-owned native
3698
- // inputs while the safe runtime-object tier remains active. Preserve its
3699
- // strict discovery fallback in that posture.
3700
- strictObjectVerification ??= Promise.all([
3701
- runtimeFingerprint(rtDir),
3702
- implicitToolchainFingerprint(driver, toolchainEnv),
3703
- effectiveCompilerInvocationFingerprint(driver, toolchainEnv, cflags),
3704
- ]).then(([currentRuntime, currentImplicit, currentInvocation]) => currentRuntime === fingerprint &&
3705
- currentImplicit === implicitToolchain &&
3706
- currentInvocation === runtimeCompilerInvocation, () => false);
3707
- return strictObjectVerification;
3708
- };
3709
- try {
3710
- const cached = await ensureRuntimeObjects(persistentCache.root, driver.argv, cflags, rtInputs, `obj-v5\0${cacheTargetIdentity(driver)}\0${toolchainEnv}\0${implicitToolchain}\0${runtimeCompilerInvocation}\0${ccName}\0${cv}\0${fingerprint}\0`, async () => await objectImplicitToolchainStillMatches(), cacheWarmPaths);
3711
- objects = await stageRuntimeObjects(cached, join(buildDir, "runtime-objects"));
3712
- }
3713
- catch (err) {
3714
- if (err instanceof CacheInputsChangedError)
3715
- cacheInputsStable = false;
3716
- if (cacheWarmOnly) {
3717
- throw new Error("native cache warming could not persist runtime objects", {
3718
- cause: err,
3719
- });
3720
- }
3721
- objects = null; // cache trouble is never a build failure
3722
- }
3723
- const compileShardedProgram = async () => {
3724
- if (programShards === null || programPublicSymbols === undefined ||
3725
- programCompilerInvocation === null || implicitCompileToolchain === null)
3726
- return null;
3727
- try {
3728
- const programDependencyHash = programDependencies ??
3729
- await translationUnitDependencyFingerprint(driver, programCompilerArgs, opts.cPath, cBytes, toolchainEnv);
3730
- const stem = basename(opts.cPath, ".ll");
3731
- const entries = programShards.map((shard, index) => {
3732
- const sourcePath = join(buildDir, shard.name);
3733
- const staged = join(buildDir, `${stem}.program-${index.toString().padStart(3, "0")}.o`);
3734
- const key = createHash("sha256")
3735
- .update("exe-program-shard-v1\0")
3736
- .update(cacheTargetIdentity(driver)).update("\0")
3737
- .update(toolchainEnv).update("\0")
3738
- .update(implicitCompileToolchain).update("\0")
3739
- .update(programCompilerInvocation).update("\0")
3740
- .update(persistentCache.identity).update("\0")
3741
- .update(driver.argv.join("\x1f")).update("\0")
3742
- .update(cv).update("\0")
3743
- .update(fingerprint).update("\0")
3744
- .update(programDependencyHash).update("\0")
3745
- .update(programCompilerArgs.join("\x1f")).update("\0")
3746
- .update(opts.cPath).update("\0")
3747
- .update(resolve(opts.cPath)).update("\0")
3748
- .update(shard.name).update("\0")
3749
- .update(shard.source)
3750
- .digest("hex");
3751
- return {
3752
- ...shard,
3753
- sourcePath,
3754
- staged,
3755
- cachePath: join(persistentCache.root, "program-shard", key),
3756
- missed: false,
3757
- };
3758
- });
3759
- const shardWidth = Math.min(8, availableParallelism());
3760
- for (let i = 0; i < entries.length; i += shardWidth) {
3761
- await Promise.all(entries.slice(i, i + shardWidth).map(async (entry) => {
3762
- await writeFile(entry.sourcePath, entry.source);
3763
- if (await copyValidCachedFile(entry.cachePath, entry.staged))
3764
- return;
3765
- entry.missed = true;
3766
- await runClang([
3767
- ...programCompilerArgs,
3768
- `-ffile-prefix-map=${entry.sourcePath}=${opts.cPath}`,
3769
- "-c",
3770
- entry.sourcePath,
3771
- "-o",
3772
- entry.staged,
3773
- ]);
3774
- }));
3775
- }
3776
- const arArgv = isZigDriver(driver) ? [driver.argv[0], "ar"] : ["ar"];
3777
- const merged = await localizeLibraryObjects(driver, arArgv, buildDir, entries.map((entry) => entry.staged), [], programPublicSymbols, `${stem}.program`);
3778
- const publishable = entries.filter((entry) => entry.missed);
3779
- if (publishable.length > 0) {
3780
- try {
3781
- const [currentRuntime, currentFingerprints, currentInvocation, currentDependencies, currentCompiler, currentMerge] = await Promise.all([
3782
- runtimeFingerprint(rtDir),
3783
- implicitToolchainFingerprints(driver, toolchainEnv),
3784
- effectiveCompilerInvocationFingerprint(driver, toolchainEnv, programCompilerArgs, ".ll"),
3785
- translationUnitDependencyFingerprint(driver, programCompilerArgs, opts.cPath, cBytes, toolchainEnv),
3786
- ccVersion(driver.argv, toolchainEnv, true),
3787
- resolveProgramShardMergeIdentity(driver),
3788
- ]);
3789
- if (currentRuntime === fingerprint &&
3790
- currentFingerprints.compile === implicitCompileToolchain &&
3791
- currentInvocation === programCompilerInvocation &&
3792
- currentDependencies === programDependencyHash &&
3793
- currentCompiler === cv &&
3794
- currentMerge === programShardMergeIdentity) {
3795
- await Promise.all(publishable.map((entry) => publishCachedFile(entry.staged, entry.cachePath)));
3796
- }
3797
- }
3798
- catch {
3799
- // The merged object is valid for this invocation; publication is
3800
- // only an optimization for later edits.
3801
- }
3802
- }
3803
- return merged;
3804
- }
3805
- catch {
3806
- // Sharding is an optimization. Compile/link the canonical TU below if
3807
- // a target tool, one shard, or relocatable merge is unavailable.
3808
- return null;
3809
- }
3810
- };
3811
- const shardedProgramObject = await compileShardedProgram();
3812
- if (programShards !== null && shardedProgramObject === null) {
3813
- // The canonical TU fallback is valid output, but it must not populate a
3814
- // cache key describing a successful shard projection/merge.
3815
- cacheInputsStable = false;
3816
- }
3817
- await buildExecutable((p) => objects?.get(p) ?? p, shardedProgramObject === null
3818
- ? { programPath, outPath: privateOut, compilerVisibleSource: opts.cPath }
3819
- : { programPath: shardedProgramObject, outPath: privateOut });
3820
- if (darwinDebugSymbols) {
3821
- // clang invokes dsymutil when compiling a source TU while linking.
3822
- // A sharded program is already an object, so run it explicitly while
3823
- // the merged object and staged runtime inputs still exist.
3824
- if (shardedProgramObject !== null)
3825
- await createDarwinDebugSymbols(privateOut);
3826
- await installDarwinDebugSymbols(await readDarwinDebugSymbols(privateOut), opts.outPath);
3827
- }
3828
- await installArtifact(privateOut, opts.outPath);
3829
- if (cachedBin !== null && keyHex !== null) {
3830
- // Metadata comparison catches ordinary changes cheaply, but cannot by
3831
- // itself prove the snapshot was taken from the same bytes hashed into
3832
- // the key. Recompute every content-bearing identity after the final link
3833
- // so a header/SDK/compiler change in either pre-build gap cannot publish
3834
- // new output under an old key.
3835
- const [currentRuntime, currentImplicit, currentRuntimeInvocation, currentProgramInvocation, currentProgramDependencies, currentLinker, currentCompiler, currentProgramShardMerge] = await Promise.all([
3836
- runtimeFingerprint(rtDir).catch(() => null),
3837
- implicitToolchainFingerprint(driver, toolchainEnv).catch(() => null),
3838
- effectiveCompilerInvocationFingerprint(driver, toolchainEnv, cflags).catch(() => null),
3839
- effectiveCompilerInvocationFingerprint(driver, toolchainEnv, programCompilerArgs, programSourceExtension).catch(() => null),
3840
- translationUnitDependencyFingerprint(driver, programCompilerArgs, opts.cPath, cBytes, toolchainEnv).catch(() => null),
3841
- implicitLinkerFingerprint(driver, toolchainEnv, linkProbeArgs, effectiveLinkInvocationArgs, linkTraceInvocationArgs).catch(() => null),
3842
- ccVersion(driver.argv, toolchainEnv, true).catch(() => null),
3843
- programShards === null
3844
- ? Promise.resolve(null)
3845
- : resolveProgramShardMergeIdentity(driver).catch(() => null),
3846
- ]);
3847
- cacheInputsStable =
3848
- cacheInputsStable &&
3849
- preBuildDependencies !== null &&
3850
- await nativeArtifactDependenciesStillMatch(preBuildDependencies) &&
3851
- currentRuntime === fingerprint &&
3852
- currentImplicit === implicitToolchain &&
3853
- currentRuntimeInvocation === runtimeCompilerInvocation &&
3854
- currentProgramInvocation === programCompilerInvocation &&
3855
- currentProgramDependencies === programDependencies &&
3856
- currentLinker === implicitLinker &&
3857
- currentCompiler === cv &&
3858
- currentProgramShardMerge === programShardMergeIdentity;
3859
- }
3860
- if (cachedBin !== null && keyHex !== null && cacheInputsStable) {
3861
- try {
3862
- // Cache artifacts are data, never execution targets. Publication keeps
3863
- // generated code and embedded literals private; the hit path reapplies
3864
- // the caller's current executable mode to its destination copy.
3865
- await publishCachedFile(privateOut, cachedBin);
3866
- if (darwinDebugSymbols) {
3867
- const symbols = privateSiblingPath(privateOut, "debug-symbols");
3868
- await writeFile(symbols, Buffer.concat([
3869
- Buffer.from(await fileDigest(privateOut), "hex"),
3870
- await readDarwinDebugSymbols(privateOut),
3871
- ]));
3872
- await publishCachedFile(symbols, `${cachedBin}.dsym`);
3873
- }
3874
- }
3875
- catch {
3876
- /* publishing is best-effort */
3877
- }
3878
- }
3879
- if (localArtifact !== null &&
3880
- localArtifactDependencyPaths !== null &&
3881
- cacheCompleteArtifact &&
3882
- cacheInputsStable) {
3883
- const stamp = await publishLocalArtifactStamp(localArtifact.stampPath, opts.outPath, localArtifact.key, localArtifactDependencyPaths, [dirname(resolve(opts.cPath))], [persistentCache.root], darwinDebugSymbols).catch(() => null);
3884
- if (stamp !== null) {
3885
- await opts.onArtifactReady?.({ dependencies: stamp.dependencies }).catch(() => undefined);
3886
- }
3887
- }
3888
- }
3889
- finally {
3890
- await rm(buildDir, { recursive: true, force: true }).catch(() => undefined);
3891
- }
3892
- // Runtime-object population is itself a cache write, including on builds
3893
- // whose native link inputs disable complete-artifact publication.
3894
- await pruneCache(persistentCache.root, cacheWarmPaths).catch(() => undefined);
3895
- }
3896
- export async function compileC(opts) {
3897
- clearCcCaches();
3898
- await compileCInternal(opts, false);
3899
- if (targetPlatform(resolveCc()) === "darwin" && !needsDarwinDebugSymbols("darwin", opts.optimization, opts.strip)) {
3900
- await rm(`${opts.outPath}.dSYM`, { recursive: true, force: true });
3901
- }
3902
- }
3903
- export function supportedNativeCacheWarmProfiles(driver) {
3904
- if (isMobileTarget(driver.target) || targetPlatform(driver) === "wasi")
3905
- return [];
3906
- return ["runtime", "tls", "dynamic"];
3907
- }
3908
- /** Populate expensive native prerequisites against the current compiler,
3909
- * target, SDK, and environment. The resulting entries use the exact same
3910
- * identities and validators as ordinary builds; this merely pays their cost
3911
- * before a developer's first program asks for them. Synthetic link products
3912
- * are discarded and never enter the complete-executable cache. */
3913
- export async function warmNativeCaches(options = {}) {
3914
- clearCcCaches();
3915
- const cacheRoot = cacheRootDir();
3916
- if (cacheRoot === null) {
3917
- throw new Error("the native build cache is disabled (unset SCRIPTC_NO_CACHE and use a non-empty SCRIPTC_CACHE_DIR)");
3918
- }
3919
- await ensurePrivateCacheRoot(cacheRoot, process.env["SCRIPTC_CACHE_DIR"] === undefined);
3920
- const known = new Set(["runtime", "tls", "dynamic"]);
3921
- for (const profile of options.profiles ?? []) {
3922
- if (!known.has(profile))
3923
- throw new Error(`unknown native cache warm profile '${profile}'`);
3924
- }
3925
- if (options.profiles?.length === 0)
3926
- return { cacheRoot, profiles: [] };
3927
- const mobileTarget = mobileLibraryTarget();
3928
- if (mobileTarget !== null) {
3929
- throw new Error(`native cache warming targets executable builds and is unsupported for SCRIPTC_TARGET=${mobileTarget}`);
3930
- }
3931
- const driver = resolveCc();
3932
- const supported = supportedNativeCacheWarmProfiles(driver);
3933
- if (supported.length === 0) {
3934
- throw new Error(`native cache warming targets persistently cached native executables and is unsupported for SCRIPTC_TARGET=${driver.target}`);
3935
- }
3936
- const profiles = [...new Set(options.profiles ?? supported)];
3937
- for (const profile of profiles) {
3938
- if (!supported.includes(profile)) {
3939
- throw new Error(`native cache warm profile '${profile}' is unsupported for SCRIPTC_TARGET=${driver.target}`);
3940
- }
3941
- }
3942
- const workDir = await mkdtemp(join(tmpdir(), "scriptc-cache-warm-"));
3943
- const cPath = join(workDir, "warm.c");
3944
- await writeFile(cPath, "int main(void) { return 0; }\n");
3945
- const protectedPaths = new Set();
3946
- try {
3947
- const results = await Promise.all(profiles.map(async (profile) => {
3948
- const started = performance.now();
3949
- await compileCInternal({
3950
- cPath,
3951
- outPath: join(workDir, process.platform === "win32" ? `${profile}.exe` : profile),
3952
- cacheIdentity: "scriptc-native-cache-warm-v1",
3953
- optimization: options.optimization ?? "release",
3954
- sanitize: options.sanitize ?? false,
3955
- ...(profile === "tls" ? { fetch: true } : {}),
3956
- ...(profile === "dynamic" ? { dynamic: true } : {}),
3957
- }, true, protectedPaths);
3958
- return {
3959
- profile,
3960
- elapsedMs: Math.round((performance.now() - started) * 10) / 10,
3961
- };
3962
- }));
3963
- await pruneCache(cacheRoot).catch(() => undefined);
3964
- if (!(await Promise.all([...protectedPaths].map(fileExists))).every(Boolean)) {
3965
- throw new Error(`SCRIPTC_CACHE_MAX_MB is too small to retain the requested native cache warm profiles (${profiles.join(", ")})`);
3966
- }
3967
- return { cacheRoot, profiles: results };
3968
- }
3969
- finally {
3970
- await rm(workDir, { recursive: true, force: true }).catch(() => undefined);
3971
- }
3972
- }
18
+ export { vendorCacheBuildIdentity, vendorCacheTargetFlavor } from "./native/vendor.js";
3973
19
  //# sourceMappingURL=native-toolchain.js.map