Targeting ARM64 for Windows in Rust

Published on Tuesday, May 26, 2020

I wanted to run a thing I'm building with Rust on my Surface Pro X which is an ARM64 device the other day. My initial thought when I got the idea, was "I hope it's not complicated to do".

TLDR; it wasn't.

Toolchain targets

One thing to be aware of is that ARM64, or aarch64-pc-windows-msvc as the toolchain target is known as, is that it belongs in tier 2 of Rust's platform support.

While tier 1 is "Guaranteed to run", tier 2 is only "Guaranteed to build".

Tier 2 platforms can be thought of as "guaranteed to build". Automated tests are not run, so it's not guaranteed to produce a working build, but platforms often work to quite a good degree [...]

So what do the different parts in the toolchain target name mean?

aarch64 This is the platform architecture we're targeting, in this case, ARM64.
pc-windows This is the operating system we're targeting, in this case, Windows.
msvc This is the compiler we want to use. MSVC is an abbreviation of "Microsoft Visual C++".

If you're interested in reading more about the different supported platforms in Rust, you can find the full list over at
https://forge.rust-lang.org/release/platform-support.html.

Installing the toolchain target

Rust supports cross-compilation, so there's no need to build our ARM64 app on an ARM64 machine, and even if we wanted to, it would prove difficult since essential tools like Cargo isn't available for ARM64 on Windows. The only prerequisite for cross-compiling is a compiler that can target the desired platform and all the necessary dependencies required to compile the code.

To compile our application for ARM64, we need to install the aarch64-pc-windows-msvc target for our Rust compiler toolchain.

> rustup target install aarch64-pc-windows-msvc

If you want to see what toolchain targets are available or installed, you can use the rustup target list command.

> rustup target list
aarch64-apple-ios
aarch64-fuchsia
aarch64-linux-android
aarch64-pc-windows-msvc (installed)
aarch64-unknown-linux-gnu

Building for ARM64

Now when the correct toolchain target has been installed, let's go ahead and create a new binary and build it with our newly installed target.

> cargo build --target=aarch64-pc-windows-msvc
   Compiling helloworld v0.1.0 (D:\Source\local\helloworld)
    Finished dev [unoptimized + debuginfo] target(s) in 0.36s

Automatically build with a specific target

If you always want to build for this target, you can create.cargo/config in your repository root and add the following contents to it:

[build]
target = "aarch64-pc-windows-msvc"

Running on an ARM64 machine

Everything compiled! Not a big surprise, it's "Guaranteed to build" after all, but it felt good anyway. Time to test it out on an actual ARM64 machine.

> ./helloworld.exe
-1073741515

Oh noes

The application exited with the error code -1073741515, more famously known as 0xC0000135, which is Windows' way of telling us that an essential component is missing. It turns out that we need to install the Microsoft Visual C++ Redistributable for Visual Studio 2019 for ARM64.

Installing the MSVC redistributable and rerunning our app now produces the expected output.

> ./helloworld.exe
Hello World

Wrapping up

Not super complicated stuff, but hopefully this post has been useful for you if you wanted to learn more about Rust's different platform tiers, toolchain targets, and cross-compilation.