拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

scriptc 测试基架(Test Harness)深度解析:Node 基准差分测试、五条跨平台测试通道与构建缓存

scriptc 测试基架(Test Harness)深度解析:Node 基准差分测试、五条跨平台测试通道与构建缓存
  • 编译器
  • 语言运行时
  • 开发工具
  • CLI

【免费下载链接】scriptc

TypeScript-to-Native Compiler

项目地址:https://gitcode.com/GitHub_Trending/sc/scriptc
点击查看免费下载

本指南以 tests/harness/README.md 为骨架,深入讲解 scriptc(TypeScript-to-Native 编译器)的测试基架设计:如何用 Node 作为「预言机(oracle)」对同一套语料做双轨字节级差分验证,如何通过 LLVM、Linux、Windows、库模式四条环境门控通道补齐跨平台矩阵,以及如何用内容寻址缓存把动辄数百次 clang 调用的全量套件压回可迭代的速度。读完本文,你将掌握 scriptc 全量测试(pnpm test)的完整运行模型、全部环境变量开关与缓存键设计,并能在自己的工作中复用这套「以解释器为基准的差分测试」思路。

一、总览:一条语料、两种风味,Node 即答案

scriptc 测试基架的核心设计可以用一句话概括:没有 golden file,Node 就是预期输出。整个tests/corpus下的每一个测试程序,都会在 Node 下运行一次,再被编译成本机二进制运行一次,两边的stdout 必须逐字节完全一致;退出码为 0 的程序还要求 stderr 也逐字节一致,且退出码必须与程序声明的// @exit:指令相符。由于预期不是人工维护的快照,测试永远不会因为「期望文件忘了更新」而漂移。

这套机制跑在两条并行的「通道(lane)」上:

  • plain(普通):pnpm test,直接编译运行并对比;
  • sanitized(消毒):SCRIPTC_SAN=1 pnpm test,所有程序都用 AddressSanitizer(ASan)外加运行时引用计数(RC)审计重新构建运行,把整个语料变成一批内存泄漏与 use-after-free 的检测用例。

两条通道都必须全绿才能提交(commit gate)。同一份语料、同一套断言,只是其中一条额外承担了消毒器覆盖率。语料程序本身非常多样——从001-hello.ts、100-number-format.ts这类标量程序,到模块图、异步、Promise、生成器、正则、streams、HTTP、甚至 CJS/ESM 互操作程序——都遵循同一条字节契约。

除了语料之外,Test262 回归 profile 是第二类「预言机」:它使用 tests/test262/README.md 中说明的上游断言作为期望,同样在两条通道中运行。

二、语料程序的指令契约:// @头注如何驱动双端行为

语料程序的前两行是它的「指令头(directive head)」,允许一行一个指令组合使用。这些指令在 differential.test.ts 中被解析,用来决定 Node 端和编译端的运行方式:

指令作用
// @exit: <n>声明预期退出码(默认 0)。非零退出的程序(通常是 uncaught-throw)只比较 stdout,因为其 stderr 是未捕获异常报告,格式属于文档化的已知分歧;退出码为 0 的程序则 stdout、stderr 都要字节级一致
// @dynamic要求以--dynamic模式编译,嵌入 island 引擎
// @transform-typesNode 端以--experimental-transform-types --disable-warning=ExperimentalWarning运行——用于使用命名空间(namespace)等 Node 默认 strip-only 模式拒绝解析的语法
// @tsc-decorators装饰器是唯一一种 Node完全无法执行的受支持语法(V8 尚未落地该提案,strip 与 transform 模式都会让 V8 拒绝语法),因此 Node 端运行的是 tsc 对程序做的确定性 ES2022 downlevel(物化在测试缓存目录下,键由程序字节 + TypeScript 版本决定)
// @no-deprecationNode 端加--no-deprecation——用于new Buffer构造器阶梯等已弃用 API 的错误路径,其弃用警告携带 PID,永远无法字节对比

