コンパイラサポートに関する覚書

本書はthumbv7m-none-eabiというコンパイラ組込みのターゲットを使いました。 このターゲットに対しては、Rustチームが、 corestdのようなコンパイル済みのクレート一式をrust-stdコンポーネントとして配布しています。

本書の内容を異なるターゲットアーキテクチャで再現したい場合、 Rustが(コンパイル)ターゲットに対して提供している異なるサポートレベルを考慮しなければなりません。

LLVMサポート

Rust 1.28現在、公式のRustコンパイラであるrustcは、(機械語)コード生成にLLVMを使用しています。 あるアーキテクチャに対して、Rustが提供する最低レベルのサポートは、rustcで有効化されているLLVMバックエンドがあることです。 次のコマンドを実行することで、LLVMを通して、rustcがサポートする全てのアーキテクチャを見ることができます。

$ # このコマンドを実行するためには、`cargo-binutils`のインストールが必要です
$ cargo objdump -- -version
LLVM (http://llvm.org/):
  LLVM version 7.0.0svn
  Optimized build.
  Default target: x86_64-unknown-linux-gnu
  Host CPU: skylake

  Registered Targets:
    aarch64    - AArch64 (little endian)
    aarch64_be - AArch64 (big endian)
    arm        - ARM
    arm64      - ARM64 (little endian)
    armeb      - ARM (big endian)
    hexagon    - Hexagon
    mips       - Mips
    mips64     - Mips64 [experimental]
    mips64el   - Mips64el [experimental]
    mipsel     - Mipsel
    msp430     - MSP430 [experimental]
    nvptx      - NVIDIA PTX 32-bit
    nvptx64    - NVIDIA PTX 64-bit
    ppc32      - PowerPC 32
    ppc64      - PowerPC 64
    ppc64le    - PowerPC 64 LE
    sparc      - Sparc
    sparcel    - Sparc LE
    sparcv9    - Sparc V9
    systemz    - SystemZ
    thumb      - Thumb
    thumbeb    - Thumb (big endian)
    wasm32     - WebAssembly 32-bit
    wasm64     - WebAssembly 64-bit
    x86        - 32-bit X86: Pentium-Pro and above
    x86-64     - 64-bit X86: EM64T and AMD64

LLVMが興味のあるアーキテクチャをサポートしており、rustcがそのバックエンドを無効化してビルドされた(Rust 1.28でのAVR)場合、 ターゲットを有効化するためにRustのソースコードを修正しなければなりません。 Pull Request rust-lang/rust#52787の最初の2つのコミットが、必要な変更のヒントになります。

その一方、LLVMがアーキテクチャをサポートしていませんが、LLVMのフォークがサポートできる場合、 rustcをビルドする前に、オリジナルのLLVMをフォークで置き換えなければなりません。 Rustビルドシステムはこれができるようになっており、原則としては、フォークを指すようにllvmサブモジュールを単に変更するだけです。

もしベンダ提供のGCCでしかターゲットアーキテクチャがサポートされていない場合、mrustcを使う選択肢があります。 これは、非公式のRustコンパイラで、RustプログラムをCコードに変換し、その後、GCCを使ってコンパイルします。

組込みのターゲット

コンパイルターゲットは、アーキテクチャだけではありません。各ターゲットは関連する仕様があり、 特に、アーキテクチャ、オペレーティングシステム、デフォルトリンカが記載されています。

Rustコンパイラはいくつかのターゲットについて知っています。これらのターゲットは、コンパイラに組み込まれている、 と呼ばれており、次のコマンドでリストを表示できます。

$ rustc --print target-list | column
aarch64-fuchsia                 mips64el-unknown-linux-gnuabi64
aarch64-linux-android           mipsel-unknown-linux-gnu
aarch64-unknown-cloudabi        mipsel-unknown-linux-musl
aarch64-unknown-freebsd         mipsel-unknown-linux-uclibc
aarch64-unknown-linux-gnu       msp430-none-elf
aarch64-unknown-linux-musl      powerpc-unknown-linux-gnu
aarch64-unknown-openbsd         powerpc-unknown-linux-gnuspe
arm-linux-androideabi           powerpc-unknown-netbsd
arm-unknown-linux-gnueabi       powerpc64-unknown-linux-gnu
arm-unknown-linux-gnueabihf     powerpc64le-unknown-linux-gnu
arm-unknown-linux-musleabi      powerpc64le-unknown-linux-musl
arm-unknown-linux-musleabihf    s390x-unknown-linux-gnu
armebv7r-none-eabihf            sparc-unknown-linux-gnu
armv4t-unknown-linux-gnueabi    sparc64-unknown-linux-gnu
armv5te-unknown-linux-gnueabi   sparc64-unknown-netbsd
armv5te-unknown-linux-musleabi  sparcv9-sun-solaris
armv6-unknown-netbsd-eabihf     thumbv6m-none-eabi
armv7-linux-androideabi         thumbv7em-none-eabi
armv7-unknown-cloudabi-eabihf   thumbv7em-none-eabihf
armv7-unknown-linux-gnueabihf   thumbv7m-none-eabi
armv7-unknown-linux-musleabihf  wasm32-experimental-emscripten
armv7-unknown-netbsd-eabihf     wasm32-unknown-emscripten
asmjs-unknown-emscripten        wasm32-unknown-unknown
i586-pc-windows-msvc            x86_64-apple-darwin
i586-unknown-linux-gnu          x86_64-fuchsia
i586-unknown-linux-musl         x86_64-linux-android
i686-apple-darwin               x86_64-pc-windows-gnu
i686-linux-android              x86_64-pc-windows-msvc
i686-pc-windows-gnu             x86_64-rumprun-netbsd
i686-pc-windows-msvc            x86_64-sun-solaris
i686-unknown-cloudabi           x86_64-unknown-bitrig
i686-unknown-dragonfly          x86_64-unknown-cloudabi
i686-unknown-freebsd            x86_64-unknown-dragonfly
i686-unknown-haiku              x86_64-unknown-freebsd
i686-unknown-linux-gnu          x86_64-unknown-haiku
i686-unknown-linux-musl         x86_64-unknown-l4re-uclibc
i686-unknown-netbsd             x86_64-unknown-linux-gnu
i686-unknown-openbsd            x86_64-unknown-linux-gnux32
mips-unknown-linux-gnu          x86_64-unknown-linux-musl
mips-unknown-linux-musl         x86_64-unknown-netbsd
mips-unknown-linux-uclibc       x86_64-unknown-openbsd
mips64-unknown-linux-gnuabi64   x86_64-unknown-redox

次のコマンドを使って、これらターゲットの仕様を表示できます。

$ rustc +nightly -Z unstable-options --print target-spec-json --target thumbv7m-none-eabi
{
  "abi-blacklist": [
    "stdcall",
    "fastcall",
    "vectorcall",
    "thiscall",
    "win64",
    "sysv64"
  ],
  "arch": "arm",
  "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64",
  "emit-debug-gdb-scripts": false,
  "env": "",
  "executables": true,
  "is-builtin": true,
  "linker": "arm-none-eabi-gcc",
  "linker-flavor": "gcc",
  "llvm-target": "thumbv7m-none-eabi",
  "max-atomic-width": 32,
  "os": "none",
  "panic-strategy": "abort",
  "relocation-model": "static",
  "target-c-int-width": "32",
  "target-endian": "little",
  "target-pointer-width": "32",
  "vendor": ""
}

ターゲットシステムに対して適切な組込みのターゲットが無い場合、JSON形式のファイルにターゲット仕様を記述するカスタムターゲットを作らなければなりません。 推奨する方法は、ターゲットシステムに似ている組込みターゲットの仕様をファイルに書き出し、ターゲットシステムに適合するように微調整することです。 そのために、先程見せたrustc --print target-spec-jsonコマンドを使用します。 Rust 1.28では、ターゲット仕様の各フィールドが何を意味するか説明する最新のドキュメントがコンパイラソースコード以外ありません。

ターゲット仕様ファイルを作れば、ファイルパスを指定するか、カレントディレクトリか$RUST_TARGET_PATHにあるのであれば、 その名前で参照することができます。

$ rustc +nightly -Z unstable-options --print target-spec-json \
      --target thumbv7m-none-eabi \
      > foo.json

$ rustc --print cfg --target foo.json # もしくは単に --target foo
debug_assertions
target_arch="arm"
target_endian="little"
target_env=""
target_feature="mclass"
target_feature="v7"
target_has_atomic="16"
target_has_atomic="32"
target_has_atomic="8"
target_has_atomic="cas"
target_has_atomic="ptr"
target_os="none"
target_pointer_width="32"
target_vendor=""

rust-stdコンポーネント

いくつかの組込みターゲットに対して、Rustチームはrustup経由でrust-stdコンポーネントを配布しています。 このコンポーネントは、コンパイル済みのcorestdといったクレート一式です。 そして、このコンポーネントは、クロスコンパイルに必要です。

次のコマンドを実行すると、rustup経由で利用可能なrust-stdコンポーネントを持つターゲット一覧が得られます。

$ rustup target list | column
aarch64-apple-ios                       mips64-unknown-linux-gnuabi64
aarch64-linux-android                   mips64el-unknown-linux-gnuabi64
aarch64-unknown-fuchsia                 mipsel-unknown-linux-gnu
aarch64-unknown-linux-gnu               mipsel-unknown-linux-musl
aarch64-unknown-linux-musl              powerpc-unknown-linux-gnu
arm-linux-androideabi                   powerpc64-unknown-linux-gnu
arm-unknown-linux-gnueabi               powerpc64le-unknown-linux-gnu
arm-unknown-linux-gnueabihf             s390x-unknown-linux-gnu
arm-unknown-linux-musleabi              sparc64-unknown-linux-gnu
arm-unknown-linux-musleabihf            sparcv9-sun-solaris
armv5te-unknown-linux-gnueabi           thumbv6m-none-eabi
armv5te-unknown-linux-musleabi          thumbv7em-none-eabi
armv7-apple-ios                         thumbv7em-none-eabihf
armv7-linux-androideabi                 thumbv7m-none-eabi
armv7-unknown-linux-gnueabihf           wasm32-unknown-emscripten
armv7-unknown-linux-musleabihf          wasm32-unknown-unknown
armv7s-apple-ios                        x86_64-apple-darwin
asmjs-unknown-emscripten                x86_64-apple-ios
i386-apple-ios                          x86_64-linux-android
i586-pc-windows-msvc                    x86_64-pc-windows-gnu
i586-unknown-linux-gnu                  x86_64-pc-windows-msvc
i586-unknown-linux-musl                 x86_64-rumprun-netbsd
i686-apple-darwin                       x86_64-sun-solaris
i686-linux-android                      x86_64-unknown-cloudabi
i686-pc-windows-gnu                     x86_64-unknown-freebsd
i686-pc-windows-msvc                    x86_64-unknown-fuchsia
i686-unknown-freebsd                    x86_64-unknown-linux-gnu (default)
i686-unknown-linux-gnu                  x86_64-unknown-linux-gnux32
i686-unknown-linux-musl                 x86_64-unknown-linux-musl
mips-unknown-linux-gnu                  x86_64-unknown-netbsd
mips-unknown-linux-musl                 x86_64-unknown-redox

ターゲットにrust-stdコンポーネントがない場合、あるいは、カスタムターゲットを使っている場合、 coreクレートをCargoでコンパイルさせるために、Xargoのようなツールが必要です。 Xargoはnightlyツールチェインを要求することに注意して下さい。長期計画では、Xargoの機能はCargoに取り込まれ、 最終的には安定版でその機能が利用可能になるはずです。