新的语言,还有对现有语言的提升,在整个编程环境中正大行其道。Mozilla 的 Rust、Apple 的 Swift、Jetbrains 的 Kotlin,以及许多其它的语言都给开发者在速度、安全性、便利性、可移植性还有能力这些方面提供了新的选择。
为什么现在正当时呢?一个大因素就是那些用来构建语言的新工具,特别是编译器。它们中首当其冲就是 LLVM (底层虚拟机 Low-Level Virtual Machine),这是一个开源项目,最开始作为伊利诺伊州大学的一个研究项目由 Swift 语言的创始人 Chris Lattner 进行开发。
LLVM 使创建新语言变得更加容易,同时也可以增强现有语言的开发。它提供了一些工具,用于自动执行语言创建任务中最不讨人喜欢的部分:创建一个编译器,将输出的代码移植到多个平台和架构,编写代码来处理常见的语言隐喻,比如异常。它的自由授权意味着它可以自由地作为软件组件重用或作为服务部署。
使用 LLVM 的语言名册中有许多熟悉的名字。苹果的 Swift 语言使用 LLVM 作为它的编译器框架,而 Rust 则将 LLVM 作为其工具链的核心组件。而且,许多编译器都有一个 LLVM 版本,如 Clang、C/C++ 编译器(这个名称叫做“C-lang”),它本身就是一个与 LLVM 紧密相连的项目。而 Kotlin,名义上是一种 JVM 语言,正在开发一种名为 Kotlin Native 的语言版本,它使用 LLVM 来编译成机器原生代码。
在它的核心,LLVM 是一个以编程方式创建机器原生代码的库。开发人员使用该 API 以一种称为中间代理或 IR 的格式生成指令。然后 LLVM 可以将 IR 编译成一个独立的二进制文件,或者在另一个程序(如语言解释器)的上下文中执行 JIT (just-in-time) 编译。
LLVM 的 API 为开发在编程语言中发现的许多常见结构和模式提供了原始的方式。例如,几乎每种语言都有函数和全局变量的概念。LLVM 将函数和全局变量作为其 IR 中的标准元素,因此,你只需在意 LLVM 的实现,并关注需要注意的语言部分,而不是花费时间和精力重新创建这些特定的轮子。
这是一个 LLVM 中间代理(IR)的例子。右边是一个简单的 C 程序;左边是由 Clang 编译器翻译成 LLVM IR 的代码。
LLVM:专为可移植性而生
关于 LLVM 的一个说法是它像常提到的 C 编程语言:C 语言有时候被认为是一种便携式、高级的汇编语言,因为它可以紧密地映射到系统硬件的结构,而且它已经被移植到几乎所有的系统架构。但是,C 语言只是作为一种可移植的汇编语言,是其工作方式的另一种效果;这并不是它的设计目标之一。
相比之下,LLVM 的 IR 是从一开始就设计为可移植的组件。它实现这种可移植性的一种方法是提供独立于任何特定机器架构的原语。例如,整数类型不局限于底层硬件的最大位宽度(例如 32 或 64 位),您可以根据需要使用尽可能多的比特字节来创建基本的整数类型,比如 128 位整数。您也不必担心手工输出来匹配特定处理器的指令集;LLVM 也会为你处理这个问题。
如果你希望看到 LLVM IR 的现场示例,请访问 ELLCC 项目网站,并尝试在浏览器中将 C 代码转换为 LLVM IR 的现场演示 Demo.
编程语言中如何使用 LLVM
LLVM 最常见的用例是作为一种语言的预先(AOT ahead-of-time)编译器。但 LLVM 也可以用于即时编译。
用 LLVM 进行即时编译
有些情况下需要在运行时动态生成代码,而不是预先编译。例如,Julia 语言就是使用 JIT 编译代码,因为它需要快速运行,并通过 REPL(read-eval-print loop)或交互式提示与用户交互Net 和 Mono 可以选择通过 LLVM 后端方式编译为原生代码。
Numba 是一个 Python 的数学加速包,JIT 将所选择的 Python 函数编译成机器码。它也可以预先编译使用 Numba 装饰器装饰的代码,但是(比如 Julia)Python 作为一种快速发展的解释性语言,使用 JIT 编译来产生这样的代码更好地补充了 Python 的交互式工作流,比 Python 的预先编译方式更好。
其他人正在尝试以非正统方式使用 LLVM 作为 JIT 编译方式,例如编译 PostgreSQL 查询,据说性能提高了五倍。
更多武汉IT培训相关资讯,请扫描下方二维码