Cross compiling, how to statically link GLIBC?

Hi there!

I'd like to write a tool I'd want to deploy to various devices with ARM processors and low RAM. So I need cross compilation.

So I started with:

cargo new rust_playground_2022-11-07
cd rust_playground_2022-11-07
rustup target add aarch64-unknown-linux-gnu
cargo build --release --target aarch64-unknown-linux-gnu

that failed with

error: linking with cc failed: exit status: 1
|
= note: "cc" "/tmp/rustcD3oCV3/symbols.o" "/home/user/Development/rust_playground_2022-11-07/target/aarch64-unknown-linux-gnu/release/deps/rust_playground_2022_11_07-63d177ba784ab869.rust_playground_2022_11_07.2f54b6d2-cgu.0.rcgu.o" "-Wl,--as-needed" "-L" "/home/user/Development/rust_playground_2022-11-07/target/aarch64-unknown-linux-gnu/release/deps" "-L" "/home/user/Development/rust_playground_2022-11-07/target/release/deps" "-L" "/home/user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/aarch64-unknown-linux-gnu/lib" "-Wl,--start-group" "-Wl,--end-group" "-Wl,-Bstatic" "/home/user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/aarch64-unknown-linux-gnu/lib/libcompiler_builtins-8cbeb5ac4095b356.rlib" "-Wl,-Bdynamic" "-lgcc_s" "-lutil" "-lrt" "-lpthread" "-lm" "-ldl" "-lc" "-Wl,--eh-frame-hdr" "-Wl,-znoexecstack" "-L" "/home/user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/aarch64-unknown-linux-gnu/lib" "-o" "/home/user/Development/rust_playground_2022-11-07/target/aarch64-unknown-linux-gnu/release/deps/rust_playground_2022_11_07-63d177ba784ab869" "-Wl,--gc-sections" "-pie" "-Wl,-zrelro,-znow" "-Wl,--strip-all" "-nodefaultlibs"
= note: /usr/bin/ld: /home/user/Development/rust_playground_2022-11-07/target/aarch64-unknown-linux-gnu/release/deps/rust_playground_2022_11_07-63d177ba784ab869.rust_playground_2022_11_07.2f54b6d2-cgu.0.rcgu.o: Relocations in generic ELF (EM: 183)

I found the solution for that problem here:

sudo pacman -S aarch64-linux-gnu-gcc
echo '[target.aarch64-unknown-linux-gnu]
linker = "aarch64-linux-gnu-gcc"' >> ~/.cargo/config

Now the build succeeds, but the resulting binary even though it's enormous 4mb big, still is identified as "dynamically linked" by file and doesn't print the expected "Hello, world!" when run but instead:

./rust_playground_2022-11-07: /lib/aarch64-linux-gnu/libc.so.6: version `GLIBC_2.33' not found (required by ./rust_playground_2022-11-07)
./rust_playground_2022-11-07: /lib/aarch64-linux-gnu/libc.so.6: version `GLIBC_2.32' not found (required by ./rust_playground_2022-11-07)
./rust_playground_2022-11-07: /lib/aarch64-linux-gnu/libc.so.6: version `GLIBC_2.34' not found (required by ./rust_playground_2022-11-07)

Ah, now I found a solution!

cargo new rust_playground_2022-11-07
cd rust_playground_2022-11-07
rustup target add aarch64-unknown-linux-musl
echo '[target.aarch64-unknown-linux-musl]
linker = "aarch64-linux-gnu-gcc"' >> ~/.cargo/config
cargo build --release --target aarch64-unknown-linux-musl

The resulting 4.1mb binary runs fine on my target machine.


And after adding this block to my Cargo.toml file:

# https://stackoverflow.com/questions/29008127/why-are-rust-executables-so-huge
[profile.release]
opt-level = 'z'     # Optimize for size.
lto = true          # Enable Link Time Optimization
codegen-units = 1   # Reduce number of codegen units to increase optimizations.
panic = 'abort'     # Abort on panic
strip = true        # Strip symbols from binary*

I got that hello world binary down to 321kb, still not what I'd expect for a Hello World, but down one factor of 10.