此外,两条 shim 让 Node 保持「预言机」地位:

  • comptime-shim.mjs:把comptime(fn)定义为普通调用fn(),于是编译期求值的结果必须等于 Node 运行时算出的结果;
  • island-shim.mjs:把__island_eval(code)定义为全局间接 eval 加String(),使动态 island 程序的值结果同样以 Node 为基准。

JS 入口(.js/.mjs/.cjs)也是一等公民:Node 直接运行它们(不做类型剥离),scriptc 则通过 checkJs 推断来编译——见 differential.test.ts 的入口扩展名列表ENTRY_EXTS = ["ts", "js", "mjs", "cjs"]。

运行细节上还有两处工程化处理:子进程 stdin 立即关闭,让两边读到同一个「空的、已关闭的流」(语料程序允许readFileSync(0)读到 EOF);Linux 上观察到 fork/exec 竞态会偶发ETXTBSY,因此对 exec 失败做了最多 10 次、每次 50ms 的短暂重试(与 npm/cargo 的立场一致)。

三、唯一的例外:node:test程序走文档化归一化

语料中有一个故意的例外:node:test程序(node-test.test.ts 驱动 tests/fixtures/node-test)不能进入纯字节对比语料,因为 Node 的 spec reporter 会在每一行结果里嵌入真实耗时——任何node:test程序都没有确定性的 stdout,即使在 Node 自己下面跑也一样。

这些 fixture 仍然在两条通道里跑,但对双方(Node 与编译二进制)统一施加一次文档化的归一化,见 node-test-normalize.ts:

  • 归一化项:(Xms)耗时、栈帧(at行)、inspect 属性块;
  • 其余一切仍须字节级一致:符号、缩进、指令、汇总计数、失败区段的test at位置与错误消息;
  • 退出码必须与 fixture 的// @exit:行一致。

另外,fixture绝不能在测试体内console.log——Node 的 reporter 流与 console 输出存在竞态延迟,混排输出对任何预言机都无法字节对比。

四、双后端差分:LLVM 通道的「声明即承诺」

LLVM 后端乘坐同一条语料,通过自己的双后端差分 llvm-differential.test.ts 运行:每个语料程序都尝试用--backend=llvm构建,而 tier 成员资格是自动发现的——尝试构建,捕获 SC3001 拒绝。

  • tier 声称支持的程序:经两个后端编译的 stdout(始终)、exit-0 程序的 stderr、以及退出码必须三方一致——LLVM 产物、C 产物、Node 预言机;
  • tier 之外的程序:必须明确拒绝,恰好输出一条SC3001诊断,点名第一个不支持的 IR 构造——绝不产出错误代码,也绝不静默回退。

拒绝会被打印成直方图,连同声称支持的程序计数一起输出,成为下一阶段(phase 2)的实现队列。tier 底线(floor)被显式钉死:六个 trivial 程序(001-hello.ts、002-log-args.ts、100-number-format.ts、101-arithmetic.ts、400-fib.ts、401-mutual-recursion.ts)一旦跌出 tier 就视为 bug;另有TIER_REGRESSIONS列表钉住不能回退的语料程序。注意发布版默认是「LLVM + 透明 C 回退」,而本套件显式backend: "c"/backend: "llvm"的钉死正是让拒绝保持响亮的手段——回退行为由同套件中的默认通道单独断言。

在SCRIPTC_SAN=1下,发射出的.ll通过sanitize_address属性把 LLVM 发射的函数也纳入 ASan 插桩——该属性在 packages/compiler/src/backend/llvm/emitter.ts 中按attributes #0 = { sanitize_address }输出,两条通道因此都有消毒器覆盖。

五、跨平台通道一:Linux(SCRIPTC_LINUX=1)

