- GraalVM for JDK 23 (最新)
- GraalVM for JDK 24 (早期アクセス)
- GraalVM for JDK 21
- GraalVM for JDK 17
- アーカイブ
- 開発ビルド
LLVMビットコードへのコンパイル
GraalVMは、LLVMビットコードにコンパイルできるC/C++、Rustなどの言語を実行できます。最初のステップとして、LLVMコンパイラのフロントエンド(例:CおよびC++の場合はclang
、Rustの場合はrust
など)を使用して、プログラムをLLVMビットコードにコンパイルする必要があります。
ファイル形式 #
GraalVM LLVMランタイムはプレーンなビットコードファイルを実行できますが、推奨される形式は、埋め込みビットコードを持つネイティブ実行ファイルです。実行ファイル形式はLinuxとmacOSで異なります。LinuxはデフォルトでELFファイルを使用します。ビットコードは.llvmbc
というセクションに格納されます。macOSプラットフォームはMach-Oファイルを使用します。ビットコードは__LLVM
セグメントの__bundle
セクションにあります。
埋め込みビットコードを持つネイティブ実行ファイルを使用すると、プレーンなビットコードファイルに比べて2つの利点があります。まず、ネイティブプロジェクトのビルドシステム(例: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はその後、ビットコードを実行しようとしますが、予期せぬ方法でランダムに失敗する可能性があります。