精华内容
下载资源
问答
  • dlopen 功能:显示加在动态库 ...RTLD_LAZY:延迟加载什么时候真正使用的时候才加载 RTLD_NOW:立即加载 返回值: 成功返回动态库的句柄,失败返回NULL dlsym 功能:获取动态库的的函数地址 参数: handle -&g...

    dlopen
    功能:显示加在动态库
    参数:
    filename -> 给路径按照路径加载,给文件名就根据LD_LIBRARY_PATH环境变量去查找
    flag -> 加载标志
    RTLD_LAZY:延迟加载,什么时候真正使用的时候才加载
    RTLD_NOW:立即加载
    返回值:
    成功返回动态库的句柄,失败返回NULL

    dlsym
    功能:获取动态库的的函数地址
    参数:
    handle -> 动态库的句柄
    symbol -> 函数名
    返回值:
    成功返回函数地址,失败返回NULL

    展开全文
  • 什么时候采用共享动态加载方式呢?比如需要通过程序判断A条件下,加载A共享,B条件下加载B共享,或者条件未达到的情况下加载默认。这种需求,可以不通过gcc编译器,而通过代码来实现动态加载。 C动态加载...

    动态加载

    共享库的加载分静态加载和动态加载。直接使用gcc编译器加载的共享库的方式叫静态加载,而通过程序代码加载共享库的方式称为共享库的动态加载。

    什么时候采用共享库的动态加载方式呢?比如需要通过程序判断A条件下,加载A共享库,B条件下加载B共享库,或者条件未达到的情况下加载默认库。这种需求,可以不通过gcc编译器,而通过代码结合业务逻辑来实现动态加载。

    C动态加载函数

    linux操作系统提供了dl库,可以用来实现共享库的动态加载。
    在C代码文件中加入#include <dlfcn.h> 预处理指令。
    dlfcn.h头文件中含有一下几个函数:

    函数 描述
    void * dlopen(const char * __path, int __mode) 加载库文件并获取一个句柄,共享库引用计数+1。 第一个参数为库文件的路径,如果是相对路径,则需要配置LD_LIBRARY_PATH环境变量来指定加载库文件的附加搜索路径。第二个参数是加载模式,它有两个值:RTLD_LAZY - 延迟加载,当程序使用共享库中的符号时才加载;RTLD_NOW - 立即加载。
    void * dlsym(void * __handle, const char * __symbol) 通过句柄获取一个函数地址。第一个handle参数就是加载的库的句柄,第二个参数是需要从库中加载的函数符号。
    int dlclose(void * __handle) 关闭句柄。成功返回0,失败返回-1。共享库引用计数-1, 当共享库的引用计数为0时,共享库内存将被回收释放。
    char * dlerror(void) 返回最近一个异常信息。

    动态加载共享库例子

    假定我们有一个libmymath.so数学库文件,该共享库的制作可以参考我另外一篇文章:C语言 共享库(动态库)制作
    libmymath.so文件由如下目标文件组成:
    – add.c # 加法实现
    – add.h # 加法头文件
    – sub.c # 减法实现
    – sub.h # 减法头文件

    写个dlmain.c来用代码加载libmymath.so库并调用其中的函数:

    #include <stdio.h>
    #include <dlfcn.h>
    
    int main(void) {
        //加载库文件,并获取其句柄
        void *handle = dlopen("./libmymath.so", RTLD_NOW);
        if (!handle) {
            fprintf(stderr, "dlopen error:%s\n", dlerror());
        }
        //获取库中的add函数,由于dlsym返回的类型是空函数指针,所以需要强制转换为add函数的指针类型
        int (*add)(int, int) = (int (*)(int, int)) dlsym(handle, "add");
        if (!add) {
            fprintf(stderr, "dlsym error:%s\n", dlerror());
            return -1;
        }
        //获取库中的sub函数,由于dlsym返回的类型是空函数指针,所以需要强制转换为sub函数的指针类型
        int (*sub)(int, int) = (int (*)(int, int)) dlsym(handle, "sub");
        if (!sub) {
            fprintf(stderr, "dlsym error:%s\n", dlerror());
            return -1;
        }
        int a = 20;
        int b = 10;
        printf("%d+%d=%d\n", a, b, add(a, b));
        printf("%d-%d=%d\n", a, b, sub(a, b));
        int close_res = dlclose(handle);
        if (close_res == -1) {
            fprintf(stderr, "dlclose error:%s\n", dlerror());
            return -1;
        }
        return 0;
    }
    

    编译:gcc -o dlmain dlmain.c

    运行./dlmain可执行文件,得到库计算出来的结果:

    20+10=30
    20-10=10
    
    展开全文
  • 前两天搞明白了动态链接和静态链接,后面终于也基本上搞懂了我之前不明白的“dlopen”是咋回事,怎么也要扒一扒。...动态加载库在编译的时候,应该是不需要去-l引用lib,而是在可执行程序中,可以自已决定加载...

        前两天搞明白了动态链接库和静态链接库,后面终于也基本上搞懂了我之前不明白的“dlopen”是咋回事,怎么也要扒一扒。

        共享库,有两种形式,第一种就是在上一篇文章中说到的“动态链接库”,而共享库的另一种形式,则被称之为“动态加载库”,也就是我刚才提到的用“dlopen”方式来玩的。动态加载库在编译的时候,应该是不需要去-l引用lib,而是在可执行程序中,可以自已决定加载库的时机。比如程序跑着跑着,突然想用libabc.so库里的一个叫abc的函数了,这时就可以用dlopen去打开这个库,然后使用dlsym去找到abc的函数指针并调用即可。

       这几个以“dl”开头的函数,叫动态加载API,提供了以下这么几个接口来支持动态加载操作:

    void *dlopen( const char *file, int mode ); 

        dlopen的函数功能是打开库文件并返回文件句柄,mode参数表示重定位的时机,有RTLD_NOW和RTLD_LAZY两个值 ,这个我们后面再分析是啥意思。

    void *dlsym( void *restrict handle, const char *restrict name ); 

        dlsym函数的功能是从这个新加载的库里根据传入的函数名,找到该函数的地址

    char *dlerror();

        dlerror没有入参,它会返回发生的上一个错误的字符串

    char *dlclose( void *handle );

        dlclose关闭打开的库文件,实际上如果当前还有其他的程序引用这个库,它是不会被关闭的,多个程序共享时采用引用计数机制,当最后一个引用它的程序关闭它时才会真正的关闭。这几个函数在使用时,需要包含<dlfcn.h>头文件。

    下面我依然用之前sumapp这个简单的demo程序来演示一下动态加载库的用法。

        首先libsum.so生成方式不变,具体可参考上一篇文章。main.c的代码我们需要变一下,重新以dlopen的方式去引用libsum.so,  代码如下:

        

    192:zch kane$ ls
    demodlopen.c    main.c        sum.h        sumappd
    libsum.so    sum.c        sum.o
    192:zch kane$ 
    192:zch kane$ 
    192:zch kane$ 
    192:zch kane$ more demodlopen.c 
    #include<stdio.h>
    #include<dlfcn.h>
    
    int  main(void)
    {
        int iNum1 = 1;
        int iNum2 = 2;
        void * pHandle = NULL;
        int (*pFunc)(int, int) = NULL;
        char * pcError;
        int iRet = 0;
    
        pHandle = dlopen("libsum.so", RTLD_LAZY);
        if (NULL == pHandle)
        {
            printf("Open libsum.so failed!, error message is %s\r\n.", dlerror());
            return 0;
        }
        
        pFunc = dlsym(pHandle, "Sum");
        if (NULL == pFunc)
        {
            printf("Find function Sum failed!, error message is %s\r\n.", dlerror());
            return 0;
        }
        
        iRet =  (*pFunc)(iNum1, iNum2);
        printf("iRet = %d\r\n", iRet);
        dlclose(pHandle);
        return 0; 
    }
    192:zch kane$ 

    编译demodlopen.c,执行sumappd

    192:zch kane$ gcc -rdynamic -o sumappd demodlopen.c -ldl
    192:zch kane$./sumappd 
    iRet = 3

    编译时-rdynamic用来通知链接器将所有符号添加到动态符号表中(目的是能够通过使用 dlopen 来实现向后跟踪)。-ldl 表明一定要将 dllib 链接于该程序。

     

    总结:动态链接库在加载时机是进程启动,而动态加载库则由程序自行决定加载时机。看了下网上有一些同学也不太明白到底什么时候适合用动态链接库,什么时候适合用动态加载库。我说一下我在工作中遇到的一个场景就是用的动态加载。由于我们做的是基于linux的嵌入式软件平台,需要同时支持多款产品,而有些特性或者说业务,在某款产品上可能不支持,以达到产品差异化的目的。比如业务A在运行时可能会用到libabc.so, 但是 libabc.so在某款产品上可能会被裁减掉,因此对于这种情况,在编译版本及写代码的时候,就得用动态加载这种方式。因为如果你用动态链接的方式,而libabc.so刚好在这款产品上被裁掉了,会导致业务A的进程启动失败(动态链接在进程启动的时候去加载动态库失败)。

    更加深入的文章,请参考http://www.ibm.com/developerworks/cn/linux/l-dynamic-libraries/index.html

    转载于:https://www.cnblogs.com/zhengchunhao/p/4893417.html

    展开全文
  • 动态加载so

    2017-08-01 13:42:28
    简介前几天做一个视频播放的功能,用到了...什么动态加载?就是讲so文件不打包进apk,在安装完应用打开app的时候通过后台下载so,将下载下来的so文件再写入到app里面。 首先我们要知道,Android加载so文件的方式

    简介

    前几天做一个视频播放的功能,用到了bilibili开源ijkplayer播放器的(集成ijkplayer),功能确实强大,但就是用到的ffmpeg解码库太大,不得已只能只能将so文件拿出来,通过动态的方式来加载。

    什么是动态加载?

    就是讲so文件不打包进apk,在安装完应用打开app的时候通过后台下载so库,将下载下来的so文件再写入到app里面。
    首先我们要知道,Android加载so文件的方式有两种:

    • System.loadLibrary
    • System.load

    它们都可以用来装载库文件,但是System.load参数必须为库文件的绝对路径,可以是任意路径;System.loadLibrary参数为库文件名,不包含库文件的扩展名,必须是在JVM属性Java.library.path所指向的路径中,路径可以通过System.getProperty('java.library.path') 获得。所有动态加载的时候我们不能用System.loadLibrary,只能用System.load来加载。


    介绍

    1. 下载so文件
    2. 安装
    3. load加载

      其中下载没什么说的,不过推荐Netroid,下载一般下载到sdcard,前面说过System.load参数为绝对路径,也就是说你可以直接加载sdcard上面的so文件,但是在sdcard上可能会被用户删除或者修改,所以我建议将so文件copy到我们app的目录(data/data/包名/app_lib)下面

       public static void loadSoFile(Context context) {
            File dir = context.getDir("libs", Context.MODE_PRIVATE);
            if (!isLoadSoFile(dir)) {
                copy(formPath, dir.getAbsolutePath());
            }
        }
    
      public static boolean isLoadSoFile(File dir) {
            File[] currentFiles;
            currentFiles = dir.listFiles();
            boolean hasJkffmpeg = false;
            if (currentFiles == null) {
                return false;
            }
            for (int i = 0; i < currentFiles.length; i++) {
               if (currentFiles[i].getName().contains(DuduUtil.SoFile.IJKFFMPEG)) {
                    hasJkffmpeg = true;
                }
            }
            return hasJkffmpeg;
        }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    save_snippets.png
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    先判断app_lib下有没有我们需要加载的so文件,如果没有的话复制到指定目录,其中formPath是下载到sdcard上so文件的路径

    ublic static int copy(String fromFile, String toFile) {
            //要复制的文件目录
            File[] currentFiles;
            File root = new File(fromFile);
            //如同判断SD卡是否存在或者文件是否存在
            //如果不存在则 return出去
            if (!root.exists()) {
                return -1;
            }
            //如果存在则获取当前目录下的全部文件 填充数组
            currentFiles = root.listFiles();
    
            //目标目录
            File targetDir = new File(toFile);
            //创建目录
            if (!targetDir.exists()) {
                targetDir.mkdirs();
            }
            //遍历要复制该目录下的全部文件
            for (int i = 0; i < currentFiles.length; i++) {
                if (currentFiles[i].isDirectory()) {
                    //如果当前项为子目录 进行递归
                    copy(currentFiles[i].getPath() + "/", toFile + currentFiles[i].getName() + "/");
    
                } else {
                    //如果当前项为文件则进行文件拷贝
                    Log.e(TAG, "path:" + currentFiles[i].getPath());
                    Log.e(TAG, "name:" + currentFiles[i].getName());
                    if (currentFiles[i].getName().contains(".so")) {
                        int id = copySdcardFile(currentFiles[i].getPath(), toFile + File.separator + currentFiles[i].getName());
                        Log.e(TAG, "id:" + id);
                    }
                }
            }
            return 0;
        }
    
    
        //文件拷贝
        //要复制的目录下的所有非子目录(文件夹)文件拷贝
        public static int copySdcardFile(String fromFile, String toFile) {
    
            try {
                FileInputStream fosfrom = new FileInputStream(fromFile);
                FileOutputStream fosto = new FileOutputStream(toFile);
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                byte[] buffer = new byte[1024];
                int len = -1;
                while ((len = fosfrom.read(buffer)) != -1) {
                    baos.write(buffer, 0, len);
                }
                // 从内存到写入到具体文件
                fosto.write(baos.toByteArray());
                // 关闭文件流
                baos.close();
                fosto.close();
                fosfrom.close();
                return 0;
    
            } catch (Exception ex) {
                return -1;
            }
        }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    save_snippets.png
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    最后一步,load

    File dir = context.getDir("libs", Context.MODE_PRIVATE);
    File[] currentFiles;
    currentFiles = dir.listFiles();
    for (int i = 0; i < currentFiles.length; i++) {
         Log.e(TAG, "#:" + currentFiles[i].getAbsolutePath());
         // System.load(currentFiles[i].getAbsolutePath());
    
     }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    save_snippets.png
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    问题

    1. java.lang.UnsatisfiedLinkError: dlopen failed: “XXXX.so” is 32-bit instead of 64-bit
      大体原因是手机cpu为64位,并且在app中你配置了加载64位(arm64-v8a),所有系统会去加载64位路径下的so库,但是你load的so库却是32位,解决方法有两种:1、将32为库换成64位,2、只加载32位库,在build.gradle中配置,armeabi,armeabi-v7a,x86位32位,arm64-v8a,x86_64是64位。
    defaultConfig {
            applicationId "xxxx"
            minSdkVersion 10
            targetSdkVersion 21
            versionCode 1
            versionName "1.0"
    
            ndk {
                abiFilters "armeabi","armeabi-v7a","x86"
            }
        }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    save_snippets.png
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2.java.lang.UnsatisfiedLinkError: Couldn’t load ijkffmpeg from loader dalvik.system.DexClassLoader[DexPathList[]]: findLibrary returned null

    加载时注意加载so文件的顺序,遇到的问题是load ijkffmpeg.so文件时需要先load另外一个so文件,但是我先load了ffmpeg,所以报了 couldn’t load异常


    展开全文
  • linux 配置和加载动态库 ldconfig

    千次阅读 2016-12-01 15:09:47
    GCC编译C++程序的那些步骤,其中包括编译的时候...动态转载动态库,是为了基于动态库编译链接而来的可执行程序设定的一个程序执行过程中需要的功能,对于那些只基于静态库的可执行程序来说,这个功能没有什么用。
  • 什么动态加载? 之前我们都是用的是自动加载,他是在exe运行启动时,就加载dll。 动态加载,在编译的时候不指定dll,根据代码需要时调用LoadLibrary来加载dll。 而且动态加载可以根据程序需时卸载dll,自动加载...
  • 可惜个人的接受能力还有待提高,视频要反复的看,O(∩_∩)O~在写交叉编译的时候出现了问题,我的理解是freetype的版本比我的.c文件的版本要低级,导致不能用,还没找到解决办法,不知道各位大神们有木有什么解决...
  • android 动态库加载原理分析

    千次阅读 2013-08-19 17:53:34
    说到JNI就不得不提到so,关于so的原理我就不赘述了。...来加载libhello-jni.so,有朋友问这个应该放在什么地方,其实这个可以放在两个地方一个是系统是/system/lib下面,另外一个是/data/data/com.exa
  • 1、静态链接: 静态库在编译链接期间被打包copy到了可执行文件中,也就是说静态库其实是在编译期间...当可执行文件加载(可执行文件复制到内存)完成后,在程序开始运行之前,操作系统就会查找可执行文件依赖的动态库
  • 往.dll里添加了一个接口,在其他程序里获取这个接口的时候返回NULL,但其他接口都能返回地址,这是为什么?求大神解答
  • c# 动态加载链接

    2013-04-17 09:54:43
    我们在编写程序的时候经常会遇到这样的情况:程序中要用到某种计算,而且这种计算的计算方式很多,我们不得不在编写程序时就要考虑的十分全面,将各种情况到考虑到。但是这样做又非常的费力,因为我们无法预测到程序...
  • 今天在写一个wpf小程序时,少了2行代码,程序运行的结果就不一样了 ...#### 请这两行代码在程序执行过程中起到了什么作用,以至于没有这两行代码的时候wpf在调用dll的时候执行结果与控制台不一样? # 谢谢!
  • 当负载是异步发生,所以我已经包括了一个回调的版本太多,所以你知道什么时候插入脚本已经完成,你就可以开始使用jQuery! 我以前发布的有关插入脚本到安全的网页 ,以便有更多的选项,你也有。 使用普通的...
  • Linux动态库依赖其它动态库的问题

    千次阅读 2019-11-15 11:17:45
    1 前言 这两天在编写一个插件系统Demo的...这个报错翻译过来就是没有在命令行中指定该动态库。 这个报错就很搞事了,你说你明明知道需要哪个库,为什么不直接帮我链接呢,非得我显示的在命令行中指定呢? 2 现象描...
  • 什么动态链接

    2019-09-16 11:03:55
    什么是dll: dll只是一组源代码的模块,每个模块包含一些可供应用程序...dll加载完成后,这个时候dll对于进程中的线程来说只是一些被放在地址进程空间附加的代码和数据,操作系统为了节省内存空间,同一个dll在内存...
  • linux加载原理

    2017-09-25 13:29:51
    +++原理+++ linux调用的方式有三种: 1、静态链接 2、动态链接 3、动态加载库  动态链接(共享)和动态加载库... 所以动态加载库就需要一组函数来控制什么时候加载。这些函数是dlopen() dlerror()
  • 编译lua动态库

    2017-11-14 15:00:00
    编译lua解释器的时候要依赖于lua动态库来编译,不能编译成静态的,否则在调用c模块的时候就会出现multiple Lua VMs detected 的错误。 multiple Lua VMs detected,什么意思呢,就是说有多个虚拟机加载,起冲突了。...
  • 动态库也叫共享库(share object),在程序链接的时候作些标记,然后在程序开始启动运行的时候,动态地加载所需库(模块)。 特点: 1.编译时(链接阶段)仅仅记录用到哪个动态库中的哪个符号(函数),不复制库中...
  • 0x01.为什么要so远程加载?(又叫动态加载) so体积过大,如果直接集成在apk里面的话,会造成包体积膨胀。所以有了这种方案。...动态加载so方案原理 Android加载so文件的方式有两种: System.loadLibra...
  • iOS 静态库和动态库

    2016-10-25 15:14:00
    什么要分为动态和静态两种呢?先看下图: 我们可以很清楚的看到: 对于静态而言,在编译链接的时候,会将静态的所有文件都添加到 目标 app 可执行文件中,并在程序运行之后,静态与 ...
  • Android动态加载—so文件

    万次阅读 2016-04-05 17:18:01
    简介前几天做一个视频播放的功能,用到了...什么动态加载?就是讲so文件不打包进apk,在安装完应用打开app的时候通过后台下载so,将下载下来的so文件再写入到app里面。 首先我们要知道,Android加载so文件的方式
  • 所谓动态链接,是指编译的时候不会把程序引用到的插入到执行程序里,而是在执行时候才会去加载相关的,所有用到此的程序可以共享一份代码。 这样带来的好处是可执行程序所占的空间变小了,同时,如果...
  • 所谓动态链接,也就是说编译的时候不会真的把你引用到的给编到你的执行程序里,而是在执行时候才会去加载相关的,所有用到此的程序可以共享一份代码,这样带来的好处是可执行程序所占的空间变小了,同时,...
  • 程序在执行的时候,需要使用到动态库里的函数的时候,程序调用动态链接器提供的API,请求动态链接器将需要的动态库加载到内存. dlopen(3) dlclose(3) dlerror(3) dlsysm(3) #include <dlfcn.h> void *dlopen...
  • 动态库里面还有一种特别的是运行时有选择加载的插件,我改cocosbuilder的时候,载入的插件的函数有initWithBundle什么的,和这个有点儿联系。 静态库是会被编进去的,但是不是全体,没有用到的符号是不会被编进去的...
  • Linux加载库文件

    2018-04-06 19:16:11
    就用这个图来解释。 其中红色的线是第一次调用库函数的时候程序执行流的路线。蓝色的是程序以后调用要走的路线。 ...为了解决这一问题设计了一种动态加载,这种里面的代码跟位置没有关...
  • 我们写程序的时候会需要加载库,一般需要先include头文件,然后再调用库函数, 而库又分为两种,静态库(lib)和动态库(dll), 那么这两种库有什么区别吗 静态库是我们的程序在链接时会把用到的静态库全部都链接进去,...

空空如也

空空如也

1 2 3 4 5 ... 11
收藏数 204
精华内容 81
关键字:

动态库什么时候动态加载