Cross-compilation using Debian Rust, not rustup

I need to cross-compile a Rust program (x86-64 to arm64), but I'm working in environment where I have to use Debian's rust package (because company policy forbids curl | sh). Debian doesn't ship rustup, and rustup refuses to install if Debian's rust is installed anyway.

How can I add a target without rustup?

I think technically you should install the libstd-rust-dev:arm64 package, but I don't think you can actually do that with the way APT multiarch works.

Edit: maybe you can? See Multiarch/HOWTO - Debian Wiki and MultiarchCross - Ubuntu Wiki

Thanks! I've tried

dpkg --add-architecture aarch64
apt-get build-dep -a aarch64 libstd-rust-dev

but apt says it's not installable :frowning:

The following packages have unmet dependencies:
 builddeps:rustc:aarch64 : Depends: libllvm4.0:aarch64 (>= 1:4.0.1-8) but it is not installable
                           Depends: rustc:aarch64 but it is not installable
                           Depends: zlib1g-dev:aarch64 but it is not installable
                           Depends: binutils:aarch64 (>= 2.26) but it is not installable or
                                    binutils-2.26:aarch64 but it is not installable
                           Depends: gdb:aarch64 (>= 7.12) but it is not installable

I think you want apt-get install, not apt-get build-dep. apt-get build-dep X installs the dependencies needed to build X, not X itself. If you did want to build the standard library yourself, it would probably make more sense to build the compiler along with it.

It might also be possible to use xargo.

Might be more trouble than it's worth, but can you spin up a VM and use rustup in the VM?

Unfortunately apt-get install doesn't support -a "Command line option 'a' [from -a] is not understood in combination with the other options."

No, the build is already running in a VM. I'm just not allowed to use curl | sh hack, anywhere, at all. Company Policy, and I'm not going to stick my neck out in defense of piping to bash.

  1. Download Rustup
  2. Audit it (it's a script, right?)
  3. Make it exectuable
  4. Execute it

Then, you aren't "curl ... | sh" if that is the only thing they are concerned about.

You can also download the platform-specific rustup-init directly: https://github.com/rust-lang-nursery/rustup.rs/#other-installation-methods

The old rustup was shell, current one is in rust and the script just downloads the rustup binary.

Try apt-get install libstd-rust-dev:arm64

edit: arm64 not aarch64

1 Like

Unfortunately, "E: Unable to locate package libstd-rust-dev:aarch64"

BTW, if I install apt-get install libstd-rust-dev I get 1.24.1+dfsg1-1~deb9u2, but my Rust is 1.28.0-1, so I'm not sure if it's going to work at all.

Oops, should be arm64 not aarch64.

Same error :frowning:

Try apt-get update – you need to do that after dpkg --add-architecture if you haven't already.

1 Like

Ahh, I did dpkg --add-architecture aarch64 instead of dpkg --add-architecture arm64 before. It installs now!

1 Like

but unfortunately it doesn't have the desired effect:

error[E0463]: can't find crate for std
|
= note: the aarch64-unknown-linux-gnu target may not be installed

I've got

  • /usr/lib/rustlib/aarch64-unknown-linux-gnu/lib/libstd-f5a209a9.rlib
  • /usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-0cce0e0e34e933aa.rlib

I think you might have some version mismatch. You say your rustc is version 1.28.0-1, but that's not a version that is distributed by Debian. All Debian-packaged Rust packages have dfsg in the version. You'll need to obtain the ARM64 libstd from whomever packaged your Rust installation.

1 Like

I put some effort into the original rustc Debian packaging to make this "just work". So just to summarise the above thread into one place, here's an example of cross-compiling for aarch64-unknown-linux-gnu (using Debian "testing"):

Note the Debian name for this architecture is arm64. In practice, you would combine the various apt install invocations for a slight increase in overall speed - I've broken them out only for clarity.

dpkg --add-architecture arm64
apt update
# Important part here is "libstd-rust-dev:arm64"
apt install cargo rustc libstd-rust-dev:arm64

If you need to install something that uses gcc/g++ from build.rs then you'll need a C cross-toolchain

apt install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu

Tell cargo to use the right linker when cross compiling. Note this is ~/.cargo/config, not in a specific project, and note cargo/rustc expect to link via gcc, not ld directly.

cat <<EOF >>~/.cargo/config
[target.aarch64-unknown-linux-gnu]
linker = "/usr/bin/aarch64-linux-gnu-gcc"
EOF

Note you might need extra native libraries, depending on crates in use. Eg, openssl-sys requires:

apt install libssl-dev:arm64
export PKG_CONFIG_ALLOW_CROSS=1

Ready!

cargo build --target aarch64-unknown-linux-gnu

file target/aarch64-unknown-linux-gnu/debug/mytest
target/aarch64-unknown-linux-gnu/debug/mytest: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, for GNU/Linux 3.7.0, BuildID[sha1]=831ce6f2b01537416207ed67ed8ef09920144bbe, with debug_info, not stripped
  1. Profit.
4 Likes

Here is a full working Dockerfile environment for anyone who wants to build AWS Lambda functions :

FROM rust:latest

RUN dpkg --add-architecture arm64
RUN apt update && apt upgrade -y
RUN apt install -y g++-aarch64-linux-gnu libc6-dev-arm64-cross libssl-dev:arm64 pkg-config

RUN rustup target add aarch64-unknown-linux-gnu
RUN rustup toolchain install stable-aarch64-unknown-linux-gnu

WORKDIR /app

ENV PKG_CONFIG_ALLOW_CROSS=1 \
    CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \
    CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc \
    CXX_aarch64_unknown_linux_gnu=aarch64-linux-gnu-g++

CMD ["cargo", "build", "--target", "aarch64-unknown-linux-gnu"]

# To build the image
#   docker build . -t rust_cross_compile/aarch64 -f Dockerfile.aarch64
# In your Rust project
#   docker run --rm -ti -v ${pwd}:/app rust_cross_compile/aarch64
2 Likes