第三条通道由环境变量门控,默认跳过、绝不进入提交门(commit gate):SCRIPTC_LINUX=1 pnpm exec vitest run tests/harness/linux-differential.test.ts。它用zig cc(SCRIPTC_CC=zigcc/SCRIPTC_TARGET,见 native-toolchain.ts)把每个程序交叉编译到 Linux triple,然后在 Docker 容器内把「编译出的二进制」与「容器内的 Linux Node」逐字节对比——语料与带运行时腿的 fixture 集(tests/fixtures/server、tests/fixtures/dgram、tests/fixtures/fetch)全部覆盖,fixture 的两条通道、按用例驱动的 driver、fetch 服务端都跑在容器内。

  • SCRIPTC_LINUX_TARGET=<arch>-linux-gnu.2.36:整个通道跑在 Bookworm(glibc 与 triple 的钉死匹配);
  • SCRIPTC_LINUX_TARGET=<arch>-linux-musl:跑在 Alpine;
  • 容器平台跟随 triple(linux/arm64对应 AArch64,linux/amd64对应 x86_64,Apple Silicon Docker 上经 Rosetta/qemu);
  • SCRIPTC_LINUX_FILTER=<regex>收窄到匹配的语料/fixture 名,便于排查。

从 linux-differential.test.ts 可以看到,没有任何特性再被 Linux 交叉门控:timers/async、信号/stdin、process/fs、child_process、动态 island(每目标 libqjs.a)、regex(每目标 libregexp 对象)、zlib、fs.watch(inotify 分支)、net/http/tls、dgram/dns、fetch(vendored curl 头 + soname stub,运行时绑定容器系统 libcurl)全部真实执行。

六、跨平台通道二:Windows(SCRIPTC_WIN=1)

第四条通道结构相同、方向相反:SCRIPTC_WIN=1 pnpm exec vitest run tests/harness/windows-differential.test.ts交叉编译到x86_64-windows-gnu,把每个.exe(连同程序源码)经scp送到 Windows 机器,再经ssh在那边同时运行双方——编译出的二进制,以及那台机器自己的Windows Node作为预言机(Windows 用户实际对比的就是它)。没有任何归一化:CRLF 或路径分隔符差异都是发现项,不是噪声。

  • SCRIPTC_WIN_FILTER=<regex>收窄单次运行;
  • ssh 主机别名默认windows-dev,可用SCRIPTC_WIN_HOST覆盖;
  • 需要跨门控特性的程序携带门控原因跳过;
  • 文件内的WINDOWS_SKIPS列表点名「能编译但故意在 Windows 上分歧」的程序(posix 形态的 spawn 程序——其 /bin 子进程在 Windows Node 下同样是 ENOENT——以及 uid/tty 表面);这两个列表就是移植工作的剩余清单(worklist)。

盒端礼仪在 windows-differential.test.ts 中有说明:所有产物集中在单一目录、机器级 advisory 锁防止两条通道踩踏、ssh ControlMaster 复用连接让每个程序约 3 次远端操作保持廉价。

七、跨平台通道三:库模式(SCRIPTC_CROSS=1)

第五条通道SCRIPTC_CROSS=1 pnpm exec vitest run tests/harness/library-cross.test.ts覆盖库模式(library mode):可执行语料已经在 Linux/Windows 通道里完成了交叉编译 + 交叉执行,而库模式要闭合同一类「预期可用、从没测过」的缺口——K-fixture 的归档(archive)正是 embedder 要链接的产物,因此每个 K-fixture 库 profile 的两种发射(emitted .c 与 .ll,刻意不携带目标 triple,zig cc -target两者皆可编译)都会为以下六个目标交叉构建:

  • aarch64-linux-gnu.2.36、x86_64-linux-gnu.2.36(Linux 通道默认 triple,glibc 钉到容器 Bookworm)
  • aarch64-linux-musl、x86_64-linux-musl(Alpine 兼容静态 triple)
  • x86_64-windows-gnu(Windows 通道 triple)
  • x86_64-macos(按契约仅构建——主机 arm64-macos 构建是普通套件的既有基线)

