Rustcに付随しているLLVMを使う

注:以下の方法はWindows(*-pc-windows-msvc)では使えません

Rustはアセンブラを生成するためにLLVMのライブラリを使います。これはtoolchainに含まれていて、例えばお手元の~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/codegen-backendsを覗いてみてください(ちなみにlibcoreやlibstdもこの辺にあります)。ここにlibrustc_codegen_llvm-llvm.soという共有ファイルがあり、これにLLVMのライブラリが含まれています。

一方、ユーザーがRustでLLVMを使う方法としては、例えば以下の記事でも紹介されていますが、llvm-sysがあります。

llvm-sysは他の*-sys crateと同様に、システム(/usr)や他の場所にインストールされているLLVMを使います。しかしLLVMのインストールは存外面倒で、パッケージ管理システム(apt,dnf等)で入るものが古すぎたりします。

私はllvmenvというのを作って管理していたのですが、今回はrustc自体に含まれるLLVMを使う方法を紹介します。


rustc-llvm-proxy

https://github.com/denzp/rustc-llvm-proxy

このcrateは実行時にlibloadingを使って動的に共有ライブラリを読み込み、LLVMの関数を呼び出します。RustとのFFIにはllvm-sysを使います。


Cargo.toml

[dependencies]

rustc-llvm-proxy = "0.1"

[dependencies.llvm-sys]
version = "60.2"
features = ["no-llvm-linking"]


この様にllvm-sysno-llvm-linkingを指定します。これでシステムに(rustc自体と別個に)LLVMがインストールされていなくてもrustc自体の使っているLLVMを使う事ができます。これにより


  • rustcのコード生成と同じLLVMのビルドを使うことができる

  • システムのLLVMに依存しない

の2点が解決されます。


main.rs

extern crate llvm_sys;

extern crate rustc_llvm_proxy;

の様にextern crateだけしておけば後はllvm-sysの場合と同じです。参考に上記の記事のコードをコンパイルできる形にしたものをrustc-llvm-proxy-exampleにおいておきます。


追記


追記2


  • rustc-llvm-proxy 0.1.3ではLLVM_InitializeAllTarget等の初期化マクロが呼べません。個別のターゲットごとの初期化を使うか、以下のPRを使ってください https://github.com/denzp/rustc-llvm-proxy/pull/4