A note on compiler support
This book makes use of a built-in compiler target, the thumbv7m-none-eabi
, for which the Rust
team distributes a rust-std
component, which is a pre-compiled collection of crates like core
and std
.
If you want to attempt replicating the contents of this book for a different target architecture, you need to take into account the different levels of support that Rust provides for (compilation) targets.
LLVM support
As of Rust 1.28, the official Rust compiler, rustc
, uses LLVM for (machine) code generation. The
minimal level of support Rust provides for an architecture is having its LLVM backend enabled in
rustc
. You can see all the architectures that rustc
supports, through LLVM, by running the
following command:
$ # you need to have `cargo-binutils` installed to run this command
$ 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
If LLVM supports the architecture you are interested in, but rustc
is built with the backend
disabled (which is the case of AVR as of Rust 1.28), then you will need to modify the Rust source
enabling it. The first two commits of PR rust-lang/rust#52787 give you an idea of the required
changes.
On the other hand, if LLVM doesn't support the architecture, but a fork of LLVM does, you will have
to replace the original version of LLVM with the fork before building rustc
. The Rust build system
allows this and in principle it should just require changing the llvm
submodule to point to the fork.
If your target architecture is only supported by some vendor provided GCC, you have the option of
using mrustc
, an unofficial Rust compiler, to translate your Rust program into C code and then
compile that using GCC.
Built-in target
A compilation target is more than just its architecture. Each target has a specification associated to it that describes, among other things, its architecture, its operating system and the default linker.
The Rust compiler knows about several targets. These are said to be built into the compiler and can be listed by running the following command:
$ 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
You can print the specification of any of these targets using the following command:
$ 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": ""
}
If none of these built-in targets seems appropriate for your target system, you'll have to create a
custom target by writing your own target specification file in JSON format. The recommended way is to
dump the specification of a built-in target that's similar to your target system into a file and then
tweak it to match the properties of your target system. To do so, use the previously shown command,
rustc --print target-spec-json
. As of Rust 1.28, there's no up to date documentation on what each of
the fields of a target specification mean, other than the compiler source code.
Once you have a target specification file you can refer to it by its path or by its name if its in
the current directory or in $RUST_TARGET_PATH
.
$ rustc +nightly -Z unstable-options --print target-spec-json \
--target thumbv7m-none-eabi \
> foo.json
$ rustc --print cfg --target foo.json # or just --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
component
For some of the built-in target the Rust team distributes rust-std
components via rustup
. This
component is a collection of pre-compiled crates like core
and std
, and it's required for
cross compilation.
You can find the list of targets that have a rust-std
component available via rustup
by running
the following command:
$ 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
If there's no rust-std
component for your target or you are using a custom target, then you'll have
to use a tool like Xargo to have Cargo compile the core
crate on the fly. Note that Xargo
requires a nightly toolchain; the long term plan is to upstream Xargo's functionality into Cargo
and eventually have that functionality available on stable.