然后在主机上对每个归档断言(无需执行——Apple 的 nm 即 llvm-nm,ELF/COFF/Mach-O 通读):

  • K1 符号精确性:携带前缀的外部定义必须等于 profile 声明的符号集合(导出 + ABI 入口点 + sidecar 身份 getter),双向;不得有携带前缀的未定义符号。符号装饰按格式归一化(Mach-O 前导下划线、ELF 与 x86_64 COFF 没有);
  • K8 环境审计:机械式 ambient 审计——对 process-disposition/threading 表面零未定义引用,归档内不得定义或引用任何 fiber/loop/timer/child 符号;
  • 可链接性:带 probe 的 fixture 必须仅凭目标 libc 就能与交叉归档链接;win32 上额外加上文档化的 embedder 系统库advapi32 / iphlpapi / ws2_32(与 native-toolchain.ts 无条件链接进 win32 可执行文件的集合一致)。任何游离未定义(该通道上线第一天就抓到的scr_win.cshim 缺口)都失败在这里——主机构建期,而不是 embedder 的构建里。

执行按基础设施的可用性分阶段,门控与兄弟通道相同:SCRIPTC_LINUX=1时 K2 标量 probe(链接了交叉归档的纯 C embedder 宿主)在每个 Linux triple 对应的 Docker 发行版里运行;SCRIPTC_WIN=1时经 scp 送到 Windows 盒运行(其 stdout 是 CRLF——probe 自身的 printf 走 mingw CRT 的文本模式 stdout,是诚实的纯 C embedder 事实,因此该腿单独归一化换行);x86_64-macos按契约仅构建,Rosetta 恰好存在时 probe 作为彩蛋运行(检测到才跑,从不要求)。通道需要 zig 在 PATH 上;SCRIPTC_CROSS_FILTER=<regex>收窄 fixture 列表。成本约为每归档 1 秒、全矩阵 112 次构建约 2.5 分钟,因此环境门控而非默认套件,永不进入提交门。

八、工作流:迭代过滤、提交全量、fetch 兼容性 profile

基架的工作流原则是「迭代时过滤,提交时全量」:

  • 开发期间只跑你正在动的东西:pnpm exec vitest run tests/harness/differential.test.ts -t <name>或单个测试文件;
  • 提交前跑全量通道作为门:pnpm test,然后SCRIPTC_SAN=1 pnpm test。

fetch 兼容性 profile:唯一的版本化事实源

无引擎 fetch/Web Streams 切片有一个版本化事实源:packages/compiler/src/compat/fetch-profile.ts。它钉死精确的 Node 与内置 Undici 预言机,驱动 lowering 的 allowlist,把每个受支持的操作投影进 packages/compiler/surface-manifest.json,并为每个操作与RequestInit/ResponseInit成员命名差分证据。没有真实 fixture 或注册的生成场景的新行会让 profile 套件失败。

pnpm test:fetch-conformance(即 fetch-conformance.test.ts)从 profile 生成程序,在钉死的 Node 与两个本机后端下运行。默认种子覆盖 WebIDL 参数转换/顺序、AbortSignal 事件、十二条有效的 ReadableStream 状态机轨迹。可复现或扩大战役:

SCRIPTC_FETCH_CONFORMANCE_SEED=12345 \ SCRIPTC_FETCH_CONFORMANCE_TRACES=50 \ pnpm test:fetch-conformance

profile 现在不仅承载受支持的行,还承载分母(denominator):它反映 AbortController、AbortSignal、Headers、Request、Response、ReadableStream、其默认 reader 与默认 controller 的公开构造器/静态/原型表面;proxy 背书的构造器 probe 记录 Node 对RequestInit/ResponseInitWebIDL 字典的确切读取(含可能比已装声明更新的运行时成员)。每个条目都被分类:

  • static:无引擎、与差分证据行一一对应;
  • dynamic-only:以 SC2020 从静态构建围栏,--dynamic下接受;
  • unsupported:两个 tier 都 SC2020——这是实现工作,不是隐式遗漏;
  • out-of-scope:Symbol.toStringTag这类反射元数据,保留以使范围边界机器可读。

