`
zealotds
  • 浏览: 122296 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

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 library
gcc -o libb.so -shared -fPIC -L. -la -Wl,-rpath,\$$ORIGIN/<sub_dir> libb.c




Check RPATH with 'readelf':
# -d means dynamic
readelf -d <dll_name>
# output looks like:
#  Tag               Type                 Name/Value
# 0x0000000000000001 (NEEDED)             Shared library: [libb.so]
# 0x0000000000000001 (NEEDED)             Shared library: [libstdc++.so.6]
# 0x0000000000000001 (NEEDED)             Shared library: [libm.so.6]
# 0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1]
# 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
# 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_H
namespace 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 them
dll: 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 them
dlopen: 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 dlopen3
dlopen2: 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 setup
dlopen3: 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 folders
strc1: 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 lib
mix1: 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 behavior
mix2: 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 *.o

dir:
    if [ ! -d bin ]; then mkdir bin; fi

dir2:
    if [ ! -d bin/libb ]; then mkdir -p bin/libb; fi

clean:
    rm -rf bin/*


For more information:
分享到:
评论

相关推荐

    05-rpath解决so动态库依赖1

    例如,`patchelf --set-rpath /usr/lib/OpenNI2/Drivers ./_pcl.cpython-36m-x86_64-linux-gnu.so`将`_pcl.cpython-36m-x86_64-linux-gnu.so`的`RPATH`设置为`/usr/lib/OpenNI2/Drivers`。 验证修复是否成功,可以...

    patchelf:一个用于修改ELF可执行文件的动态链接器和RPATH的小实用程序

    $ patchelf --set-interpreter /lib/my-ld-linux.so.2 my-program 更改可执行文件和库的RPATH : $ patchelf --set-rpath /opt/my-libs/lib:/other-libs my-program 缩小可执行文件和库的RPATH : $ patchelf --...

    gmssl.tar.gz

    ubuntu20编译Gmssl时,“version OPENSSL_1_1_0d not defined”问题的...修改Gmssl的Makefile文件,在CFLAGS赋值时添加-Wl,-rpath=$(LIBRPATH),LIB_LDFLAGS赋值LIB_LDFLAGS=-Wl,-rpath=$(LIBRPATH) -znodelete -m64。

    linux下构建多目录下Makefile产生so动态库样例

    在Linux环境下,构建多目录下的Makefile以生成.so动态库是一项常见的任务,特别是在大型软件项目中。这样的项目通常包含多个源文件,分布在不同的目录结构中,每个目录可能有自己的子Makefile,最终通过主Makefile来...

    wl命令文件

    wifi模块测试所用的wl命令,可将文件拷贝机器中,方便调试文件

    rPath简化定制Linux.pdf

    《rPath简化定制Linux》是一份关于如何利用rPath技术高效定制Linux操作系统的专业指导文档。rPath是一家致力于简化Linux定制流程的公司,其产品和服务主要面向IT组织和独立软件供应商(ISV)。rPath的核心理念是通过...

    编译FFmpeg到Android studio中

    --extra-ldflags="-Wl,-rpath-link=$SYSROOT/usr/lib -L$SYSROOT/usr/lib -nostdlib++ --sysroot=$SYSROOT" \ --disable-shared \ --enable-static \ --extra-cflags="-I$SYSROOT/usr/include" \ --extra-...

    opencv、cmake编译缺少ffmpeg、ippicv

    IPPICV(Intel Performance Primitives Image Processing Library)是Intel提供的一套优化的图像处理函数库,它利用Intel硬件的特性来加速计算,特别是在多核CPU上。在OpenCV中,IPPICV被用于提高图像处理的效率,...

    不同版本Linux下基于libxml2的C编译问题解决

    解决 Linux 下基于 libxml2 的 C 编译问题 在不同的 Linux 版本下编译基于 libxml2 的 C 项目时,可能会遇到各种问题。本文将解决 libxml2 的 Makefile 编译问题,使用软链接来解决依赖项缺失的问题。 问题背景 --...

    Linux下使用动态库小结

    编译完成后,只需要将`libz-1.2.3`拷贝到目标设备的默认库路径下,或者通过`-rpath`或`LD_LIBRARY_PATH`指定路径,就可以在目标设备上运行了。 #### 三、案例分析 假设有一个简单的测试场景,其中包含两个文件夹:...

    contribute.zip

    在Linux环境下,Qt是一个强大的C++图形用户界面应用程序开发框架,它允许开发者创建美观且功能丰富的桌面和移动应用。本文将深入探讨如何在Qt环境中构建一个项目,生成可执行文件,并将其打包成一个无需依赖外部运行...

    linux下生成so文件并且调用so文件的方法

    在Linux环境下,生成和调用共享库(SO文件,即Shared Object)是常见的软件开发实践。SO文件允许多个程序共享同一段代码,节省内存并提高系统效率。下面将详细介绍如何生成SO文件以及如何在应用程序中调用它们。 一...

    qt-embedded-3.3.4 tslib触摸屏校正+qte3移植+触摸屏+开机启动

    sed -i 's/LDFLAGS:=$(LDFLAGS) -rpath $(PLUGIN_DIR)/LDFLAGS:=$(LDFLAGS) -rpath `cd $(PLUGIN_DIR) && pwd`/g' tslib/plugins/Makefile ``` 接着完成 Tslib 的编译和安装: ```bash make make install ``` **3....

    php-5.6.29.tar.gz

    -with-pdo-mysql=shared,mysqlnd --with-gd --with-iconv --with-zlib --enable-zip --enable-inline-optimization --disable-debug --disable-rpath --enable-shared --enable-xml --enable-bcmath --enable-shmop ...

    patchelf1.0-0.9

    它在Linux系统中扮演着重要的角色,尤其在软件的编译和移植过程中。patchelf 1.0与0.9版本之间的差异可能涉及到功能增强、错误修复或兼容性改进。 patchelf的基本操作包括: 1. **设置RPATH/RUNPATH**:RPATH和...

    Qt自定义动态库的生成和使用

    QMAKE_LFLAGS += -Wl,-rpath,\$$ORIGIN ``` 这里的`yourlibname`应替换为你的库名。 4. **构建库**:在Qt Creator中,选择“Build” &gt; “Build All”或按下F7键,Qt会生成动态库文件。 5. **使用库**:在其他...

    Linux下使用Java调用Hikvision设备网络SDK的使用指南.pdf

    .so文件即Shared Object的简称,在Linux环境下是指编译好的函数库,可被其他程序调用。在功能上,.so文件与Windows系统中的.dll文件类似,都是为了实现函数和数据的共享。Linux操作系统中函数库至关重要,因为许多...

    tslib+Minigui移植到2440总结

    - 将 `LDFLAGS:=$(LDFLAGS)-rpath$(PLUGIN_DIR)` 改为 `LDFLAGS:=$(LDFLAGS)-rpath` 后跟插件目录的绝对路径。 - 解决编译时出现的 “only absolute run-paths are allowed” 错误。 4. **修改 `tests/ts_...

    linux全志R16的linux系统编译的资料_20170502_1655.7z

    全志R16平台编译linux系统V1.0.txt 2017/4/11 13:36 (编译请使用编译android的lichee的选项编译生成的.config文件,不然直接编译会报错!!!!) rootroot@cm-System-Product-Name:/home/wwt/linux_r16$ tar...

Global site tag (gtag.js) - Google Analytics