zealotds 发表于 2013-2-4 22:09:11

Linux Shared Library (DLL) & -rpath,'$ORIGIN'

The Argument -rpath,'$ORIGIN'

Needs to be prefixed with "-Wl," for most Linux OS (or "-R<path>" for Solaris, -brtl for AIX and "-Wl,+b<path>" for HPUX). It is to pass linker options to your linker through gcc or g++. It is significant if you need to build a binary that depends on other dynamic library. "rpath" means runtime path (to load dependent dynamic library). And the very useful variable that we frequently used is "$ORIGIN" which means the path where your (link) target binary is loaded.

# assuming your target lib is libb.so and it depends on liba.so# and their deployment structure is like:<install_root>|libb.so|<sub_dir>|liba.so# then you should supply below argument to your gcc or g++:# the double '$' is necessary if it is written in makefile (as escaping char)# -Wl,-rpath,'$$ORIGIN/<sub_dir>'# or, without single quote, you can write it like:# -Wl,-rpath,\$$ORIGIN/<sub_dir># and -shared and -fPIC is usually need to build dynamic linkable librarygcc -o libb.so -shared -fPIC -L. -la -Wl,-rpath,\$$ORIGIN/<sub_dir> libb.c

Check RPATH with 'readelf':
# -d means dynamicreadelf -d <dll_name># output looks like:#Tag               Type               Name/Value# 0x0000000000000001 (NEEDED)             Shared library: # 0x0000000000000001 (NEEDED)             Shared library: # 0x0000000000000001 (NEEDED)             Shared library: # 0x0000000000000001 (NEEDED)             Shared library: # 0x0000000000000001 (NEEDED)             Shared library: # 0x000000000000000f (RPATH)            Library rpath: [$ORIGIN/libb]# 0x000000000000000c (INIT)               0x7d8# 0x000000000000000d (FINI)               0xa88# 0x000000006ffffef5 (GNU_HASH)         0x158# 0x0000000000000005 (STRTAB)             0x3c8# 0x0000000000000006 (SYMTAB)             0x1a0# 0x000000000000000a (STRSZ)            479 (bytes)# 0x000000000000000b (SYMENT)             24 (bytes)# 0x0000000000000003 (PLTGOT)             0x200e28# 0x0000000000000002 (PLTRELSZ)         216 (bytes)# 0x0000000000000014 (PLTREL)             RELA# 0x0000000000000017 (JMPREL)             0x700# 0x0000000000000007 (RELA)               0x628# 0x0000000000000008 (RELASZ)             216 (bytes)# 0x0000000000000009 (RELAENT)            24 (bytes)# 0x000000006ffffffe (VERNEED)            0x5d8# 0x000000006fffffff (VERNEEDNUM)         2# 0x000000006ffffff0 (VERSYM)             0x5a8# 0x000000006ffffff9 (RELACOUNT)          3# 0x0000000000000000 (NULL)               0x0