被排除在普查之外的相邻接口族也携带理由。Node 升级若增删公开成员或字典键,聚焦套件就会失败,直到该成员被分类。static、dynamic-only、unsupported 行投影进发布的 surface manifest;可按status/owner过滤NODE24_FETCH_COMPAT_PROFILE.inventory.entries,得到下一个内聚实现队列。Node 变更时,应同步更新.node-version与 profile 的 Node/Undici 元组、pnpm manifest重新生成,然后跑聚焦的 plain 与 sanitized 一致性通道,再跑全量 sandbox 门;静态 fetch 表面变化时则先改 profile,其证据检查会让缺失的 fixture 或生成场景成为实现工作清单。

九、全量套件锁与 worker 配额

无过滤的vitest run会取一个机器级 advisory 锁(OS 临时目录下的 pidfile,实现见 suite-lock.mjs),让并发全量套件(典型场景:并行 agent)排队而不是超订 CPU——超订是已知的 flake 来源(vitest worker RPC 超时、事件循环时序失败)。关键设计是:

  • 锁**按风味(flavor)**区分(plain vsSCRIPTC_SAN=1):两条通道通过各自独立的缓存目录读取同一棵已提交树,因此 merge gate 可以刻意各跑一条——用SCRIPTC_TEST_WORKERS在两者之间切分核心(如 5 和 5),否则超订 flake 会回来;同风味的两次运行仍然排队;
  • 过滤与 watch 运行从不等待;
  • SCRIPTC_NO_LOCK=1退出;死进程留下的陈旧锁自动窃取;等待者 45 分钟后放弃并继续(MAX_WAIT_MS);
  • SCRIPTC_TEST_WORKERS=<n>封顶 vitest worker 池(默认不变,全部核心)。

十、构建与预言机缓存:把 clang 主导的套件压回可迭代速度

