When a program uses a shared library, the dynamic linker (ld.so) must find that library at runtime. By default it looks in standard directories like /lib, /usr/lib, and directories listed in /etc/ld.so.conf.
But what if your library is in a non-standard location like /home/user/myproject/lib or /opt/vendor/lib64? You have three options:
| Method | How | Scope | Drawback |
|---|---|---|---|
| Standard dirs | Install to /usr/lib | System-wide | Requires root, pollutes system |
| LD_LIBRARY_PATH | Set env variable | Per-session | Must set before every run; security risk |
| rpath | Embed in executable at link time | Per-binary | Path is baked in; less flexible |
rpath is the cleanest for distributing self-contained applications because the search path travels with the binary.
When a program is executed, the dynamic linker searches for shared libraries in this exact order:
The -rpath option is passed to the linker via gcc’s -Wl, mechanism:
# Basic: embed /home/mtk/pdir into the rpath of prog
gcc -g -Wall \
-Wl,-rpath,/home/mtk/pdir \
-o prog prog.c libdemo.so
# The dynamic linker will search /home/mtk/pdir at runtime
You can specify multiple rpath directories in two ways:
# Method 1: Multiple -rpath options (each adds to the list)
gcc -o prog prog.c \
-Wl,-rpath,/opt/myapp/lib \
-Wl,-rpath,/usr/local/vendor/lib \
-ldemo
# Method 2: Colon-separated list in one -rpath option
gcc -o prog prog.c \
-Wl,-rpath,/opt/myapp/lib:/usr/local/vendor/lib \
-ldemo
# Verify what got embedded:
objdump -p prog | grep RPATH
# Output: RPATH /opt/myapp/lib:/usr/local/vendor/lib
Instead of specifying -rpath on the gcc command line, you can set the LD_RUN_PATH environment variable before building:
# Set LD_RUN_PATH before the build command
export LD_RUN_PATH=/home/mtk/pdir:/opt/myapp/lib
# Now build without -rpath; LD_RUN_PATH is used instead
gcc -g -Wall -o prog prog.c -L/home/mtk/pdir -ldemo
# Verify it was embedded
objdump -p prog | grep RPATH
# Output: RPATH /home/mtk/pdir:/opt/myapp/lib
-rpath is specified on the command line, LD_RUN_PATH is completely ignored. LD_RUN_PATH is only used when -rpath is absent.#!/bin/bash
# rpath_demo.sh โ demonstrates -rpath for non-standard library location
set -e
WORKDIR=/tmp/rpath_demo
mkdir -p $WORKDIR/mylib $WORKDIR/myapp
cd $WORKDIR
# ---- Create the shared library source ----
cat > mylib/myutils.c << 'EOF'
#include <stdio.h>
void say_hello(const char *who) {
printf("Hello from myutils library, %s!\n", who);
}
int add_numbers(int a, int b) {
return a + b;
}
EOF
# ---- Create the application source ----
cat > myapp/main.c << 'EOF'
#include <stdio.h>
void say_hello(const char *who);
int add_numbers(int a, int b);
int main(void) {
say_hello("EmbeddedPathashala");
int result = add_numbers(10, 32);
printf("10 + 32 = %d\n", result);
return 0;
}
EOF
echo "=== Building shared library in non-standard dir: $WORKDIR/mylib ==="
cd $WORKDIR/mylib
gcc -g -c -fPIC -Wall myutils.c
gcc -g -shared -Wl,-soname,libmyutils.so.1 \
-o libmyutils.so.1.0.0 myutils.o
ln -sf libmyutils.so.1.0.0 libmyutils.so.1
ln -sf libmyutils.so.1 libmyutils.so
echo "=== Building application with -rpath embedded ==="
cd $WORKDIR/myapp
gcc -g -Wall \
-Wl,-rpath,$WORKDIR/mylib \
-L$WORKDIR/mylib \
-o myapp main.c \
-lmyutils
echo ""
echo "=== Inspecting rpath embedded in myapp ==="
objdump -p myapp | grep RPATH
# Expected: RPATH /tmp/rpath_demo/mylib
echo ""
echo "=== ldd shows the library is found via rpath ==="
ldd myapp
echo ""
echo "=== Running myapp (no LD_LIBRARY_PATH needed!) ==="
./myapp
export LD_LIBRARY_PATH=... before running myapp. The rpath is baked into the binary itself.#!/bin/bash
# compare_methods.sh โ show difference between LD_LIBRARY_PATH and rpath
WORKDIR=/tmp/compare_demo
mkdir -p $WORKDIR/lib $WORKDIR/bin
cd $WORKDIR
# Assume libdemo.so is already built in $WORKDIR/lib
# Build with rpath:
echo "=== Build WITH rpath ==="
gcc -o bin/prog_rpath main.c \
-Wl,-rpath,$WORKDIR/lib \
-L$WORKDIR/lib \
-ldemo
echo "prog_rpath rpath:"
objdump -p bin/prog_rpath | grep RPATH
# Build WITHOUT rpath:
echo ""
echo "=== Build WITHOUT rpath ==="
gcc -o bin/prog_norpath main.c \
-L$WORKDIR/lib \
-ldemo
echo "prog_norpath rpath (should be empty):"
objdump -p bin/prog_norpath | grep RPATH || echo " (no RPATH embedded)"
echo ""
echo "=== Running prog_rpath (works without LD_LIBRARY_PATH) ==="
bin/prog_rpath && echo "Success!" || echo "Failed"
echo ""
echo "=== Running prog_norpath WITHOUT LD_LIBRARY_PATH (should fail) ==="
bin/prog_norpath 2>&1 || echo "Expected failure: library not found"
echo ""
echo "=== Running prog_norpath WITH LD_LIBRARY_PATH (works) ==="
LD_LIBRARY_PATH=$WORKDIR/lib bin/prog_norpath && echo "Success!"
echo ""
echo "=== NOTE: LD_LIBRARY_PATH overrides rpath with DT_RUNPATH, ==="
echo "=== but NOT with DT_RPATH (old ELF tag). ==="
#!/bin/bash
# ld_run_path_demo.sh โ using LD_RUN_PATH as alternative to -rpath
WORKDIR=/tmp/ldrunpath_demo
mkdir -p $WORKDIR/lib $WORKDIR/app
cd $WORKDIR
# Suppose libfoo is in /opt/locallibs/lib
LIBDIR=/opt/locallibs/lib
mkdir -p $LIBDIR
# Build the library
cat > /tmp/foo.c << 'EOF'
#include <stdio.h>
void foo_init(void) { printf("foo library initialized\n"); }
EOF
gcc -shared -fPIC -o $LIBDIR/libfoo.so /tmp/foo.c
# Build using LD_RUN_PATH (no -rpath on command line)
echo "=== Method 1: LD_RUN_PATH during build ==="
export LD_RUN_PATH=$LIBDIR
gcc -o app/prog_ldrunpath main.c -L$LIBDIR -lfoo
objdump -p app/prog_ldrunpath | grep RPATH
unset LD_RUN_PATH
# Build using -rpath directly (overrides LD_RUN_PATH)
echo ""
echo "=== Method 2: -rpath on command line ==="
export LD_RUN_PATH=/some/other/path # this will be IGNORED
gcc -o app/prog_rpath main.c \
-Wl,-rpath,$LIBDIR \
-L$LIBDIR -lfoo
objdump -p app/prog_rpath | grep RPATH
# Shows $LIBDIR, NOT /some/other/path โ -rpath wins
unset LD_RUN_PATH
-Wl,-rpath,/path/to/dir option. The -Wl, prefix passes the following comma-separated argument directly to the linker (ld). Example: gcc -o myprog main.c -Wl,-rpath,/opt/mylibs/lib -L/opt/mylibs/lib -lmylib. Multiple paths can be given with multiple -rpath options or as a colon-separated list.LD_RUN_PATH is an environment variable that serves as an alternative to the -rpath linker option. If -rpath is specified on the command line, LD_RUN_PATH is completely ignored. LD_RUN_PATH is only used when -rpath is not present. Both result in an rpath list being embedded in the executable, but -rpath takes priority.objdump -p executable | grep RPATH or objdump -p executable | grep RUNPATH. You can also use readelf -d executable | grep -E 'RPATH|RUNPATH'. These commands display the DT_RPATH or DT_RUNPATH entries from the ELF dynamic section of the file.-L/path is a compile-time (static link time) option that tells the linker where to find libraries when building the executable. It is NOT embedded in the final binary and has no effect at runtime. -Wl,-rpath,/path is embedded in the binary and is used by the dynamic linker at runtime to find shared libraries. Typically you need both: -L to build successfully, and -rpath so the binary can find its libraries when run.โ Major Version Upgrade Next: Chained Libraries with rpath โ