Sample
// liba.h#ifndef LIBA_GPGH7YWD_H#define LIBA_GPGH7YWD_Hnamespace dlltest {void foo();class A {public:    A();};} /* dlltest */#endif /* end of include guard: LIBA_GPGH7YWD_H */// liba.cpp#include <iostream>#include "liba.h"namespace dlltest {void foo() {    std::cout << "liba:foo" << std::endl;}A::A() {    foo();}}// libb.h#ifndef LIBB_5NC56UVQ_H#define LIBB_5NC56UVQ_H#include "liba.h"namespace dlltest {void goo();class B : public A {public:    B();};}#endif /* end of include guard: LIBB_5NC56UVQ_H */// libb.cpp#include <iostream>#include "libb.h"namespace dlltest {void goo() {    std::cout << "libb:goo" << std::endl;}B::B() {    goo();}}// libc1.h: // you never want to name it libc.so because it is // the name of standard C library#ifndef LIBC_1Y6MU09S_H#define LIBC_1Y6MU09S_H#include "libb.h"extern "C" void hoo();extern "C" void hoo2();namespace dlltest {class C : public B {public:    C();};}#endif /* end of include guard: LIBC_1Y6MU09S_H */// libc1.cpp#include <iostream>#include "libc1.h"void hoo() {    std::cout << "libc:hoo" << std::endl;}void hoo2() {    dlltest::C c;}namespace dlltest {C::C() {    hoo();}}
// main.cpp// implicit dll dependency#include "libc1.h"using namespace dlltest;int main(int argc, const char *argv[]){    C c;    return 0;}
// main2.cpp// load dll with dlopen#include <stdio.h>#include <stdlib.h>#include <dlfcn.h>typedef void(*FP)();int main(int argc, char **argv) {void *handle;char *error;handle = dlopen ("./libc1.so", RTLD_LAZY);if (!handle) {      fprintf (stderr, "%s\n", dlerror());      exit(1);}dlerror();    /* Clear any existing error */FP fp = (FP)dlsym(handle, "hoo2");if ((error = dlerror()) != NULL){      fprintf (stderr, "%s\n", error);      exit(1);}(*fp)();dlclose(handle);return 0;}
// makefile# Dynamic loading shared library#   dynamic libraries could be independent on each other when built#   but, in this case, executable binary depends on all of themdll: dir    g++ -fPIC -shared -o bin/liba.so liba.cpp    g++ -fPIC -shared -o bin/libb.so libb.cpp    g++ -fPIC -shared -o bin/libc1.so libc1.cpp    g++ -o bin/dlink main.cpp -Lbin -lc1 -lb -la -Wl,-rpath,\$$ORIGIN# libc1.so is loaded by dlopen in main2.cpp# libc1.so implicitly depends on libb.so, without RPATH libc1 #   doesn't know where to find it# libb.so implicitly depends on liba.so, without RPATH libb doesn't #   know where to find it# need to link libb.so and liba.so to demo, so demo will load libb#   and liba when it needs themdlopen: dir2    g++ -fPIC -shared -o bin/liba.so liba.cpp    g++ -fPIC -shared -o bin/libb/libb.so libb.cpp    g++ -fPIC -shared -o bin/libc1.so libc1.cpp    g++ -o bin/dldemo main2.cpp -Lbin/libb -Lbin -la -lb -ldl -Wl,-rpath,\$$ORIGIN -Wl,-rpath,\$$ORIGIN/libb# alternative to dlopen case:# add libb dependency explicitly when build libc1:#   -Lbin/libb and -lb is essential because you want libc1 know    libb#   has the symbols it needs and -rpath tells libc1 where to find libb# but liba's search path is not built into libb, it's needed to #   build the dependency into dldemo# otherwise,update the rpath of libb(for liba) should also work, check dlopen3dlopen2: dir2    g++ -fPIC -shared -o bin/liba.so liba.cpp    g++ -fPIC -shared -o bin/libb/libb.so libb.cpp    g++ -fPIC -shared -o bin/libc1.so libc1.cpp -Lbin/libb -lb -Wl,-rpath,\$$ORIGIN/libb    g++ -o bin/dldemo main2.cpp -Lbin -la -ldl -Wl,-rpath,\$$ORIGIN# second alternative to dlopen case:# dldemo implicitly depends on none of 3 libs, but you still need to tell it where to#   find libc1 with -rpath. otherwise, if you specify correct path to libc1.so when #   dlopen (and start the program in correct working diretory if you use indirect #   file path in dlopen), then -rpath is not needed # libc1 implicitly depends on libb and libc1 know where to find libb with -rpath setup# libb implicitly depends on liba and libb know where to find liba with -rpath setupdlopen3: dir2    g++ -fPIC -shared -o bin/liba.so liba.cpp    g++ -fPIC -shared -o bin/libb/libb.so libb.cpp -Lbin -la -Wl,-rpath,\$$ORIGIN/..    g++ -fPIC -shared -o bin/libc1.so libc1.cpp -Lbin/libb -lb -Wl,-rpath,\$$ORIGIN/libb    #g++ -o bin/dldemo main2.cpp -ldl -Wl,-rpath,\$$ORIGIN    g++ -o bin/dldemo main2.cpp -ldl# demostrate how to use -rpath to organize libraries into separate foldersstrc1: dir2    g++ -fPIC -shared -o bin/liba.so liba.cpp    g++ -fPIC -shared -o bin/libb/libb.so libb.cpp    g++ -fPIC -shared -o bin/libc1.so libc1.cpp    g++ -o bin/strc1 main.cpp -Lbin -lc1 -la -Lbin/libb -lb \    -Wl,-rpath,\$$ORIGIN -Wl,-rpath,\$$ORIGIN/libb# mix static lib with dynamic libmix1: dir    g++ -fPIC -shared -o bin/liba.so liba.cpp    g++ -fPIC -c libb.cpp    g++ -fPIC -shared -o bin/libc1.so libc1.cpp libb.o    g++ -o bin/mix1 main.cpp -Lbin -lc1 -la -Wl,-rpath,\$$ORIGIN    rm *.o# static link:# if you build 'dll' before 'mix2' without clean, you can find the below -lc1# will link dynamic lib libc1.so instead of static lib libc1.a# the conclusion is shared lib link is default behaviormix2: dir clean    g++ -fPIC -shared -o bin/liba.so liba.cpp    g++ -fPIC -shared -o bin/libb.so libb.cpp    g++ -c libc1.cpp    ar -cvq bin/libc1.a libc1.o    g++ -o bin/mix2 main.cpp -Lbin -lc1 -lb -la -Wl,-rpath,\$$ORIGIN    rm *.odir:    if [ ! -d bin ]; then mkdir bin; fidir2:    if [ ! -d bin/libb ]; then mkdir -p bin/libb; ficlean:    rm -rf bin/*

For more information:

[*]check 'man ld'
[*]RPATH on Wiki
[*]Shared Library Search Path
[*]use ldd command to check dependency of a binary
页: [1]
查看完整版本: Linux Shared Library (DLL) & -rpath,'$ORIGIN'