Background
Today, I resumed a rust
project of mine after a long time. In order to check my last working code, I ran cargo run
. But it refused to run with error message:
...."-Wl,-Bdynamic" "-l" "dl" "-l" "rt" "-l" "pthread" "-l" "pthread" "-l" "gcc_s" "-l" "c" "-l" "m" "-l" "rt" "-l" "pthread" "-l" "util" "-l" "util"
= note: /usr/bin/ld: cannot find Scrt1.o: No such file or directory
collect2: error: ld returned 1 exit status
Linker Issues!
ld
is used to link libraries. So, the error was not in the code but in the linking phase. I googled the error and the solution was to have build-essential
package installed. But the package was already installed on my machine (it is one of the first packages I install on any development machine).
Some more googling revealed that cargo
uses the system cc
linker to link to the C runtime. Running which cc
gave me $HOME/anaconda3/bin/cc
. This cc
is part of my Anaconda root environment. (Anaconda is a package manager for scientific computing packages. It is a convenient way for installing multiple versions of packages in different environments).
On Linux, the linker knows where to find the required libraries using the shared library cache. I ran ldconfig -v
to refresh it and then try again. Same error!
It is possible to explicitly list directories to include using LD_LIBRARY_PATH
environment variable. I tried setting the LD_LIBRARY_PATH
to point to the required directory and then run cargo as LD_LIBRARY_PATH=DIR cargo build -v
. But it gave the same error.
I thought that cargo
must be setting the linker value somewhere, so instead let me try directly compiling with rustc
. Even that gave the same error. With this, I eliminated the possibility of some environment variable only affecting cargo
.
More googling!
Further searching for the error with "rust" added showed me results of people having trouble cross-compiling. From this, I learned that cargo has different targets i.e different instruction sets (e,g x86-64, arm, x86, mips), different OSs (e.g linux, windows, freebsd) and different C runtimes (e.g glibc, musl, msvc). The Rust documentation on cargo mentioned that this is called a target triple. The Cargo book mentioned that you can direct cargo to explicitly use a particular linker using RUSTFLAGS environment variable.
Since I am only building for my machine, I had to find out the exact value of the target. Rust gives an exhaustive list of all supported targets by running rustc --print target-list
. My target was x86_64-unknown-linux-gnu
.
It is possible to pass a linker to cargo
explicitly as RUSTFLAGS="-C linker=x86_64-unknown-linux-gnu" cargo build -v
. It worked!
All-time fix!
I do not want to do this every time I run cargo
. The Cargo book says that cargo uses a global config file in $HOME/.cargo/config
.
I added the following to the file:
# Specify which linker to use for this target
[target.x86_64-unknown-linux-gnu]
linker = "x86_64-linux-gnu-gcc"
Now, cargo build
works without issues.
Top comments (3)
How did you determine which target you needed to feed to cargo?
Why was it broken, in the first place?
Cargo itself was working fine. The issue was a combination of a non-standard
gcc
and cargo not being able to find the correct linker path by default.