• 这个结构体的 sizeof 大小是多少?
  • unsigned 与 long long 相乘的类型是什么?
  • 你是否遇到过,想要测试一个简短的 C++ 代码,而为创建一个新文件,等待编译的漫长过程感到烦躁?
  • 可不可以让 C++ 像 python 一样交互地运行?

Well,你需要的是一个交互式 C++ 解释器!

你没听错,在技术日新月异的今天,人们可以把解释型的语言做出“编译器”,把编译型的语言做出解释器……今天要介绍的 cling 正是一个基于 LLVM 和 clang 的交互式 C++ 解释器。

炫技时刻

在终端中启动 cling:

$ cling -std=c++17

会看见这样一个界面:

****************** CLING ******************
* Type C++ code and press enter to run it *
*             Type .q to exit             *
*******************************************
[cling]$

在 $ 后面就可以输入 C++ 代码了:

[cling]$ 15u*16ll
(long long) 240
[cling]$ struct node {
[cling]$ ?   int v, sz;
[cling]$ ?   node *ch[26], *fa;
[cling]$ ?   }
[cling]$ sizeof(node)
(unsigned long) 224

cling 很棒地实现了 REPL,即 Read-evaluate-print loop,读取—求值—打印的循环。玩过 python 的都知道,每当输入一行表达式就立即得出值(以及类型)的感觉。

在 cling 中,没有分号结尾的被视为表达式,会显示类型和值,以分号结尾的语句则不会。

再来看一些例子:

[cling]$ long long v = 1145141919810
(long long) 1145141919810
[cling]$ scanf("%d", &v)
input_line_24:2:14: warning: format specifies type 'int *' but the argument has type 'long long *' [-Wformat]
 scanf("%d", &v)
        ~~   ^~
        %lld
32767
(int) 1
[cling]$ v
(long long) 1142461333503

编译警告很友好,并且你可能会注意到有个 (int) 1——如果你平时比较粗心,你可能今天才想起 scanf 是有返回值的!

设计测试运算符优先级的表达式:

[cling]$ 3<<2|1
(int) 13
[cling]$ 3<<(2|1)
(int) 24

退出:

[cling]$ .q

.q 一样,cling 在 C++ 语言之外自身还有一些以点开头的特殊命令,如 .L 可以直接加载另一个 C++ 文件里的内容等等,具体可以参考官网。

cling 的更多玩法请读者自行探索。也许你过几天就需要它,为什么不现在就将他安装了呢?

安装方法

方法 1 手动安装

前提条件:你最好得使用类 Linux 的系统!目前没有针对 Windows 原生编译好的程序。 在 Windows 上用 WSL 也是可以的。

NOTE: 下面的步骤写的比较简略,需要一定的 Linux 实践经验。

到其官网这里下载你对应的操作系统的编译好的文件。

注意:因为 cling 基于 LLVM 和 clang 构建,它会附带一整个 clang 编译器,

  1. 导致编译好的文件非常大,做好准备让你的磁盘少掉一两个 G。

  2. 它附带的 clang 通常比你平常用的版本老。因此建议你放在别的(如 /opt)目录下,并只创建一个 cling 的符号链接到 /usr/bin/ 以免混淆 clang 的版本。

然而,你会发现官方所谓《 N i g h t l y   b u i l d 》最近一个版本是 2020 年 11 月编译的了。如果你嫌老……

我用学校机房的“破”电脑花费了一个晚上,针对 Ubuntu 20.04 自己编译了一个 0.9 版本,可以在这里下载。警告:这个压缩包大概有 600 MB!

在 Windows 上原生构建理论上也是可行的,但环境较难弄,我并未尝试,不知是否有冒险家愿意尝试。

方法 2 通过其他渠道安装

通过 Anaconda 或 docker 可以安装。注意,**以下的方法我都没有试过,**并且获得的版本可能较老。

conda config --add channels conda-forge
conda install cling

docker pull compilerresearch/cling
docker run -t -i compilerresearch/cling

背景补充和未来展望

cling 是 CERN 的 ROOT 工程 的一个核心一部分。没错 CERN 就是那个搞对撞机的【欧洲核子研究组织】,而 ROOT 则是一个面向高能物理学领域的 data scientist 的数据分析框架。早些年头 python 在科学数据分析领域还不如现在流行,C++ 语言在这方面有大量的应用。近 5 年来,cling 帮助分析了 1 EB 的物理数据,在 1000 多篇科学出版物的背后发挥着重要的作用。1

ROOT 的开发者也许不以为他们搞出了个多么了不起的东西,但 cling 却获得了越来越多的在科研之外的社区成员的喜爱,特别是 LLVM、搞编译器的人们,他们一起帮助完善 cling,修 bug。

尽管已有一些应用,cling 仍然处在版本号以 0. 开头的不稳定阶段。(甚至在若干版本以前,只要输入了会 CE 的代码就会崩溃……大概这种状态)cling 宣称能较快支持新语言标准,因为它大量复用 LLVM 和 clang 的代码。然而实际上稍差一点:今年 LLVM 发布 12 版本,cling 发布 0.9 版,而 cling 的基础 LLVM 是 2019 年的 9 版本。因为仅靠复用代码不能实现完全的解释器的功能,有的地方必须在 LLVM 之上打补丁。可想而知每一次 LLVM 新版发布时都维护一下这个“补丁”是很麻烦的。

随着两方社区增进交流,cling 想将其自己实现的有必要的部分回馈给 LLVM,而 cling 又想要从 LLVM 的更新中获益,依赖版本的跟进不及时成了摆在他们面前的挑战。最近,cling 宣布向 LLVM 的 clang-repl 项目过渡。2今年五月,clang-repl 最少的基本功能完成,进入 LLVM 仓库。(这不意味着 cling 作为一个项目会停止。)cling 和 clang-repl 的未来如何,让我们拭目以待。

注:以上含有我的个人理解,可能不准确。请参考官网和下面的参考资料。

参考资料