Building a simple (hello-world-esque) example of using ld's option -rpath with $ORIGIN
(I'd rather have
[foo.sh]
than[lib/foo.sh]
but I'll fix that later).
There's most of your problem: the /
in the name stops the dynamic linker from doing the rpath magic.
(Your rpath is wrong too. Think about it: from the shell, if you were currently in the directory where your executable is, how would you get to the directory where your library is? Here, you'd need to cd ../lib
. So your rpath should be $ORIGIN/../lib
.)
If you built your object as libfoo.so
and linked with -Llib -lfoo
, the linker would work out what you were intending, and do the right thing. But if you're going to use unusual naming conventions, you'll have to help it out:
Change the link line for the library to explicitly set the SONAME for your library to just
foo.sh
:g++ -shared -Wl,-soname,foo.sh -o lib/foo.sh obj/foo.o
Fix the rpath:
g++ -o run/main.run obj/main.o -Wl,-rpath,'$ORIGIN/../lib' -Llib -l:foo.sh
It's useful to run ldd main/main.run
to see what's going on. In your original failing case, you'll see something like:
lib/foo.sh (0xNNNNNNNN)
(the lack of any => /some/resolved/path
showing that it's not done any path resolution). In the fixed case, you'll see something like:
foo.sh => /your/path/to/run/../lib/foo.sh (0xNNNNNNNN)
CMAKE RPATH with packaging
I've been fussing with cmake on this as well. Cmake uses CMAKE_SKIP_BUILD_RPATH for linking at build time and CMAKE_INSTALL_RPATH to set the rpath used when the install target is built. cmake has some good info on using its rpath mechanism:
http://www.cmake.org/Wiki/CMake_RPATH_handling
An alternative method is to use ldconfig. I notice that when you build svn(1.6.17), it's make install target invokes ldconfig to set rpath.
take a look at $ORIGIN as you'll need that in your rpath to keep it relative to the binary rather than relative to $PWD.
Building a simple (hello-world-esque) example of using ld's option -rpath with $ORIGIN
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
Can't Run Sonar Server Caused by Elasticsearch Cannot Running as Root
Check If a Program in a Specific Path Is Running
Cuda Performance Penalty When Running in Windows
How to Find Out What Linux Capabilities a Process Requires to Work
X86 Assembly: Before Making a System Call on Linux Should You Save All Registers
Dynamically Determining Where a Rogue Avx-512 Instruction Is Executing
How to Write Shell Command Within Pharo Smalltalk
How to Check Fips 140-2 Support in Openssl
Why Linux Kernel Use Trap Gate to Handle Divide_Error Exception
On X64 Linux, Differencebetween Syscall, Int 0X80 and Ret to Exit a Program
Open a File Directly from a Gitlab Private Repository
Building Arm Gnu Cross Compiler
.Bashrc Not Read When Shell Script Is Invoked from Desktop Shortcut
How to Get Docker Container Id from Within the Container with Cgroup V2
Use Sed with Ignore Case While Adding Text Before Some Pattern