测试运行的时间大头是 clang(约 275 个语料程序 × 两条通道,-O2 / -O1+ASan)。生产级内容寻址构建缓存 + 基架的预言机缓存让重复运行变快。测试把缓存钉在node_modules/.cache/scriptc-tests/cas(gitignored;SCRIPTC_CACHE_DIR覆盖),而非用按用户默认值。缓存层(键设计见 native-toolchain.ts 与 executable-cache.ts、library-cache.ts):

  • binaries(bin/):键 = 已解析的 clang 身份/版本 + 目标/编译器环境 + 隐式系统头依赖字节 + 链接器/汇编器身份 + 运行时指纹(每个运行时 .c/.h + vendor 钉死)+ 完整归一化命令行 + 发射的 C 字节(按项目不变量字节稳定)。命中跳过原生代码生成与链接,但二进制仍会真实运行——对比与消毒器覆盖从不被跳过。每个命中都要校验和验证;sanitized 通道的旗标落在天然不同的键里。FFI 归档/对象输入与 ambient 系统库总是重链接,因为其命名文件可能隐藏可变传递依赖;
  • library archives(lib/):键 = 已解析 clang 与 ar 身份/版本 + 目标/编译器环境与隐式依赖 + 运行时指纹 + 目标/旗标 + 门控运行时源集合 + 发射的程序 TU 字节;校验和验证的命中跳过代码生成与ar;
  • library program objects(program-obj/):生成的库 TU 编译成独立于微小 exact-source 身份 TU 的、按内容取键的校验和对象。仅 build-id 未命中时复用大 program 对象、编译身份 getter 并重新归档;运行时/头/工具链输入仍是键的一部分,发布前重新检查;
  • early executable frontend(early-exe/):完全相同的可执行文件重复构建时,先验证新鲜的有效编译器身份、前端完整文件/解析快照与原生依赖证明,然后直接恢复发射的 C/LLVM 单元、可选 IR 与最终可执行文件,不再启动 TypeScript、lowering 或完整 clang/链接器发现。源码/配置/包编辑、新出现的解析候选、模式/目标/编译器/FFI 变更、运行时/工具链更新、损坏负载都会未命中;
  • early library frontend(early-lib/):验证 TypeScript 前端读过的每个文件的内容哈希 + 记录的失败解析与目录枚举探测,然后恢复生成的 C/LLVM 单元、可选 IR、sidecar 与原生特性门。TypeScript 纯注释未命中可在 token 等价检查后恢复压缩的 lowered IR;语义注释/指令、JavaScript 注释、token/配置/包编辑与新解析候选会未命中;
  • runtime objects(obj/):按风味给运行时源做的.o(含独立的-DSCR_LIB风味),编辑后的可执行文件/库只需重编译程序自己的 TU 再链接/归档。每个对象携带验证摘要;损坏项在到达链接器/归档器前重建。发布时在编译后重查运行时与隐式工具链指纹,防止并发源/头编辑把新字节放到旧键下。编译经 ccache(已安装时)路由,否则静默回退;
  • oracle results(oracle/):Node 每个程序的 stdout/退出码,键 = 程序字节 + 所 spawn node 的版本 + shim 内容 + 调用形态。只跳过 spawn,对比从不改变。实时程序(setTimeout/setInterval/Promise.race——298 个中的 18 个)被排除,永远实时 spawn Node:其 stdout 是计时器交错,只有在同一瞬时负载下 Node 与原生二进制才一致,所以一次运行缓存的裁决绝不能碰到另一次运行的实时原生结果。os.networkInterfaces(macOS 旋转 awdl0/llw0 链路本地地址)与系统 CA 证书存储这类易变主机状态同样排除。

逃生舱:SCRIPTC_NO_CACHE=1双向绕过一切缓存(不读不写——运行行为与未缓存路径完全一致);显式空的SCRIPTC_CACHE_DIR效果相同,非空值覆盖生产默认值。淘汰是每个缓存根上的大小封顶 LRU 清扫(SCRIPTC_CACHE_MAX_MB,默认 4096,实现在 build-cache.ts),首次写入后及长生命周期进程内周期性执行;读命中会 bump mtime。

保守绕过:能解析可变编译输入的编译器环境变量(CPATH、SDKROOT、clang 配置目录及其同类)保守地绕过持久产物与运行时对象;编译器包装器同样绕过(它们可能按真实源码/对象拓扑条件性注入输入),而直接 Clang、Apple 系统 Clang shim 与zig cc保留缓存。编译器必须保持可用,让每次调用重新发现依赖选择。不透明 ar 包装器重建库程序成员与归档,同时保留运行时对象复用;受信平台 ar 与zig ar保留完整归档命中。仅链接搜索变量与显式原生链接输入绕过完整可执行文件,但保留安全的运行时对象复用。

验收产物:pnpm test:cache-identity(可选--san,实现见 cache-identity.mjs)完整跑三遍——未缓存、填充缓存、缓存命中——然后对缓存与未缓存两遍之间每个测试的 name/status/failure 输出做 diff,任何漂移都非零退出。pnpm build是增量的(tsbuildinfo 在node_modules/.cache/scriptc-tsc/);pnpm build:fresh是干净构建的逃生舱。

开发构建基准:pnpm bench:builds

重建工作区后,pnpm bench:builds在生成的 17 模块、256 函数 TypeScript 程序上用--optimization=dev度量构建的 CLI。它报告一次空 scriptc 缓存的构建、五次精确重建、以及五次「修改一个被导入模块后」的重建。每次运行都用全新私有缓存,并在计时区外逐个验证每个二进制的 stdout、stderr 与退出状态是否与 Node 一致;临时文件完成后移除。pnpm bench:builds --iterations=3改变样本数;进度走 stderr,JSON 结果(含单样本与中位数)走 stdout(抓 JSON 时用pnpm --silent bench:builds)。

