How can I type cargo run without needing to set the LD_LIBRARY_PATH shell variable?
Add the following line to build.rs:
println!("cargo:rustc-env=LD_LIBRARY_PATH=/home/jan/Uni/Bachelorarbeit/Programme/Rust_Cpp_crossover_erneut/");
This only works with cargo run
and not with cargo build
and then executing the output. The environment variable does not get saved into the binary.
How should I resolve a ld: library not found for -liconv error when running cargo build?
First step is to install libiconv
via Homebrew:
brew install libiconv
Notice that the output is saying something weird:
==> Caveats
libiconv is keg-only, which means it was not symlinked into /opt/homebrew,
because macOS already provides this software and installing another version in
parallel can cause all kinds of trouble.
If you need to have libiconv first in your PATH, run:
echo 'export PATH="/opt/homebrew/opt/libiconv/bin:$PATH"' >> ~/.zshrc
For compilers to find libiconv you may need to set:
export LDFLAGS="-L/opt/homebrew/opt/libiconv/lib"
export CPPFLAGS="-I/opt/homebrew/opt/libiconv/include"
I haven't been able to piece together a complete explanation, but it is something to do with libiconv
being provided by MacOS in a version that has the wrong symbols. On my system libiconv
can't be found (is it a M1 thing?); nevertheless, brew refuses to step on the OSes' toes, which seems a reasonable decision.
These variables do not apply to cargo
however.
The best way to solve the problem (that I found) is to modify your LIBRARY_PATH
variable to provide path to iconv. You might have already had to modify your LIBRARY_PATH
(see e.g. https://apple.stackexchange.com/questions/40704/homebrew-installed-libraries-how-do-i-use-them).
What I did was to add the following line to my ~/.zshrc
:
export LIBRARY_PATH=$LIBRARY_PATH:$(brew --prefix)/lib:$(brew --prefix)/opt/libiconv/lib
Afterwards libiconv
is detected correctly.
What is LD_LIBRARY_PATH and how to use it?
Typically you must set java.library.path
on the JVM's command line:
java -Djava.library.path=/path/to/my/dll -cp /my/classpath/goes/here MainClass
How can I specify the type of the loop variable in a for loop?
It's not possible to have a type annotation in a for-loop, because the for-loop expects a pattern, and a pattern cannot contain type annotations. See the Rust reference for more details.
Instead you can do one of three things:
Make the type of the iterator unambiguous
In this case, it would be:
for i in 0..101u8 {
println!("{}", i);
}
(playground)
Use an irrefutable pattern with the @-pattern
for i @ 0..=255u8 in 0..101 {
println!("{}", i);
}
(playground)
Add a type annotation inside the loop:
for i in 0..101 {
let i: u8 = i;
println!("{}", i);
}
(playground)
Linking Rust application with a dynamic library not in the runtime linker search path
Here's a Minimal, Reproducible Example that exhibits the same problem that you experienced. I created a C library exporting a simple addition function. I also created a Cargo project to use this function.
dynlink/
├── executable
│ ├── build.rs
│ ├── Cargo.lock
│ ├── Cargo.toml
│ └── src
│ └── main.rs
└── library
├── awesome_math.c
└── libawesome_math.so
awesome_math.c
#include <stdint.h>
uint8_t from_the_library(uint8_t a, uint8_t b) {
return a + b;
}
The library was compiled as gcc -g -shared awesome_math.c -o libawesome_math.so
.
src/main.rs
extern {
fn from_the_library(a: u8, b: u8) -> u8;
}
fn main() {
unsafe {
println!("Adding: {}", from_the_library(1, 2));
}
}
build.rs
fn main() {
println!("cargo:rustc-link-lib=dylib=awesome_math");
println!("cargo:rustc-link-search=native=/home/shep/rust/dynlink/library");
}
Cargo.toml
[package]
name = "executable"
version = "0.1.0"
edition = "2021"
[profile.dev]
rpath = true
Investigating further, I asked the Rust compiler to print out the linker args it was going to use:
cargo rustc -- --print link-args
This printed out a bunch of stuff, but an important line was:
"-Wl,-rpath,$ORIGIN/../../../../../../.rustup/toolchains/nightly-aarch64-unknown-linux-gnu/lib/rustlib/aarch64-unknown-linux-gnu/lib"
This is a directive to the linker to add specific values to the rpath of the finished binary. Missing is any reference to the dynamic library that we are linking to. In retrospect, this probably makes sense, as how would the compiler know that we want to include it in the rpath?
A workaround is to add another directive to the linker. There are interesting options (like $ORIGIN
), but for simplicity, we will just use an absolute path:
cargo rustc -- -C link-args="-Wl,-rpath,/home/shep/rust/dynlink/library/"
And the resulting binary prints the right thing for ldd
and runs without setting LD_LIBRARY_PATH
:
$ ldd ./target/debug/executable | grep awesome
libawesome_math.so => /home/shep/rust/dynlink/library/libawesome_math.so (0x0000ffffb1e56000)
$ ./target/debug/executable
Adding: 3
Turning to making it relative, we can use $ORIGIN
:
cargo rustc -- -C link-args='-Wl,-rpath,$ORIGIN/../../../library/'
Be careful to escape $ORIGIN
properly for your shell, and remember that the path is relative to the executable, not the current working directory.
See also:
- How can I specify linker flags/arguments in a build script?
Related Topics
Sendmail/Procmail - Get Mail Sender and Mail Subject, Utf8 Encoding Issues
Javafx: Tested/Confirmed Hardware (Gpu) Acceleration on Linux
.Net Core 3.1 Deploy on Centos 7
How to Get Awk to Print Without White Space
Error: You Must Install at Least One Postgresql-Client-<Version> Package
Environment Variables in Symbolic Links
Mqtt Socket Error on Client <Unknown>
Difference Between $() and () in Bash
How to Use Vi to Edit a Command in Terminal on Linux
How to Select a Static Port Number for a Custom App
How The File Size Is Limited on a Specific File System
Svn Setup of Existing Directory
Detect If Interface Is in Promiscuous Mode with C