aarch64-linux-gnu + SSH config is selecting the wrong linker: x86_64-w64-mingw32-gcc instead of aarch64-linux-gnu-gcc
I am trying to use dinghy (for the first time) with an aarch64 embedded Linux platform, via SSH.
I'm on Ubuntu 24.04 with the aarch64-linux-gnu-gcc toolchain installed:
$ which aarch64-linux-gnu-gcc
/usr/bin/aarch64-linux-gnu-gcc
$ dpkg -S /usr/bin/aarch64-linux-gnu-gcc
gcc-aarch64-linux-gnu: /usr/bin/aarch64-linux-gnu-gcc
The sysroot appears to be installed to /usr/aarch64-linux-gnu/ by libc6-dev-arm64-cross and friends:
$ dpkg -S /usr/aarch64-linux-gnu
binutils-aarch64-linux-gnu, libstdc++6-arm64-cross, libtsan2-arm64-cross, liblsan0-arm64-cross, libitm1-arm64-cross, libgomp1-arm64-cross, libgcc-s1-arm64-cross, libc6-arm64-cross, libhwasan0-arm64-cross, libubsan1-arm64-cross, libasan8-arm64-cross, libatomic1-arm64-cross, linux-libc-dev-arm64-cross, libc6-dev-arm64-cross: /usr/aarch64-linux-gnu
I think I have the right Rust target installed:
$ rustup target install aarch64-unknown-linux-gnu
info: component 'rust-std' for target 'aarch64-unknown-linux-gnu' is up to date
So for this I have set up my .dinghy.toml as per the instructions:
[platforms.aarch64-linux]
rustc_triple = "aarch64-unknown-linux-gnu"
toolchain = "/usr"
[ssh_devices]
emb = { hostname="192.168.0.2", username="root", platform="aarch64-linux" }
When I run cargo dinghy -d emb test, the process tries to link with the wrong linker (some paths redacted with ...):
$ cargo dinghy -d emb test -v
Targeting platform aarch64-linux and device emb
...
error: linking with `/.../target/aarch64-unknown-linux-gnu/aarch64-linux/linker` failed: exit status: 1
|
= note: "/.../target/aarch64-unknown-linux-gnu/aarch64-linux/linker" "/tmp/rustcqwGjnM/symbols.o" "<21 object files omitted>" "-Wl,--as-needed" "-Wl,-Bstatic" "<sysroot>/lib/rustlib/aarch64-unknown-linux-gnu/lib/{libtest-*,libgetopts-*,libunicode_width-*,librustc_std_workspace_std-*,libstd-*,libpanic_unwind-*,libobject-*,libmemchr-*,libaddr2line-*,libgimli-*,librustc_demangle-*,libstd_detect-*,libhashbrown-*,librustc_std_workspace_alloc-*,libminiz_oxide-*,libadler2-*,libunwind-*,libcfg_if-*,liblibc-*,librustc_std_workspace_core-*,liballoc-*,libcore-*,libcompiler_builtins-*}.rlib" "-Wl,-Bdynamic" "-lgcc_s" "-lutil" "-lrt" "-lpthread" "-lm" "-ldl" "-lc" "-L" "/tmp/rustcqwGjnM/raw-dylibs" "-Wl,--eh-frame-hdr" "-Wl,-z,noexecstack" "-L" "<sysroot>/lib/rustlib/aarch64-unknown-linux-gnu/lib" "-o" "/.../target/aarch64-unknown-linux-gnu/debug/deps/test_dinghy-c9f0160be67509b8" "-Wl,--gc-sections" "-pie" "-Wl,-z,relro,-z,now" "-nodefaultlibs"
= note: some arguments are omitted. use `--verbose` to show all linker arguments
= note: /usr/bin/x86_64-w64-mingw32-ld: unrecognized option '--eh-frame-hdr'
/usr/bin/x86_64-w64-mingw32-ld: use the --help option for usage information
collect2: error: ld returned 1 exit status
This linker, /usr/bin/x86_64-w64-mingw32-ld, is obviously incorrect (it's a Windows cross-compiler!).
$ cat target/aarch64-unknown-linux-gnu/aarch64-linux/linker
#!/bin/sh
/usr/bin/x86_64-w64-mingw32-gcc "$@"
Any idea what's going wrong here? Why is the wrong linker being picked up?
Note: I have a .cargo/config.toml set up with:
[target.aarch64-unknown-linux-gnu]
linker = "aarch64-linux-gnu-gcc"
Thus, the following cross-compilation works: cargo build --target aarch64-unknown-linux-gnu, but I don't seem to be able to pass --target to cargo dinghy in any meaningful way.
Hey ! Thanks for your interest, sorry it did not work out of the box for you.
There is a (undocumented) flag you could try: add deb_multiarch='aarch64-linux-gnu' to the toolchain. Dinghy regular toolchain selection works by searching from the given toolchain directory something that look like a compiler or a linker. It works well with self-contained toolchains. On debian, the cross-platform toolchains are all installed together in the same directories so we need to give dinghy more hints so it can pick the right one.
@kali Thank you for the hint - that does indeed fix the linker error:
$ cat target/aarch64-unknown-linux-gnu/aarch64-linux/linker
#!/bin/sh
/usr/bin/aarch64-linux-gnu-gcc --sysroot / "$@"
For future users' benefit, it might be worth noting this in the docs, somewhere :)
I also have a Xilinx/PetaLinux 2024.2 SDK that seems problematic too - the toolchain is in:
$ ls ~/sdk/sysroots/x86_64-petalinux-linux/usr/bin/aarch64-xilinx-linux/ | grep gcc
aarch64-xilinx-linux-gcc
aarch64-xilinx-linux-gcc-ar
aarch64-xilinx-linux-gcc-nm
aarch64-xilinx-linux-gcc-ranlib
I set toolchain to:
toolchain = "/home/user/sdk/sysroots/x86_64-petalinux-linux/usr/bin/aarch64-xilinx-linux/"
However, it seems that cargo-dinghy is explicitly looking for a bin/ subdirectory in the toolchain directory, because:
$ cargo dinghy -d emb test -v
[2025-10-23T22:12:48Z ERROR cargo_dinghy] Could not assemble platform aarch64-xilinx-linux
Caused by:
0: failed to read directory `/home/user/sdk/sysroots/x86_64-petalinux-linux/usr/bin/aarch64-xilinx-linux/bin`
1: No such file or directory (os error 2)
This might be a quirk of how Yocto/PetaLinux organises its sysroots, or maybe dinghy is being too strict with expected paths?
Is there a way to let dinghy just pick up the cross-compiler toolchain from the environment?
For example, there's a script supplied by the SDK called environment-setup-cortexa72-cortexa53-xilinx-linux that sets up a bunch of env-vars like PATH, CROSS_COMPILE to make the SDK work "by default" (and this also works with general Cargo builds):
$ env | grep aarch
GDB=aarch64-xilinx-linux-gdb
CPP=aarch64-xilinx-linux-gcc -E -mcpu=cortex-a72.cortex-a53+crc -mbranch-protection=standard -fstack-protector-strong -O2 -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security -Werror=format-security --sysroot=/home/user/sdk/sysroots/cortexa72-cortexa53-xilinx-linux
TARGET_PREFIX=aarch64-xilinx-linux-
CXX=aarch64-xilinx-linux-g++ -mcpu=cortex-a72.cortex-a53+crc -mbranch-protection=standard -fstack-protector-strong -O2 -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security -Werror=format-security --sysroot=/home/user/sdk/sysroots/cortexa72-cortexa53-xilinx-linux
LD=aarch64-xilinx-linux-ld --sysroot=/home/user/sdk/sysroots/cortexa72-cortexa53-xilinx-linux
READELF=aarch64-xilinx-linux-readelf
AR=aarch64-xilinx-linux-ar
AS=aarch64-xilinx-linux-as
NM=aarch64-xilinx-linux-nm
OECORE_TARGET_ARCH=aarch64
OBJCOPY=aarch64-xilinx-linux-objcopy
STRIP=aarch64-xilinx-linux-strip
OBJDUMP=aarch64-xilinx-linux-objdump
PATH=/home/user/sdk/sysroots/x86_64-petalinux-linux/usr/bin:/home/user/sdk/sysroots/x86_64-petalinux-linux/usr/sbin:/home/user/sdk/sysroots/x86_64-petalinux-linux/bin:/home/user/sdk/sysroots/x86_64-petalinux-linux/sbin:/home/user/sdk/sysroots/x86_64-petalinux-linux/usr/bin/../x86_64-petalinux-linux/bin:/home/user/sdk/sysroots/x86_64-petalinux-linux/usr/bin/aarch64-xilinx-linux:/home/user/sdk/sysroots/x86_64-petalinux-linux/usr/bin/aarch64-xilinx-linux-musl:...
CC=aarch64-xilinx-linux-gcc -mcpu=cortex-a72.cortex-a53+crc -mbranch-protection=standard -fstack-protector-strong -O2 -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security -Werror=format-security --sysroot=/home/user/sdk/sysroots/cortexa72-cortexa53-xilinx-linux
CROSS_COMPILE=aarch64-xilinx-linux-
CONFIGURE_FLAGS=--target=aarch64-xilinx-linux --host=aarch64-xilinx-linux --build=x86_64-linux --with-libtool-sysroot=/home/user/sdk/sysroots/cortexa72-cortexa53-xilinx-linux
RANLIB=aarch64-xilinx-linux-ranlib
This works with general cargo builds:
$ cat .cargo/config.toml
[target.aarch64-unknown-linux-gnu]
linker = "aarch64-xilinx-linux-gcc"
$ cargo build --target aarch64-unknown-linux-gnu
...
Running `/home/user/.rustup/toolchains/1.89.0-x86_64-unknown-linux-gnu/bin/rustc ... --target aarch64-unknown-linux-gnu -C linker=aarch64-xilinx-linux-gcc ... link-arg=--sysroot=/home/user/sdk/sysroots/cortexa72-cortexa53-xilinx-linux`
It would be really useful if I could get this working with cargo-dinghy too.
You're right, we're just looking into
TBH, it is a bit weird to use the build tools from the sysroot subdir on the host system, typical toolchain have the sysroot and "host" build tools side by side.
One idea would be to "normalize" your toolchain, by making a "bin" symlink in the right place pointing inside the sysroot. Not sure if this is going to work, but maybe it's worth a try.
A more serious idea would be to add an opt-in extra option in dinghy.toml toolchain descriptor that would allow overriding the "bin" subpath so dinghy would look for build tools in a different location (probably relative to the toolchain root). Feel free to give it a shot, see if that is working. That's a PR that we would certainly accept.