这是本地延迟基准,不是 CI 里的时序断言:比较时要同 Node 版本、目标、编译器安装与机器负载;空缓存样本不会刷 OS 文件系统或 Node 字节码缓存;记得取消设置SCRIPTC_TARGET,因为基准会执行生成的主机二进制。选优化时应把它与代表性应用的度量并列,而不要只看这个小模块图基线。

十一、Test262 回归与快照普查

默认静态编译器有一个钉死的 Test262 回归 profile 与一个独立的全快照普查运行器,命令、结果报告与当前 strict-script/标量断言限制见 tests/test262/README.md。要点:

  • 离线回归 profile:pnpm test:test262,upstream.json钉死 Test262 修订、归档校验和、完整快照摘要与未改动的 vendored 回归输入;同一回归测试与主机断言检查包含在pnpm test里,pnpm test:sandbox把用例分到 plain 与 sanitized 两条通道;
  • 完整快照普查:pnpm test:test262:fetch下载并验证完整钉死快照,--root传目录、--filter普查 API 族、--list只列清单、--limit/--workers/SCRIPTC_TEST_SHARD=i/n控制规模,--report/--journal落证据,--compile-timeout(默认 120s)/--runtime-timeout(默认 10s)限定超时,--keep保留中间物调查;
  • 静态编译器默认后端可能按普通编译器策略从 LLVM 回退到 C;每条执行结果都记录实际后端,--backend llvm或--backend c可钉死,SCRIPTC_SAN=1开启消毒器;两条通道(plain/sanitized)都会跑回归 profile,动态 island 被禁用。

十二、落地建议:如何把这些机制用于你自己的编译器项目

从 scriptc 测试基架可以提炼出一套可迁移的差分测试方法论:

  1. 让解释器成为预言机,而不是手写 golden——预期输出随语言实现演进自动更新,测试永不因期望文件失修而漂移;
  2. 用指令头让「预期」成为程序的一部分(退出码、运行模式、Node 旗标),键由程序字节决定,缓存天然安全;
  3. 同语料多通道——一份语料同时喂给 sanitized 构建、LLVM 后端、Linux/Windows 交叉执行,通道之间的分歧本身就是 bug 信号;
  4. 把「不支持」也测成显式诊断(SC3001 拒绝 + 直方图),拒绝保持响亮,绝不静默回退;
  5. 缓存只跳过「产物生成」,永不跳过「执行与对比」——命中仍要跑二进制、仍要校验和,消毒器覆盖从不缩水;
  6. 全量套件按风味分锁 + worker 配额,让并发 agent 与 merge gate 既能并行又不超订 CPU。

对 scriptc 本身,日常开发的最佳姿势是:改动局部特性时用-t <name>或单文件过滤跑 differential.test.ts 与 llvm-differential.test.ts;涉及 fetch/Web Streams 时用SCRIPTC_FETCH_CONFORMANCE_SEED/TRACES扩大会话跑pnpm test:fetch-conformance;跨平台改动按需打开SCRIPTC_LINUX=1/SCRIPTC_WIN=1/SCRIPTC_CROSS=1通道;提交前以pnpm test与SCRIPTC_SAN=1 pnpm test全量关门,并可用pnpm test:cache-identity验证缓存不会改变任何裁决。

  • 编译器
  • 语言运行时
  • 开发工具
  • CLI

【免费下载链接】scriptc

TypeScript-to-Native Compiler

项目地址:https://gitcode.com/GitHub_Trending/sc/scriptc
点击查看免费下载
上一篇:5分钟解锁中文Figma:设计师人工翻译的完美汉化方案
下一篇:ESPnet2 LibriTTS-R 多说话人 TTS Recipe 实战:从语料准备到 FastSpeech2 / VITS 训练与推理

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

返回列表