xargoによるRustのクロスコンパイル

これはRust Internal Advent Calender 12/17の記事です

[xargo: The sysroot manager that lets you build and customize `std`](https://github.com/japaric/xargo)

標準ライブラリと`#![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](https://forge.rust-lang.org/platform-support.html)にlibstd/rustc/cargoの対応状況がまとめられています。現状stdが未対応なのは`thumb*-none-eabi`と特殊なターゲットである`nvptx`だけです（例によって[Accel](https://qiita.com/termoshtt/items/41b4e23c4ce5e822319c)の開発のための調査です）。
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.

https://clang.llvm.org/docs/CrossCompilation.html

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`ファイルを作成する必要があります：

```toml:Xargo.toml
[target.thumbv6m-none-eabi.dependencies]
collections = {}
```

これでlibcoreに加えて[libcollection]がリンクされます。

```toml:Xargo.toml
[target.i686-unknown-linux-gnu.dependencies.std]
features = ["jemalloc"]
```

これは`i686-unknown-linux-gnu`ターゲットの場合にlibstdをjemallocオプションでコンパイルします。このようにクロスコンパイルではなく、カスタムなstdを作成するのにもxargoを使用できます。

### カスタムターゲット
[Rust Platform Support](https://forge.rust-lang.org/platform-support.html)にあるターゲットに対しては上で十分ですが、`nvptx`や他のサポートされていないターゲットに対しても、自分でターゲットを記述することによってクロスコンパイルすることが可能です。`nvptx`については[japaric/nvptx](https://github.com/japaric/nvptx)の方に詳しい記述があります:[^1]

[^1]: あるいは[denzp/rust-ptx-linker](https://github.com/denzp/rust-ptx-linker)の改良版を使う方がいいかもしれません


```json:nvptx64-nvidia-cuda.json
{
    "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]：

[^2]: [termoshtt/accel:src/ptx_builder/Xargo.toml](https://github.com/termoshtt/accel/blob/master/src/ptx_builder/Xargo.toml)

```toml:Xargo.toml
[dependencies.core]
git = "https://github.com/japaric/core64"
rev = "0e29675fda37afa727f96818dabd8cbfb969dba4"
```

最後に
-------
皆さんもクリスマスプレゼントとして新しいアーキテクチャを手に入れたと思いますので、是非この機会にRustのクロスコンパイルをお試しください(｀・ω・´)