jank 0.18 发布:重新设计 C++ 错误报告,上线官方原生包仓库
距离 jank 上一次更新已经过去三个月,这个以 Clojure 语义为基础、编译到原生 C++ 的编程语言带来了一批重要改进。最受关注的是错误报告系统的全面升级——从编译期错误延伸到运行时异常和 C++ 互操作错误,同时上线了官方原生包仓库。
运行时异常的堆栈追踪
在现代 C++ 编译器中,获取堆栈追踪并没有标准、可移植的方式。对于从 JVM 世界迁移过来的开发者来说,这一点可能令人意外,但在原生世界中确实如此。
jank 的情况更加复杂:它是 JIT 编译 C++ 代码的,需要获取包含 JIT 编译帧在内的准确堆栈追踪,并且还要把部分 C++ 帧映射回实际的 jank 代码。
为了解决这个问题,jank 团队做了大量工作。最终效果是:当一个异常从 clojure.core/subs 背后的 C++ 代码抛出时,jank 能够正确地指向最近的用户 Clojure 调用,跳过调用 C++ 函数的 clojure.core 帧。
在堆栈追踪中,可以看到两个 Clojure 特定的帧,编号为 #1 和 #3:
clojure.core/subs帧user/foo帧(实际调用 subs 的地方)
这两个帧都包含了使用的确切 arity,以及各自 jank 文件中的精确源码位置。
值得注意的是,这个堆栈追踪从三个独立的地方拉取调试信息:
- 当前可执行文件(所有非 Clojure 帧)
- AOT 编译的目标文件(加载
clojure.core时加载,相当于 Clojure JVM 的.class文件) - JIT 编译的目标文件(编译
user/foo函数时添加到 LLVM JIT 运行时)
jank 现在能够将这三者无缝编织在一起,提供美观的错误报告。该功能在 macOS 和 Linux 上均可靠工作。
错误页面
在错误输出的底部,还藏着一个 URL。自去年最初的错误报告设计以来,jank 团队就打算为每种错误提供专门的错误页面,每个页面提供关于错误的更多信息、常见原因和建议修复方案。
目前所有这些错误页面都已创建,并成为 jank 文档的一部分。当编译器或运行时遇到错误时,会在输出中附上对应的错误页面链接,帮助开发者快速理解问题并找到解决方案。
C++ 互操作错误
除了运行时异常,jank 还改进了 C++ 互操作错误的报告。当 jank 代码调用 C++ 函数时,如果参数类型不匹配或函数不存在,jank 现在能够给出更清晰的错误信息,指出具体是哪个 C++ 函数调用出了问题,以及期望的参数类型是什么。
这对于 jank 的 C++ 互操作能力至关重要——jank 的核心设计目标之一就是能够无缝调用 C++ 库,而清晰的错误报告是实现这一目标的关键一环。
官方原生包仓库
本次更新还上线了 jank 官方原生包仓库。在此之前,jank 项目的依赖管理主要依赖 Clojure 生态的工具,但对于原生编译场景,需要一个专门的包仓库来管理预编译的原生库。
官方原生包仓库的上线意味着 jank 用户现在可以更方便地分享和使用预编译的 jank 库,无需每次都从源码编译。这对于大型项目和 CI/CD 场景尤为重要,可以显著缩短构建时间。
jank 是什么
jank 是一个以 Clojure 语义为基础的编程语言,但它不运行在 JVM 上,而是编译到原生 C++ 代码。它的目标是在保持 Clojure 表达力的同时,获得接近 C++ 的性能和更小的运行时开销。
jank 支持 Clojure 的核心特性,包括不可变数据结构、宏、多方法、协议等,同时通过 C++ 互操作能够直接调用原生库。它使用 LLVM 作为 JIT 编译后端,支持 AOT 编译和 JIT 编译两种模式。
项目地址:https://github.com/jank-lang/jank
官方博客:https://jank-lang.org/blog/2026-09-04-better-and-better/