- 适用于 JDK 24 的 GraalVM(最新)
- 适用于 JDK 25 的 GraalVM(早期访问)
- 适用于 JDK 21 的 GraalVM
- 适用于 JDK 17 的 GraalVM
- 存档
- 开发构建
编译为 LLVM 位码
GraalVM 可以执行 C/C++、Rust 以及其他可编译为 LLVM 位码的语言。第一步,您必须使用某个 LLVM 编译器前端将程序编译为 LLVM 位码,例如 C 和 C++ 使用 clang
,Rust 编程语言使用 rust
等。
文件格式 #
虽然 GraalVM LLVM 运行时可以执行 纯位码文件,但首选格式是包含嵌入式位码的本地可执行文件。可执行文件格式在 Linux 和 macOS 上有所不同。Linux 默认使用 ELF 文件。位码存储在名为 .llvmbc
的节中。macOS 平台使用 Mach-O 文件。位码位于 __LLVM
段的 __bundle
节中。
使用嵌入位码的本地可执行文件比纯位码文件具有两个优势。首先,本地项目的构建系统(例如 Makefile
)期望结果是可执行文件。嵌入位码而非更改输出格式可提高与现有项目的兼容性。其次,可执行文件允许指定库依赖项,这在 LLVM 位码中是不可能的。GraalVM LLVM 运行时利用此信息来查找和加载依赖项。
用于编译 C/C++ 的 LLVM 工具链 #
为简化将 C/C++ 编译为包含嵌入式位码的可执行文件,LLVM 运行时附带了一个预构建的 LLVM 工具链。该工具链包含用于 C 的 clang
或用于 C++ 的 clang++
等编译器,还包含构建本地项目所需的其他工具,例如链接器(ld
)或用于创建静态库的归档器(ar
)。
- 使用
lli
的--print-toolchain-path
参数获取工具链的位置./path/to/bin/lli --print-toolchain-path
- 设置
LLVM_TOOLCHAIN
环境变量export LLVM_TOOLCHAIN=$(./path/to/bin/lli --print-toolchain-path)
- 然后查看工具链路径的内容以获取可用工具列表
ls $LLVM_TOOLCHAIN
使用这些工具就像您进行本地编译一样。例如,将此 C 代码保存到名为 hello.c
的文件中
#include <stdio.h>
int main() {
printf("Hello from GraalVM!\n");
return 0;
}
然后您可以按如下方式将 hello.c
编译为包含嵌入式 LLVM 位码的可执行文件
$LLVM_TOOLCHAIN/clang hello.c -o hello
生成的可执行文件 hello
可以使用 lli
在 GraalVM 上执行
$JAVA_HOME/bin/lli hello
外部库依赖项 #
如果位码文件依赖于外部库,GraalVM 将自动从二进制头文件中获取依赖项。例如
#include <unistd.h>
#include <ncurses.h>
int main() {
initscr();
printw("Hello, Curses!");
refresh();
sleep(1);
endwin();
return 0;
}
然后,此 hello-curses.c 文件可以通过以下方式编译和运行
$LLVM_TOOLCHAIN/clang hello-curses.c -lncurses -o hello-curses
lli hello-curses
运行 C++ #
为了运行 C++ 代码,GraalVM LLVM 运行时需要来自 LLVM 项目的 libc++
标准库。GraalVM 附带的 LLVM 工具链会自动链接 libc++
。例如,将此代码保存为 hello-c++.cpp 文件
#include <iostream>
int main() {
std::cout << "Hello, C++ World!" << std::endl;
}
使用 GraalVM 附带的 clang++
编译并执行
$LLVM_TOOLCHAIN/clang++ hello-c++.cpp -o hello-c++
lli hello-c++
Hello, C++ World!
运行 Rust #
GraalVM 捆绑的 LLVM 工具链不附带 Rust 编译器。要安装 Rust,请在命令提示符中运行以下命令,然后按照屏幕上的说明操作
curl https://sh.rustup.rs -sSf | sh
将此 Rust 示例代码保存到 hello-rust.rs 文件中
fn main() {
println!("Hello Rust!");
}
然后可以使用 --emit=llvm-bc
标志将其编译为位码
rustc --emit=llvm-bc hello-rust.rs
要运行 Rust 程序,我们必须告诉 GraalVM 在何处查找 Rust 标准库
lli --lib $(rustc --print sysroot)/lib/libstd-* hello-rust.bc
Hello Rust!
由于 Rust 编译器未使用 GraalVM 附带的 LLVM 工具链,因此根据本地 Rust 安装情况,可能会出现以下类似错误之一
Mismatching target triple (expected x86_64-unknown-linux-gnu, got x86_64-pc-linux-gnu)
Mismatching target triple (expected x86_64-apple-macosx10.11.0, got x86_64-apple-darwin)
这表明 Rust 编译器使用的目标三元组与 GraalVM 附带的 LLVM 工具链不同。在这种特殊情况下,这些差异只是 Linux 发行版或 macOS 版本之间的不同命名约定,并没有真正的区别。在这种情况下,可以安全地忽略该错误
lli --experimental-options --llvm.verifyBitcode=false --lib $(rustc --print sysroot)/lib/libstd-* hello-rust.bc
仅在手动验证目标三元组确实兼容(即架构、操作系统和 C 库都匹配)后,才应使用此选项。例如,x86_64-unknown-linux-musl
和 x86_64-unknown-linux-gnu
确实不同,位码是为不同的 C 库编译的。--llvm.verifyBitcode=false
选项会禁用所有检查,GraalVM 将无论如何尝试运行位码,这可能会以意想不到的方式随机失败。