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
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
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
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
It is possible to pass a linker to
cargo explicitly as
RUSTFLAGS="-C linker=x86_64-unknown-linux-gnu" cargo build -v. It worked!
I do not want to do this every time I run
cargo. The Cargo book says that cargo uses a global config file in
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"
cargo build works without issues.