これはRust Internal Advent Calender 12/17の記事です
xargo: The sysroot manager that lets you build and customize std
標準ライブラリと#![no_std]
xargoの説明をする前にRustの標準ライブラリについて確認しましょう。Rustにはcore
とstd
の名前空間があります。std
が通常の標準ライブラリ(libstd)を担うのに対し、core
はRust言語のための最小の標準ライブラリ(libcore)を提供します。
http://ykomatsu.github.io/rust/book-ja/no-stdlib.html
#![no_std]
属性を付けることによりstd
を使用せず、代わりにcore
を使用します。libcoreはlibstdよりも小さく依存関係も少ないため、libstdすべてが実装されていないなどの場合に使えます。Rust Platform Supportにlibstd/rustc/cargoの対応状況がまとめられています。現状stdが未対応なのはthumb*-none-eabi
と特殊なターゲットであるnvptx
だけです(例によってAccelの開発のための調査です)。
xargoはこのlibstdやlibcoreをカスタマイズしてコンパイルするためにユーティリティです。
Target Triple / sysroot
Rustがベースとしているコンパイル基盤LLVMにはTarget Tripleというアーキテクチャの指定方式があります。
The triple has the general format
<arch><sub>-<vendor>-<sys>-<abi>
, where:
arch = x86_64, i386, arm, thumb, mips, etc.
sub = for ex. on ARM: v5, v6m, v7a, v7m, etc.
vendor = pc, apple, nvidia, ibm, etc.
sys = none, linux, win32, darwin, cuda, etc.
abi = eabi, gnu, android, macho, elf, etc.
RustはバックエンドへのコンパイルをLLVMに頼っているため、アーキテクチャの指定はこれをそのまま使用します。
xargoはcargo互換のビルドコマンドですが、更にsysroot
管理機能があります。クロスコンパイルではそのターゲットに応じてリンクするライブラリを切り替える必要がありますが、ホスト側のlibcoreとターゲットのlibcoreがあってややこしいことになります。sysroot
はこの管理を簡単にするため、仮想的なroot directoryを用意してそこ以下のlib/
等を使います。xargoはこのディレクトリの管理とホストとターゲットの切り替えを実施してくれます。
この記事を書いてる段階では$HOME/.xargo
以下にターゲット毎にlibcore
等が用意されます。
xargoの使い方
READMEに詳しく書いてます!(`・ω・´)キリッ
https://github.com/japaric/xargo
なので要点だけ短めに・・・
xargoはcargoのコマンドがそのまま使えます。build
だけでなくpublish
等も使えるのでターゲット依存のコードが入っていてもアップロードできます。クロスコンパイル時は--target
でターゲットを指定します:
xargo build --target thumbv6m-none-eabi
xargoはcargoと違ってデフォルトでlibstd ではなく libcoreをリンクします。
libstdをリンクするにはXargo.toml
ファイルを作成する必要があります:
[target.thumbv6m-none-eabi.dependencies]
collections = {}
これでlibcoreに加えて[libcollection]がリンクされます。
[target.i686-unknown-linux-gnu.dependencies.std]
features = ["jemalloc"]
これはi686-unknown-linux-gnu
ターゲットの場合にlibstdをjemallocオプションでコンパイルします。このようにクロスコンパイルではなく、カスタムなstdを作成するのにもxargoを使用できます。
カスタムターゲット
Rust Platform Supportにあるターゲットに対しては上で十分ですが、nvptx
や他のサポートされていないターゲットに対しても、自分でターゲットを記述することによってクロスコンパイルすることが可能です。nvptx
についてはjaparic/nvptxの方に詳しい記述があります:1
{
"arch": "nvptx64",
"cpu": "sm_20",
"data-layout": "e-i64:64-v16:16-v32:32-n16:32:64",
"linker": "false",
"linker-flavor": "ld",
"llvm-target": "nvptx64-nvidia-cuda",
"max-atomic-width": 0,
"os": "cuda",
"panic-strategy": "abort",
"target-c-int-width": "32",
"target-endian": "little",
"target-pointer-width": "64"
}
これをXargo.tomlの横に置くことで以下が実行できます:
xargo build --target nvptx64-nvidia-cuda
nvptx
はstdが対応していないのでlibcoreを使うことになります。この時使うlibcoreを指定することもできます2:
[dependencies.core]
git = "https://github.com/japaric/core64"
rev = "0e29675fda37afa727f96818dabd8cbfb969dba4"
最後に
皆さんもクリスマスプレゼントとして新しいアーキテクチャを手に入れたと思いますので、是非この機会にRustのクロスコンパイルをお試しください(`・ω・´)
-
あるいはdenzp/rust-ptx-linkerの改良版を使う方がいいかもしれません ↩