Error: "linker 'cc' not found" when cross compiling a rust project from windows to linux using cargo - linux

I have a basic rust/cargo project with a single main file and some basic dependencies. The cargo build command works fine when the target is not specified (I am using windows so it builds to windows), but when I try to cross compile the program to linux using cargo build --target=x86_64-unknown-linux-gnu or cargo build --target=x86_64-unknown-linux-musl, the process fails with the following error: linker 'cc' not found.
Does anyone have an idea how to get around this? Is there a specific linker I need to install?
Thanks.

I've just figured it out.
It turns out you need to tell cargo to use the LLVM linker instead. You do this by creating a new directory called .cargo in your base directory, and then a new file called config.toml in this directory. Here you can add the lines:
[target.x86_64-unknown-linux-musl]
rustflags = ["-C", "linker-flavor=ld.lld"]
Then building with the command cargo build --target=x86_64-unknown-linux-musl should work!

Related

Target dependent ParseConfig

I'm trying to only build a library without having all tests dependencies available,
my tests directory have it's own SConscript file that run env.ParseConfig('pkg-config --libs --cflags libfuzzertestdependonthis')
And if I'm building the library by specifying the lib target only, the command ParseConfig will fail because the lib is not available in my build environment
The only solutions i found are really bad:
enclose env.ParseConfig in try expect block
checking the command line build target content to exclude some part of the SConstruct file
I wonder if there a smart way to do this, it would be great if ParseConfig could be a handled as a source node for a specific target instead of being run immediately.
Edit:my question don't seems to be clear enough, so I will try with a better example.
When I'm building in release mode, I don't have(don't want) the libcunit required to build the tests, the issue I'm facing is that ParseConfig command is always executed regarless of the target, and in this example ParsConfig will execute pkg-config --libs libcunit, which will fail because this lib is not installed.
Ok. From your update.
If you're building in your release mode, don't call ParseConfig()..

How do I remove the dependency on libunwind when cross-compiling Rust programs with the panic_abort option?

I'm specifying the -Cpanic=abort and -Zbuild-std=panic_abort when compiling. Why does the linker still say it needs libunwind to compile a program?
I'm experimenting with various ways to cross-compile Rust programs as small as possible (using the min-sized-rust repo as a reference). Right now I'm trying to compile the powerpc64-unknown-linux-musl target and I'm stuck on trying to remove a dependency on libunwind.
Here's my setup:
# 1. Install the Rust std source code
rustup component add rust-src --toolchain nightly
# 2. Setup a simple rust repo
cargo init testing
cd testing
# 3. Download a musl toolchain
wget https://musl.cc/powerpc64-linux-musl-cross.tgz
tar xzf powerpc64-linux-musl-cross.tgz
# 4. Try to compile the project (options on the command line instead of in files for
# maximum obviousness).
# RUSTFLAGS:
# -Cpanic=abort - abort immediately on panic
# -Clink-self-contained=no - don't use rustc's builtin libraries and objects (this
# is needed because powerpc64-unknown-linux-musl is a tier 3 target)
# -Clink-arg=--sysroot and -Clink-arg=/path/to/sysroot - pass the option to the linker
# to specify the sysroot of cross-compilation toolchain
# Cargo options:
# --config target.<triple>.linker - specify the linker to use
# -Zbuild-std=std,panic_abort - build the standard library from source. Specify
# panic_abort to make the abort on panic work
RUSTFLAGS="-Cpanic=abort -Clink-self-contained=no -Clink-arg=--sysroot -Clink-arg=powerpc64-linux-musl-cross/powerpc64-linux-musl/" \
cargo +nightly build \
--config "target.powerpc64-unknown-linux-musl.linker=\"powerpc64-linux-musl-cross/bin/powerpc64-linux-musl-gcc\"" \
--target powerpc64-unknown-linux-musl -Zbuild-std=panic_abort,std --release
This fails with the following error:
error: linking with `/home/user/Projects/testing/powerpc64-linux-musl-cross/bin/powerpc64-linux-musl-gcc` failed: exit status: 1
<output snipped>
= note: /home/user/Projects/testing/powerpc64-linux-musl-cross/bin/../lib/gcc/powerpc64-linux-musl/11.2.1/../../../../powerpc64-linux-musl/bin/ld: cannot find -lunwind
From min-size-rust repository:
"Even if panic = "abort" is specified in Cargo.toml, rustc will still include panic strings and formatting code in final binary by default. An unstable panic_immediate_abort feature has been merged into the nightly rustc compiler to address this.
To use this, repeat the instructions above to use build-std, but also pass the following -Z build-std-features=panic_immediate_abort option."
Still, you will get "cannot find -lunwind", because the linker still uses libunwind, even though it's truly unneeded,why! I do not know, maybe it's a bug.(Maybe someone with fair knowledge about linkers can easily solve that.I tried a naive solution which is "cargo .... --verbose", copy , remove "libunwind" then relinking which failed)
I verified that is indeed the missing piece by build from source(--target=x86_64-unknown-linux-musl) AND using an old simple trick which is "touch libunwind.a" in the "self-contained" directory inside a target lib folder.(because the linker would still use it even though it's now truly unneeded, then I gave him a dummy libunwind.a)
In your case, I really tried to build it to your target until I got a headache, but couldn't and stopped, but here is possible solutions:
Giving that you're using "-Z build-std-features=panic_immediate_abort"
-If you can custom the linking process, then solve it (until what seems to be a bug is solved)
-Create a dummy(empty) libunwind.a where it should be in your toolchain

How do I fix "ld: error: unable to find library -lgcc" when cross-compiling rust to android?

I'm trying to get rust working on android. However, when I try to cross-compile to android I get the following linking error:
$ cargo build --target=arm-linux-androideabi
Compiling <project> v0.1.0 (<project>)
error: linking with `/opt/android-sdk/ndk/23.0.7599858/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi31-clang` failed: exit status: 1
(very long toolchain command from cargo)
ld: error: unable to find library -lgcc
clang-12: error: linker command failed with exit code 1 (use -v to see invocation)
I have installed the ndk and changed the linker in .cargo/config to the android clang linker. I also tried the standalone toolchains with the same result. The guide I used was the following: https://mozilla.github.io/firefox-browser-architecture/experiments/2017-09-21-rust-on-android.html
Cross-compilation does work when using crate-type = ["rlib"] instead of crate-type = ["cdylib"], but I need an .so file not an .rlib file.
In case it's relevant, i'm using Manjaro Linux.
UPDATE:
I found the following pull request: https://github.com/rust-lang/rust/pull/85806 After switching to ndk22 it worked. I havn't tried if the pull request fixes the issue (probably does).
Without switching to an older NDK version, I found using the workaround provided by ssrlive to work for me. Here's their comment:
Fixing build error for NDK 23 and above
find out all the 4 folders containing file libunwind.a, in my PC,
it's
C:\Users\Administrator\AppData\Local\Android\Sdk\ndk\23.1.7779620\toolchains\llvm\prebuilt\windows-x86_64\lib64\clang\12.0.8\lib\linux\x86_64\
and more. create 4 text files named libgcc.a in the same folders
with this contents
INPUT(-lunwind)
reference
link
In macOS, the paths are
~/Library/Android/sdk/ndk/24.0.8215888/toolchains/llvm/prebuilt/darwin-x86_64/lib64/clang/14.0.1/lib/linux/i386/libunwind.a
~/Library/Android/sdk/ndk/24.0.8215888/toolchains/llvm/prebuilt/darwin-x86_64/lib64/clang/14.0.1/lib/linux/arm/libunwind.a
~/Library/Android/sdk/ndk/24.0.8215888/toolchains/llvm/prebuilt/darwin-x86_64/lib64/clang/14.0.1/lib/linux/aarch64/libunwind.a
~/Library/Android/sdk/ndk/24.0.8215888/toolchains/llvm/prebuilt/darwin-x86_64/lib64/clang/14.0.1/lib/linux/x86_64/libunwind.a
In Linux, the paths are
~/Android/Sdk/ndk/24.0.8215888/toolchains/llvm/prebuilt/linux-x86_64/lib64/clang/14.0.1/lib/linux/i386/libunwind.a
~/Android/Sdk/ndk/24.0.8215888/toolchains/llvm/prebuilt/linux-x86_64/lib64/clang/14.0.1/lib/linux/aarch64/libunwind.a
~/Android/Sdk/ndk/24.0.8215888/toolchains/llvm/prebuilt/linux-x86_64/lib64/clang/14.0.1/lib/linux/x86_64/libunwind.a
~/Android/Sdk/ndk/24.0.8215888/toolchains/llvm/prebuilt/linux-x86_64/lib64/clang/14.0.1/lib/linux/arm/libunwind.a
In Windows, the paths are
~/AppData/Local/Android/Sdk/ndk/24.0.8215888/toolchains/llvm/prebuilt/windows-x86_64/lib64/clang/14.0.1/lib/linux/aarch64/libunwind.a
~/AppData/Local/Android/Sdk/ndk/24.0.8215888/toolchains/llvm/prebuilt/windows-x86_64/lib64/clang/14.0.1/lib/linux/arm/libunwind.a
~/AppData/Local/Android/Sdk/ndk/24.0.8215888/toolchains/llvm/prebuilt/windows-x86_64/lib64/clang/14.0.1/lib/linux/i386/libunwind.a
~/AppData/Local/Android/Sdk/ndk/24.0.8215888/toolchains/llvm/prebuilt/windows-x86_64/lib64/clang/14.0.1/lib/linux/x86_64/libunwind.a
create file command in Linux/macOS
cat << EOF > libgcc.a
INPUT(-lunwind)
EOF
This is of course extremely brittle and not the "right" solution, but the workaround works fine as of 2022-10-12 with ndk version 25.1.8937393.

How can I specify a custom Cargo output directory?

I put this in my Cargo.toml
[build]
target-dir = "../my-target"
However, Cargo doesn't recognize this key.
cargo run --release --bin my_project
warning: unused manifest key: build
error: failed to open: /.../project-root/target/releases/.cargo-lock
Caused by:
Permission denied (os error 13)
The custom target dir with the environment variable works:
CARGO_TARGET_DIR=../my-target cargo run --bin my_project
but how can I specify '../my-target' in Cargo.toml?
[build] is a Cargo-level configuration rather than for the project:
This document will explain how Cargo’s configuration system works, as well as available keys or configuration. For configuration of a project through its manifest, see the manifest format.
Put your [build] inside $PROJECT_DIR/.cargo/config or even $HOME/.cargo/config. See the above link for all the options.
Use the CARGO_TARGET_DIR environment variable:
CARGO_TARGET_DIR=../my-target cargo run --bin my_project
(This is stated in the question, but I wanted to highlight it for anyone that skips over that)

Haxe: rebuild hxcpp failed with Error: Could not find build target "std"

Trying to rebuild hxcpp failed with the cryptic error message:
Error: Could not find build target "std"
Some users report this hint (I swear I didn't see it when I hit the issue, unless I'm just blind):
Have you tried rebuilding the hxcpp.n and build.n scripts?
This is done by running haxe in the tools/hxcpp and tools/build directories.
Hence:
cd hxcpp/tools/hxcpp
haxe compile.hxml
cd ../build
haxe compile.hxml
Fixes it.
Also note that nightly hxcpp builds are available from nmehost.com and openfl.org if you just need a newer version than what's available via haxelib.

Resources