精华内容
下载资源
问答
  • 《CMake实践》笔记三:构建静态库与动态库 及 如何使用外部共享库和头文件 五、静态库与动态库构建 读者云,太罗唆了,一个Hello World就折腾了两个大节。OK,从本节开始,我们不再折腾Hello Wor...

    《CMake实践》笔记一:PROJECT/MESSAGE/ADD_EXECUTABLE

    《CMake实践》笔记二:INSTALL/CMAKE_INSTALL_PREFIX

    《CMake实践》笔记三:构建静态库与动态库 及 如何使用外部共享库和头文件

     

    五、静态库与动态库构建

    读者云,太能罗唆了,一个Hello World就折腾了两个大节。OK,从本节开始,我们不再折腾Hello World了,我们来折腾Hello World的共享库。

    本节的任务:

    1、建立一个静态库和动态库,提供HelloFunc函数供其他程序编程使用,HelloFunc向终端输出Hello World字符串。

    2、安装头文件与共享库。

     

    (一)、准备工作:

    在/backup/cmake目录建立t3目录,用于存放本节涉及到的工程

     

    (二)、建立共享库

    cd /backup/cmake/t3
    mkdir lib

    在t3目录下建立CMakeLists.txt,内容如下:

    PROJECT(HELLOLIB)
    ADD_SUBDIRECTORY(lib)

    在lib目录下建立两个源文件hello.c与hello.h

    hello.c内容如下:

    #include "hello.h"
    void HelloFunc()
    {
        printf("Hello World\n");
    }

    hello.h内容如下:

    #ifndef HELLO_H
    #define HELLO_H
    #include <stdio.h>
    void HelloFunc();
    #endif

    在lib目录下建立CMakeLists.txt,内容如下:

    SET(LIBHELLO_SRC hello.c)
    ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})

     

    (三)、编译共享库

    仍然采用 out-of-source 编译的方式,按照习惯,我们建立一个build目录,在build目录中

    cmake ..
    make

    这时,你就可以在lib目录得到一个libhello.so,这就是我们期望的共享库。

    如果你要指定libhello.so生成的位置,可以通过在主工程文件CMakeLists.txt中修改ADD_SUBDIRECTORY(lib)指令来指定一个编译输出位置或者在lib/CMakeLists.txt中添加SET(LIBRARY_OUTPUT_PATH <路径>)来指定一个新的位置。这两者的区别我们上一节已经提到了,所以,这里不再赘述,下面,我们解释一下一个新的指令ADD_LIBRARY:

    ADD_LIBRARY(libname [SHARED|STATIC|MODULE][EXCLUDE_FROM_ALL]source1 source2 ... sourceN)

    你不需要写全libhello.so,只需要填写hello即可,cmake系统会自动为你生成libhello.X。类型有三种:

    • SHARED,动态库(扩展名为.so)
    • STATIC,静态库(扩展名为.a)
    • MODULE,在使用dyld的系统有效,如果不支持dyld,则被当作SHARED对待。
    • EXCLUDE_FROM_ALL 参数的意思是这个库不会被默认构建,除非有其他的组件依赖或者手工构建。

    C/C++ 静态链接库(.a) 与 动态链接库(.so)库

    Linux C 静态库(.a) 与 动态库(.so)的详解

     

    (四)、添加静态库

    同样使用上面的指令,我们在支持动态库的基础上再为工程添加一个静态库,按照一般的习惯,静态库名字跟动态库名字应该是一致的,只不过后缀是.a罢了。下面我们用这个指令再来添加静态库:

    ADD_LIBRARY(hello STATIC ${LIBHELLO_SRC})

    然后再在build目录进行外部编译,我们会发现,静态库根本没有被构建,仍然只生成了一个动态库。因为hello作为一个target是不能重名的,所以,静态库构建指令无效。

    如果我们把上面的hello修改为hello_static:

    ADD_LIBRARY(hello_static STATIC ${LIBHELLO_SRC})

    就可以构建一个libhello_static.a的静态库了。这种结果显示不是我们想要的,我们需要的是名字相同的静态库和动态库,因为target名称是唯一的,所以,我们肯定不能通过ADD_LIBRARY指令来实现了。这时候我们需要用到另外一个指令:

    SET_TARGET_PROPERTIES,其基本语法是:
    SET_TARGET_PROPERTIES(target1 target2 ...PROPERTIES prop1 value1prop2 value2 ...)

    这条指令可以用来设置输出的名称,对于动态库,还可以用来指定动态库版本和API版本。在本例中,我们需要作的是向lib/CMakeLists.txt中添加一条:

    SET_TARGET_PROPERTIES(hello_static PROPERTIES OUTPUT_NAME "hello")

    这样,我们就可以同时得到libhello.so/libhello.a两个库了。与他对应的指令是:

    GET_TARGET_PROPERTY(VAR target property)

    具体用法如下例,我们向lib/CMakeListst.txt中添加:

    GET_TARGET_PROPERTY(OUTPUT_VALUE hello_static OUTPUT_NAME)
    MESSAGE(STATUS  "This is the hello_static OUTPUT_NAME:" ${OUTPUT_VALUE})

    如果没有这个属性定义,则返回 NOTFOUND。

    让我们来检查一下最终的构建结果,我们发现,libhello.a已经构建完成,位于build/lib目录中,但是libhello.so去消失了。这个问题的原因是:cmake在构建一个新的target时,会尝试清理掉其他使用这个名字的库,因为,在构建libhello.a时,就会清理掉libhello.so.为了回避这个问题,比如再次使用SET_TARGET_PROPERTIES定义

    CLEAN_DIRECT_OUTPUT属性。向lib/CMakeLists.txt中添加:

    SET_TARGET_PROPERTIES(hello PROPERTIES CLEAN_DIRECT_OUTPUT 1)
    SET_TARGET_PROPERTIES(hello_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)

    这时候,我们再次进行构建,会发现build/lib目录中同时生成了 libhello.so 和 libhello.a

     

    (五)、动态库版本号

    按照规则,动态库是应该包含一个版本号的,我们可以看一下系统的动态库,一般情况是

    libhello.so.1.2
    libhello.so ->libhello.so.1
    libhello.so.1->libhello.so.1.2

    为了实现动态库版本号,我们仍然需要使用SET_TARGET_PROPERTIES指令。具体使用方法如下:

    SET_TARGET_PROPERTIES(hello PROPERTIES VERSION 1.2 SOVERSION 1)

    VERSION指代动态库版本,SOVERSION指代API版本。将上述指令加入lib/CMakeLists.txt中,重新构建看看结果。

    在build/lib目录会生成:

    libhello.so.1.2
    libhello.so.1->libhello.so.1.2
    libhello.so ->libhello.so.1

     

    (六)、安装共享库和头文件

    以上面的例子,我们需要将libhello.a, libhello.so.x以及hello.h安装到系统目录,才能真正让其他人开发使用,在本例中我们将hello的共享库安装到<prefix>/lib目录,将hello.h安装到<prefix>/include/hello目录。

    利用上一节了解到的INSTALL指令,我们向lib/CMakeLists.txt中添加如下指令:

    INSTALL(TARGETS hello hello_static
    LIBRARY DESTINATION lib
    ARCHIVE DESTINATION lib)
    INSTALL(FILES hello.h DESTINATION include/hello)

    注意,静态库要使用ARCHIVE关键字通过:

    cmake -DCMAKE_INSTALL_PREFIX=/usr ..
    make
    make install

    我们就可以将头文件和共享库安装到系统目录/usr/lib和/usr/include/hello中了。

     

    (七)、小结

    本小节,我们谈到了:

    如何通过 ADD_LIBRARY 指令构建动态库和静态库。

    如何通过 SET_TARGET_PROPERTIES 同时构建同名的动态库和静态库。

    如何通过 SET_TARGET_PROPERTIES 控制动态库版本

    最终使用上一节谈到的 INSTALL 指令来安装头文件和动态、静态库。

    在下一节,我们需要编写另一个高级一点的Hello World来演示怎么使用我们已经构建的构建的共享库libhello和外部头文件。

     


     

    以下是我跟着做的截图,确实很方便:(这里有点失误,设置了个CC的环境变量,所以这里找的是arm-linux-gcc去了。。本意是用gcc编译的)

     


     

    六、如何使用外部共享库和头文件

    抱歉,本节仍然继续折腾Hello World。

    上一节我们已经完成了libhello动态库的构建以及安装,本节我们的任务很简单:

    编写一个程序使用我们上一节构建的共享库。

    1、准备工作:

    请在/backup/cmake目录建立t4目录,本节所有资源将存储在t4目录。

     

    2、重复以前的步骤,建立src目录,编写源文件main.c,内容如下:

    #include <hello.h>
    int main()
    {
        HelloFunc();
        return 0;
    }

    编写工程主文件CMakeLists.txt

    PROJECT(NEWHELLO)
    ADD_SUBDIRECTORY(src)

    编写src/CMakeLists.txt

    ADD_EXECUTABLE(main main.c)

    上述工作已经严格按照我们前面季节提到的内容完成了。

     

    3、外部构建

    按照习惯,仍然建立build目录,使用cmake ..方式构建。

    过程:

    cmake ..
    make

    构建失败,如果需要查看细节,可以使用第一节提到的方法

    make VERBOSE=1

    来构建

    错误输出为是:

    /backup/cmake/t4/src/main.c:1:19: error: hello.h: 没有那个文件或目录

     

    4、引入头文件搜索路径

    hello.h位于/usr/include/hello目录中,并没有位于系统标准的头文件路径,(有人会说了,白痴啊,你就不会include <hello/hello.h>,同志,要这么干,我这一节就没什么可写了,只能选择一个glib或者libX11来写了,这些代码写出来很多同志是看不懂的)

    为了让我们的工程能够找到hello.h头文件,我们需要引入一个新的指令

    INCLUDE_DIRECTORIES,其完整语法为:

    INCLUDE_DIRECTORIES([AFTER|BEFORE] [SYSTEM] dir1 dir2 ...)

    这条指令可以用来向工程添加多个特定的头文件搜索路径,路径之间用空格分割,如果路径中包含了空格,可以使用双引号将它括起来,默认的行为是追加到当前的头文件搜索路径的后面,你可以通过两种方式来进行控制搜索路径添加的方式:

    (1)、CMAKE_INCLUDE_DIRECTORIES_BEFORE,通过SET这个cmake变量为on,可以将添加的头文件搜索路径放在已有路径的前面。

    (2)、通过AFTER或者BEFORE参数,也可以控制是追加还是置前。现在我们在src/CMakeLists.txt中添加一个头文件搜索路径,方式很简单,加入:INCLUDE_DIRECTORIES(/usr/include/hello)

    进入build目录,重新进行构建,这是找不到hello.h的错误已经消失,但是出现了一个新的错误:

    main.c:(.text+0x12): undefined reference to `HelloFunc'

    因为我们并没有link到共享库libhello上。

     

    5、为target添加共享库

    我们现在需要完成的任务是将目标文件链接到libhello,这里我们需要引入两个新的指令

    LINK_DIRECTORIES和TARGET_LINK_LIBRARIES
    LINK_DIRECTORIES的全部语法是:
    LINK_DIRECTORIES(directory1 directory2 ...)

    这个指令非常简单,添加非标准的共享库搜索路径,比如,在工程内部同时存在共享库和可执行二进制,在编译时就需要指定一下这些共享库的路径。这个例子中我们没有用到这个指令。

    TARGET_LINK_LIBRARIES的全部语法是:
    TARGET_LINK_LIBRARIES(target library1<debug | optimized> library2...)

    这个指令可以用来为target添加需要链接的共享库,本例中是一个可执行文件,但是同样可以用于为自己编写的共享库添加共享库链接。为了解决我们前面遇到的HelloFunc未定义错误,我们需要作的是向src/CMakeLists.txt中添加如下指令:

    TARGET_LINK_LIBRARIES(main hello)

    也可以写成

    TARGET_LINK_LIBRARIES(main libhello.so)

    这里的hello指的是我们上一节构建的共享库libhello.

    进入build目录重新进行构建。

    cmake ..
    make

    这是我们就得到了一个连接到libhello的可执行程序main,位于build/src目录,运行main的结果是输出:

    Hello World

    让我们来检查一下main的链接情况:

    ldd src/main
    linux-gate.so.1 => (0xb7ee7000)
    libhello.so.1 => /usr/lib/libhello.so.1 (0xb7ece000)
    libc.so.6 => /lib/libc.so.6 (0xb7d77000)
    /lib/ld-linux.so.2 (0xb7ee8000)

    可以清楚的看到main确实链接了共享库libhello,而且链接的是动态库libhello.so.1

    那如何链接到静态库呢?

    方法很简单:

    将TARGET_LINK_LIBRRARIES指令修改为:

    TARGET_LINK_LIBRARIES(main libhello.a)

    重新构建后再来看一下main的链接情况

    ldd src/main
    linux-gate.so.1 => (0xb7fa8000)
    libc.so.6 => /lib/libc.so.6 (0xb7e3a000)
    /lib/ld-linux.so.2 (0xb7fa9000)

    说明,main确实链接到了静态库libhello.a

     

    6、特殊的环境变量 CMAKE_INCLUDE_PATH 和 CMAKE_LIBRARY_PATH

    务必注意,这两个是环境变量而不是cmake变量。使用方法是要在bash中用export或者在csh中使用set命令设置或者CMAKE_INCLUDE_PATH=/home/include cmake ..等方式。

    这两个变量主要是用来解决以前autotools工程中--extra-include-dir等参数的支持的。也就是,如果头文件没有存放在常规路径(/usr/include, /usr/local/include等),则可以通过这些变量就行弥补。我们以本例中的hello.h为例,它存放在/usr/include/hello目录,所以直接查找肯定是找不到的。前面我们直接使用了绝对路径INCLUDE_DIRECTORIES(/usr/include/hello)告诉工程这个头文件目录。为了将程序更智能一点,我们可以使用CMAKE_INCLUDE_PATH来进行,使用bash的方法如下:

    export CMAKE_INCLUDE_PATH=/usr/include/hello然后在头文件中将INCLUDE_DIRECTORIES(/usr/include/hello)替换为:

    FIND_PATH(myHeader hello.h)
    IF(myHeader)
    INCLUDE_DIRECTORIES(${myHeader})
    ENDIF(myHeader)

    上述的一些指令我们在后面会介绍。这里简单说明一下,FIND_PATH用来在指定路径中搜索文件名,比如:

    FIND_PATH(myHeader NAMES hello.h PATHS /usr/include/usr/include/hello)

    这里我们没有指定路径,但是,cmake仍然可以帮我们找到hello.h存放的路径,就是因为我们设置了环境变量CMAKE_INCLUDE_PATH。如果你不使用FIND_PATH,CMAKE_INCLUDE_PATH变量的设置是没有作用的,你不能指望它会直接为编译器命令添加参数-I<CMAKE_INCLUDE_PATH>。以此为例,CMAKE_LIBRARY_PATH可以用在FIND_LIBRARY中。同样,因为这些变量直接为FIND_指令所使用,所以所有使用FIND_指令的cmake模块都会受益。

     

    7、小节

    本节我们探讨了:

    如何通过INCLUDE_DIRECTORIES指令加入非标准的头文件搜索路径。

    如何通过LINK_DIRECTORIES指令加入非标准的库文件搜索路径。

    如果通过TARGET_LINK_LIBRARIES为库或可执行二进制加入库链接。

    并解释了如果链接到静态库。

    到这里为止,您应该基本可以使用cmake工作了,但是还有很多高级的话题没有探讨,比如编译条件检查、编译器定义、平台判断、如何跟pkgconfig配合使用等等。

    到这里,或许你可以理解前面讲到的“cmake的使用过程其实就是学习cmake语言并编写cmake程序的过程”,既然是“cmake语言”,自然涉及到变量、语法等。

    下一节,我们将抛开程序的话题,看看常用的CMAKE变量以及一些基本的控制语法规则。

    未完,待续。。。。

     


     

    这里关于LINK_DIRECTORIES似乎有个bug。基本上按照上述所写方法,只是我没有将测试用的hello.h和libhello.so安装在系统的usr/lib目录下。于是我就需要用到这个LINK_DIRECTORIES指定我的库文件的目录。main.c的CMakeLists.txt如下:

    ADD_EXECUTABLE(main main.c)
    FIND_PATH(myHeader hello.h)
    IF(myHeader)
    INCLUDE_DIRECTORIES(${myHeader})
    ENDIF(myHeader)
    TARGET_LINK_LIBRARIES(main libhello.so)
    LINK_DIRECTORIES(/home/wideking/cmakeDemo/libhello/bulid)

    在编译的时候它就是找不到我的libhello.so文件。goole了一下,有人试过将ADD_EXECUTABLE和LINK_DIRECTORIES互换了下位置就行了。我也试了试,提示错误,必须先有main,才能有库的链接,确实也应该这样。于是再在后面增加一行ADD_EXECUTABLE就变成了这样:

    ADD_EXECUTABLE(main main.c)
    FIND_PATH(myHeader hello.h)
    IF(myHeader)
    INCLUDE_DIRECTORIES(${myHeader})
    ENDIF(myHeader)
    TARGET_LINK_LIBRARIES(main libhello.so)
    LINK_DIRECTORIES(/home/wideking/cmakeDemo/libhello/bulid)
    ADD_EXECUTABLE(main main.c)

    虽然有构建的时候有warning,但是这样才能正常的使用。我是在cmake2.6版本中测试的。不知道这个是我没理解对还是咋的。。。。

    那个warning就是不得不多添加了一次ADD_EXECUTABLE出来的

     

     

    《CMake实践》笔记一:PROJECT/MESSAGE/ADD_EXECUTABLE

    《CMake实践》笔记二:INSTALL/CMAKE_INSTALL_PREFIX

    《CMake实践》笔记三:构建静态库与动态库 及 如何使用外部共享库和头文件 

    本文转自:https://www.cnblogs.com/52php/p/5681755.html

    展开全文
  • 动态库中,关于全局变量的调用

    千次阅读 2014-09-26 11:01:01
    测试目的:动态库中全局变量使用方法 cheshi

    测试目的:动态库中全局变量的使用方法


    测试经过:动态库a中有一个全局变量,动态库b链接动态库a,主程序c链接a、b,在程序c中改变全局变量的值,查看pri在动态库b中的值是否改变了


    测试结果:主程序和库b共用一套a的动态库,共用一套全局变量。


    库a的代码:

    #include<stdio.h>
    
    int pri =0;
    
    void fun()
    {
    	printf("i am is a ,pri = %d\n",pri);
    }
    void change()
    {
    	pri = 6;
    }

    编译:gcc -shared sa.c -o libsa.so


    库b的代码:

    #include<stdio.h>
    #include<sa.h>
    
    void fun_b()
    {
    	printf("i am is b\n");
    	fun();
    }
    
    编译:gcc -shared sb.c -o libsb.so

    主程序C的代码:

    #include<stdio.h>
    
    #include "sa.h"
    #include "sb.h"
    
    int main()
    {
    	fun();
    	printf("===========================\n");
    	fun_b();
    	printf("===========================\n");
    	change();
    	printf("===========================\n");
    	fun_b();
    	printf("===========================\n");
    	fun();
    }
    

    编译:gcc -I../sa -I../sb -o test main.c -lsa -lsb 

    注意:动态库使用的时候ldd test会发现自己编译的库无法找到,所以可以把动态库移动到/lib或/usr/lib目录下


    输出结果:

    i am is a ,pri = 0
    ===========================
    i am is b
    i am is a ,pri = 0
    ===========================
    ===========================
    i am is b
    i am is a ,pri = 6
    ===========================
    i am is a ,pri = 6

    展开全文
  • [原]模块间(dll, exe)使用导出变量、静态变量和外部变量的试验与结论 Technorati 标签: vc,模块,导出变量,静态变量,外部变量 // Dll头文件声明 AFX_EXT_DATA int D1_nCount; extern int D1_nCountE; static ...

    [原]模块间(dll, exe)使用导出变量、静态变量和外部变量的试验与结论
    Technorati 标签: vc,模块,导出变量,静态变量,外部变量
    // Dll头文件声明

    AFX_EXT_DATA int D1_nCount;

    extern int D1_nCountE;

    static int D1_nCountS = 0;

    AFX_EXT_API int D1_GetCount();

    // 结论:多模块调用时,或重复调用时,模块内的静态变量是唯一的,不会重复分配内存
    int nCount = D1_GetCount();
    nCount = D2_GetCount();
    nCount = D1_GetCount();

    // 结论:dll中声明的静态变量在每个使用的cpp下均有一份拷贝,多模块更是如此(静态变量在编译时会分别拷贝)
    nCount = D1_nCountS;
    D1_nCountS = 2;

    // 结论:dll中声明的外部变量不能用于其他模块,链接失败(基地址都不一样,肯定不行)
    nCount = D1_nCountE;
    D1_nCountE = 2;

    // 结论:dll中导出的数据到处都可以用,在模块内部只有一份拷贝,每个用到的模块各有一份拷贝
    nCount = D1_nCount;
    D1_nCount = 2;

    ---- 2008年6月2日

    以下后续试验得出了新的结论:

    // Dll头文件声明

    #ifdef DLL2_EXPORTS
    #define D2_API        __declspec(dllexport)
    #else
    #define D2_API        __declspec(dllimport)
    #endif

    D2_API extern int D2_nCount;

    // 结论:dll中导出变量在其所在模块为导出,在其他模块必须为导入
    // 结论:dll中导出的外部变量到处都可以用,在所有模块中都只有一份拷贝
    // 结论:dll中导出的变量到处都可以用,在所有模块中都只有一份拷贝,
    // 但是在其所在模块只能包含一次(否则为重定义),所以只能声明为外部变量
    nCount = D2_nCount;
    D2_nCount = 2;

    // 总结论:dll中的变量一般情况下是以函数接口形式导出,
    // 但在某些情况下可能需要在模块间直接使用,那么就有两种方法:
    // 如果需要该变量在每个模块都有一份拷贝,那么可以使用static声明,
    // 不过这种用途一般比较少。。还有就是使用__declspec(dllexport) extern声明,
    // 一般都是需要各个模块公用一份拷贝,注意在其他模块使用时需要用
    // __declspec(dllexport)导入该变量,否则就又是导出了,而且没有实现

     

    DLL文件(Dynamic Linkable Library 即动态链接库文件),是一种不能单独运行的文件,它允许程序共享执行特殊任务所必需的代码和其他资源
    比较大的应用程序都由很多模块组成,这些模块分别完成相对独立的功能,它们彼此协作来完成整个软件系统的工作。可能存在一些模块的功能较为通用,在构造其它软件系统时仍会被使用。在构造软件系统时,如果将所有模块的源代码都静态编译到整个应用程序 EXE 文件中,会产生一些问题:一个缺点是增加了应用程序的大小,它会占用更多的磁盘空间,程序运行时也会消耗较大的内存空间,造成系统资源的浪费;另一个缺点是,在编写大的 EXE 程序时,在每次修改重建时都必须调整编译所有源代码,增加了编译过程的复杂性,也不利于阶段性的单元测试。
    Windows 系统平台上提供了一种完全不同的较有效的编程和运行环境,你可以将独立的程序模块创建为较小的 DLL 文件,并可对它们单独编译和测试。在运行时,只有当 EXE 程序确实要调用这些 DLL 模块的情况下,系统才会将它们装载到内存空间中。这种方式不仅减少了 EXE 文件的大小和对内存空间的需求,而且使这些 DLL 模块可以同时被多个应用程序使用。Windows 自己就将一些主要的系统功能以 DLL 模块的形式实现。
    一般来说,DLL 是一种磁盘文件,以.dll、.DRV、.FON、.SYS 和许多以 .EXE 为扩展名的系统文件都可以是 DLL。它由全局数据、服务函数和资源组成,在运行时被系统加载到调用进程的虚拟空间中,成为调用进程的一部分。如果与其它 DLL 之间没有冲突,该文件通常映射到进程虚拟空间的同一地址上。DLL 模块中包含各种导出函数,用于向外界提供服务。DLL 可以有自己的数据段,但没有自己的堆栈,使用与调用它的应用程序相同的堆栈模式;一个 DLL 在内存中只有一个实例;DLL 实现了代码封装性;DLL 的编制与具体的编程语言及编译器无关。
    在 Win32 环境中,每个进程都复制了自己的读/写全局变量。如果想要与其它进程共享内存,必须使用内存映射文件或者声明一个共享数据段。DLL 模块需要的堆栈内存都是从运行进程的堆栈中分配出来的。Windows 在加载 DLL 模块时将进程函数调用与 DLL 文件的导出函数相匹配。Windows 操作系统对 DLL 的操作仅仅是把 DLL 映射到需要它的进程的虚拟地址空间里去。DLL 函数中的代码所创建的任何对象(包括变量)都归调用它的线程或进程所有。
    调用方式:
    1、静态调用方式:由编译系统完成对 DLL 的加载和应用程序结束时 DLL 卸载的编码(如还有其它程序使用该 DLL,则 Windows 对 DLL 的应用记录减1,直到所有相关程序都结束对该 DLL 的使用时才释放它,简单实用,但不够灵活,只能满足一般要求。
    隐式的调用:需要把产生动态连接库时产生的 .LIB 文件加入到应用程序的工程中,想使用 DLL 中的函数时,只须说明一下。隐式调用不需要调用 LoadLibrary() 和 FreeLibrary()。程序员在建立一个 DLL 文件时,链接程序会自动生成一个与之对应的 LIB 导入文件。该文件包含了每一个 DLL 导出函数的符号名和可选的标识号,但是并不含有实际的代码。LIB 文件作为 DLL 的替代文件被编译到应用程序项目中。
    当程序员通过静态链接方式编译生成应用程序时,应用程序中的调用函数与 LIB 文件中导出符号相匹配,这些符号或标识号进入到生成的 EXE 文件中。LIB 文件中也包含了对应的 DL L文件名(但不是完全的路径名),链接程序将其存储在 EXE 文件内部。
    当应用程序运行过程中需要加载 DLL 文件时,Windows 根据这些信息发现并加载 DLL,然后通过符号名或标识号实现对 DLL 函数的动态链接。所有被应用程序调用的 DLL 文件都会在应用程序 EXE 文件加载时被加载在到内存中。可执行程序链接到一个包含 DLL 输出函数信息的输入库文件(.LIB文件)。操作系统在加载使用可执行程序时加载 DLL。可执行程序直接通过函数名调用 DLL 的输出函数,调用方法和程序内部其 它的函数是一样的。
    2、动态调用方式:是由编程者用 API 函数加载和卸载 DLL 来达到调用 DLL 的目的,使用上较复杂,但能更加有效地使用内存,是编制大型应用程序时的重要方式。
    显式的调用:
    是指在应用程序中用 LoadLibrary 或 MFC 提供的 AfxLoadLibrary 显式的将自己所做的动态连接库调进来,动态连接库的文件名即是上面两个函数的参数,再用 GetProcAddress() 获取想要引入的函数。自此,你就可以象使用如同本应用程序自定义的函数一样来调用此引入函数了。在应用程序退出之前,应该用 FreeLibrary 或 MFC 提供的 AfxFreeLibrary 释放动态连接库。直接调用 Win32 的 LoadLibary 函数,并指定 DLL 的路径作为参数。LoadLibary 返回 HINSTANCE 参数,应用程序在调用 GetProcAddress 函数时使用这一参数。GetProcAddress 函数将符号名或标识号转换为 DLL 内部的地址。程序员可以决定 DLL 文件何时加载或不加载,显式链接在运行时决定加载哪个 DLL 文件。使用 DLL 的程序在使用之前必须加载(LoadLibrary)加载DLL从而得到一个DLL模块的句柄,然后调用 GetProcAddress 函数得到输出函数的指针,在退出之前必须卸载DLL(FreeLibrary)。
    正因为DLL 有占用内存小,好编辑等的特点有很多电脑病毒都是DLL格式文件。但不能单独运行。
    动态链接库通常都不能直接运行,也不能接收消息。它们是一些独立的文件,其中包含能被可执行程序或其它DLL调用来完成某项工作的函数。只有在其它模块调用动态链接库中的函数时,它才发挥作用。

    打得累死了,大哥你多给积分吧

    展开全文
  • I . Android Studio 中使用 Android.mk 配置动态库库 总结 II . 第三方动态库来源 III ....IV . 预编译 第三方 动态库 ( ... 动态库加载版本限制 ( 6.0 以上 不能使用 Android.mk 配置动态库 ) IX . 完整代码示例 1 . bu



    I . Android Studio 中使用 Android.mk 配置动态库 总结



    Android Studio 中使用 Android.mk 配置第三方 动态库 :


    ① Android.mk 脚本路径设置 : 在 Module 级别的 build.gradle 脚本中配置 Android.mk 构建脚本的路径 ;

        externalNativeBuild {
            ndkBuild{
                path "src/main/ndkBuild_Shared/Android.mk"
            }
        }
    

    ② 预编译第三方动态库 : 在 Android.mk 中预编译动态库 , 注意动态库与静态库使用的配置不同 , 这里以动态库举例 :

    include $(CLEAR_VARS)
    LOCAL_MODULE := add
    LOCAL_SRC_FILES := libadd.so
    include $(PREBUILT_SHARED_LIBRARY)
    

    ③ 链接动态库 : 在 Android.mk 中预链接动态库或静态库 , 注意动态库与静态库使用的配置不同 , 这里以动态库举例 :

    LOCAL_SHARED_LIBRARIES := add
    

    ④ Java 代码实现 : 声明 native 方法 , 加载编译的动态库 ;


    ⑤ C 代码实现 : 声明函数库中的函数 , 调用动态库中的函数 ;



    II . 第三方动态库来源



    1 . 第三方动态库源码 : add.c ;

    #include <stdio.h>
    
    int add(int a, int b){
    	return a + b;
    }
    

    2 . Ubuntu 交叉编译过程 : 参考 【Android NDK 开发】Ubuntu 函数库交叉编译 ( Android 动态库交叉编译 | Android 静态库交叉编译 ) , 最终编译出 libadd.so 动态库 , 和 libadd.a 静态库 ;



    III . 配置 Android.mk 构建脚本路径



    1 . 源码 编译 / 打包 配置 原理 : 【Android NDK 开发】Android Studio 的 NDK 配置 ( 源码编译配置 | 构建脚本配置 | 打包配置 | CMake 配置 | ndkBuild 配置 ) : I . 源码编译配置


    2 . 构建脚本路径配置 原理 : 【Android NDK 开发】Android Studio 的 NDK 配置 ( 源码编译配置 | 构建脚本配置 | 打包配置 | CMake 配置 | ndkBuild 配置 ) : II . 构建脚本配置


    3 . 这里直接设置 Android.mk 构建脚本路径 : 省略无关配置 , 只保留 NDK 相关配置 ;

    apply plugin: 'com.android.application'
    
    android {
        ...
        defaultConfig {
         	...
            // 配置 AS 工程中的 C/C++ 源文件的编译
            //     defaultConfig 内部的 externalNativeBuild 配置的是配置 AS 工程的 C/C++ 源文件编译参数
            //     defaultConfig 外部的 externalNativeBuild 配置的是 CMakeList.txt 或 Android1.mk 构建脚本的路径
            externalNativeBuild {
                /*cmake {
                    cppFlags ""
    
                    //配置编译 C/C++ 源文件为哪几个 CPU 指令集的函数库 (arm , x86 等)
                    abiFilters "armeabi-v7a"
                }*/
                ndkBuild{
                    abiFilters "armeabi-v7a" /*, "arm64-v8a", "x86", "x86_64"*/
                }
            }
    
            //配置 APK 打包 哪些动态库
            //  示例 : 如在工程中集成了第三方库 , 其提供了 arm, x86, mips 等指令集的动态库
            //        那么为了控制打包后的应用大小, 可以选择性打包一些库 , 此处就是进行该配置
            ndk{
                // 打包生成的 APK 文件指挥包含 ARM 指令集的动态库
                abiFilters "armeabi-v7a" /*, "arm64-v8a", "x86", "x86_64"*/
            }
    
        }
    
        // 配置 NDK 的编译脚本路径
        // 编译脚本有两种 ① CMakeList.txt ② Android1.mk
        //     defaultConfig 内部的 externalNativeBuild 配置的是配置 AS 工程的 C/C++ 源文件编译参数
        //     defaultConfig 外部的 externalNativeBuild 配置的是 CMakeList.txt 或 Android1.mk 构建脚本的路径
        externalNativeBuild {
    
            // 配置 CMake 构建脚本 CMakeLists.txt 脚本路径
            /*cmake {
                path "src/main/cpp/CMakeLists.txt"
                version "3.10.2"
            }*/
    
            // 配置 Android1.mk 构建脚本路径
            ndkBuild{
                path "src/main/ndkBuild_Shared/Android.mk"
                //path "src/main/ndkBuild_Static/Android.mk"
            }
        }
     	...
    }
    ...
    


    IV . 预编译 第三方 动态库 ( Android.mk )



    1 . 清除变量 : ( add 模块配置开始 )


    ① 作用 : 配置新的模块之前都要先清除 LOCAL_XXX 变量 ;

    ② 例外情况 : 有一个例外 , 就是不会清除 LOCAL_PATH 变量 ;

    ③ 模块开始标识 : include $(CLEAR_VARS) , 一般作为一个模块配置的起始标志 ;

    ④ 模块结尾 : include $(XXX_STATIC_LIBRARY) / include $(XXX_SHARED_LIBRARY) 一般作为模块配置结束标志 ;

    include $(CLEAR_VARS)
    

    2 . 配置动态库名称 :


    ① 自动生成函数库名称前提 : 没有 LOCAL_MODULE_FILENAME 配置 , 就会自动生成函数库名称 ;

    ② 动态库命名规则 : 在 LOCAL_MODULE 名称基础上 , 添加 lib 前缀 ( 如果前面有 lib 前缀不再添加 ) 和 .so 后缀 ;

    ③ 生成动态库名称 : libadd.so ;

    LOCAL_MODULE := add
    

    3 . 设置预编译的动态库路径 :

    LOCAL_SRC_FILES := libadd.so
    

    4 . 设置预编译动态库 : ( add 模块配置结束 )

    include $(PREBUILT_SHARED_LIBRARY)
    

    5 . 完整的第三方动态库预编译模块配置 :

    在这里插入图片描述

    # II . 预编译第三方动态库
    
    
    # 1 . 清除变量 ( add 模块配置开始 )
    #	① 作用 : 配置新的模块之前都要先清除 LOCAL_XXX 变量
    #	② 例外情况 : 但是不会清除 LOCAL_PATH 变量
    #	③ 模块开始 : include $(CLEAR_VARS)
    #  	④ 模块结尾 : include $(XXX_STATIC_LIBRARY) / include $(XXX_SHARED_LIBRARY)
    include $(CLEAR_VARS)
    
    # 2 . 配置动态库名称
    #	① 自动生成函数库名称前提 : 没有 LOCAL_MODULE_FILENAME 配置 , 就会自动生成函数库名称
    # 	② 动态库命名规则 : 在 LOCAL_MODULE 名称基础上 , 添加 lib 前缀和 .so 后缀
    # 	③ 生成动态库名称 : libadd.so
    LOCAL_MODULE := add
    
    # 3 . 预编译的动态库路径
    LOCAL_SRC_FILES := libadd.so
    
    # 4 . 设置预编译动态库 ( add 模块配置结束 )
    include $(PREBUILT_SHARED_LIBRARY)
    


    V . 链接动态库 ( 设置动态库依赖 )



    设置动态依赖库 :


    ① 依赖库 : 编译 native-lib 模块 , 需要链接 add 静态库 ;

    ② add 动态库 : add 模块是一个预编译库 , 预编译内容是引入的第三方动态库 ;

    LOCAL_SHARED_LIBRARIES := add
    

    在这里插入图片描述

    # IV . 配置动态库模块
    
    
    # 1 . 清除变量 ( native-lib 模块配置开始 )
    #	① 作用 : 配置新的模块之前都要先清除 LOCAL_XXX 变量
    #	② 例外情况 : 但是不会清除 LOCAL_PATH 变量
    include $(CLEAR_VARS)
    
    
    # 2 . 配置动态库名称
    #	① 自动生成函数库名称前提 : 没有 LOCAL_MODULE_FILENAME 配置 , 就会自动生成函数库名称
    # 	② 动态库命名规则 : 在 LOCAL_MODULE 名称基础上 , 添加 lib 前缀 和 .so 后缀
    # 	③ 生成动态库名称 : libnative-lib.so
    LOCAL_MODULE := native-lib
    
    
    # 3 . 编译的源文件
    LOCAL_SRC_FILES := native-lib.c
    
    # 4 . 设置动态依赖库
    #	① 依赖库 : 编译 native-lib 模块 , 需要链接 add 动态库
    #	② add 动态库 : add 模块是一个预编译库 , 预编译内容是引入的第三方动态库
    LOCAL_SHARED_LIBRARIES := add
    
    # 5 . 链接日志库
    LOCAL_LDLIBS := -llog
    
    # 6 . 设置预编译动态库 ( native-lib 模块配置结束 )
    include $(BUILD_SHARED_LIBRARY)
    


    VI . Java 代码定义 native 方法并加载动态库



    1 . 声明 并使用 native 方法 :

    public native String stringFromJNI();
    

    2 . 加载动态库 : 这里要加载两个动态库 ;

            System.loadLibrary("add");
            System.loadLibrary("native-lib");
    

    在这里插入图片描述



    VII . C 代码调用动态库函数



    1 . 声明动态库外部方法 :

    //声明 libadd.so 动态库中的方法
    extern int add(int a, int b);
    

    2 . 调用动态库的方法 :

    //调用动态库中的函数
    int sum = add(1, 2);
    

    在这里插入图片描述



    VIII . 动态库加载版本限制 ( 6.0 以上 不能使用 Android.mk 配置动态库 )



    1 . 问题描述 :

    6.0 版本开始 , 使用 Android.mk 构建脚本预编译第三方的动态库 , 如果程序中使用 System.loadLibrary 加载该预编译库 , 就会报错 ;

    6.0 以下的手机版本 ( 不包括 6.0 版本 ) , System.loadLibrary 需要手动加载依赖的动态库 ;

    6.0 及以上的手机版本 , System.loadLibrary 会自动加载依赖的动态库 , 此时不能加载依赖的动态库 , 否则会出错 ;


    2 . 报错信息 : 6.0 以上的手机 不能使用 Android.mk 加载动态库 , 一旦加载崩溃 ; 报以下错误 ;

    2020-02-13 01:58:38.044 23033-23033/kim.hsl.mk E/AndroidRuntime: FATAL EXCEPTION: main
        Process: kim.hsl.mk, PID: 23033
        java.lang.UnsatisfiedLinkError: dlopen failed: library "Y:/002_WorkSpace/001_AS/006_NDK_Android_mk/app/build/intermediates/ndkBuild/debug/obj/local/armeabi-v7a/libadd.so" not found
            at java.lang.Runtime.loadLibrary0(Runtime.java:977)
            at java.lang.System.loadLibrary(System.java:1567)
            at kim.hsl.mk.MainActivity.<clinit>(MainActivity.java:19)
            ...
    

    3 . 解决方案 : 6.0 以上的手机 , 只能使用 CMake 配置动态库 , 或者使用静态库 ;


    4 . CMake 配置方案参考 : 【Android NDK 开发】NDK 交叉编译 ( Ubuntu 中交叉编译动态库 | Android Studio 中配置使用第三方动态库 )



    IX . 完整代码示例





    1 . build.gradle 配置示例


    apply plugin: 'com.android.application'
    
    android {
        compileSdkVersion 29
        buildToolsVersion "29.0.0"
        defaultConfig {
            applicationId "kim.hsl.mk"
            minSdkVersion 15
            targetSdkVersion 29
            versionCode 1
            versionName "1.0"
            testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    
            // 配置 AS 工程中的 C/C++ 源文件的编译
            //     defaultConfig 内部的 externalNativeBuild 配置的是配置 AS 工程的 C/C++ 源文件编译参数
            //     defaultConfig 外部的 externalNativeBuild 配置的是 CMakeList.txt 或 Android1.mk 构建脚本的路径
            externalNativeBuild {
                /*cmake {
                    cppFlags ""
    
                    //配置编译 C/C++ 源文件为哪几个 CPU 指令集的函数库 (arm , x86 等)
                    abiFilters "armeabi-v7a"
                }*/
                ndkBuild{
                    abiFilters "armeabi-v7a" /*, "arm64-v8a", "x86", "x86_64"*/
                }
            }
    
            //配置 APK 打包 哪些动态库
            //  示例 : 如在工程中集成了第三方库 , 其提供了 arm, x86, mips 等指令集的动态库
            //        那么为了控制打包后的应用大小, 可以选择性打包一些库 , 此处就是进行该配置
            ndk{
                // 打包生成的 APK 文件指挥包含 ARM 指令集的动态库
                abiFilters "armeabi-v7a" /*, "arm64-v8a", "x86", "x86_64"*/
            }
    
        }
    
        // 配置 NDK 的编译脚本路径
        // 编译脚本有两种 ① CMakeList.txt ② Android1.mk
        //     defaultConfig 内部的 externalNativeBuild 配置的是配置 AS 工程的 C/C++ 源文件编译参数
        //     defaultConfig 外部的 externalNativeBuild 配置的是 CMakeList.txt 或 Android1.mk 构建脚本的路径
        externalNativeBuild {
    
            // 配置 CMake 构建脚本 CMakeLists.txt 脚本路径
            /*cmake {
                path "src/main/cpp/CMakeLists.txt"
                version "3.10.2"
            }*/
    
            // 配置 Android1.mk 构建脚本路径
            ndkBuild{
                path "src/main/ndkBuild_Shared/Android.mk"
                //path "src/main/ndkBuild_Static/Android.mk"
            }
        }
    
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            }
        }
    }
    
    dependencies {
        implementation fileTree(dir: 'libs', include: ['*.jar'])
        implementation 'androidx.appcompat:appcompat:1.1.0'
        implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
        testImplementation 'junit:junit:4.12'
        androidTestImplementation 'androidx.test:runner:1.2.0'
        androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    }
    
    


    2 . Android.mk 配置示例


    # I . 保存构建脚本的路径 , 并赋值给 LOCAL_PATH 变量
    
    
    #   ① 内置函数 : my-dir 是 NDK 内置的函数 , 获取当前的目录路径
    #	在该案例中就是 Android.mk 文件所在的目录的绝对路径 , 工程根目录/app/src/main/cpp
    #	将该目录赋值给 LOCAL_PATH 变量
    #	所有的 Android1.mk 的第一行配置都是该语句
    
    LOCAL_PATH := $(call my-dir)
    
    
    
    # II . 预编译第三方动态库
    
    
    # 1 . 清除变量 ( add 模块配置开始 )
    #	① 作用 : 配置新的模块之前都要先清除 LOCAL_XXX 变量
    #	② 例外情况 : 但是不会清除 LOCAL_PATH 变量
    #	③ 模块开始 : include $(CLEAR_VARS)
    #  	④ 模块结尾 : include $(XXX_STATIC_LIBRARY) / include $(XXX_SHARED_LIBRARY)
    include $(CLEAR_VARS)
    
    # 2 . 配置动态库名称
    #	① 自动生成函数库名称前提 : 没有 LOCAL_MODULE_FILENAME 配置 , 就会自动生成函数库名称
    # 	② 动态库命名规则 : 在 LOCAL_MODULE 名称基础上 , 添加 lib 前缀 和 .so 后缀
    # 	③ 生成动态库名称 : libadd.so
    LOCAL_MODULE := add
    
    # 3 . 预编译的动态库路径
    LOCAL_SRC_FILES := libadd.so
    
    # 4 . 设置预编译动态库 ( add 模块配置结束 )
    include $(PREBUILT_SHARED_LIBRARY)
    
    
    
    # III . 打印变量值
    
    
    # 打印 LOCAL_PATH 值
    # Build 打印内容 : LOCAL_PATH : Y:/002_WorkSpace/001_AS/005_NDK_Compile/app/src/main/cpp
    # 编译 APK 时会在 Build 中打印
    $(info LOCAL_PATH : $(LOCAL_PATH))
    
    
    
    # IV . 配置动态库模块
    
    
    # 1 . 清除变量 ( native-lib 模块配置开始 )
    #	① 作用 : 配置新的模块之前都要先清除 LOCAL_XXX 变量
    #	② 例外情况 : 但是不会清除 LOCAL_PATH 变量
    include $(CLEAR_VARS)
    
    
    # 2 . 配置动态库名称
    #	① 自动生成函数库名称前提 : 没有 LOCAL_MODULE_FILENAME 配置 , 就会自动生成函数库名称
    # 	② 动态库命名规则 : 在 LOCAL_MODULE 名称基础上 , 添加 lib 前缀 和 .so 后缀
    # 	③ 生成动态库名称 : libnative-lib.so
    LOCAL_MODULE := native-lib
    
    
    # 3 . 编译的源文件
    LOCAL_SRC_FILES := native-lib.c
    
    # 4 . 设置静态依赖库
    #	① 依赖库 : 编译 native-lib 模块 , 需要链接 add 静态库
    #	② add 静态库 : add 模块是一个预编译库 , 预编译内容是引入的第三方动态库
    LOCAL_SHARED_LIBRARIES := add
    
    # 5 . 链接日志库
    LOCAL_LDLIBS := -llog
    
    # 6 . 设置预编译动态库 ( native-lib 模块配置结束 )
    include $(BUILD_SHARED_LIBRARY)
    
    
    
    # V . 配置动态库与静态库区别
    
    
    #	1 . 预编译时的路径不一致 :
    #		① 动态库路径 : libadd.so
    #		② 静态库路径 : libadd.a
    
    #	2 . 预编译时结束配置不一致 :
    #		① 动态库配置 : include $(PREBUILT_SHARED_LIBRARY)
    #		② 静态库配置 : include $(PREBUILT_STATIC_LIBRARY)
    
    #	3 . 链接依赖库时配置不一致 :
    #		① 动态库依赖配置 : LOCAL_SHARED_LIBRARIES
    #		② 静态库依赖配置 : LOCAL_STATIC_LIBRARIES
    


    3 . Java 代码示例


    package kim.hsl.mk;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    import android.os.Bundle;
    import android.widget.TextView;
    
    public class MainActivity extends AppCompatActivity {
    
        static {
    
            // 1 . 加载动态库的情况 : ( 必须不能注释下面的代码 )
            //      ① 6.0 以下的版本 : 需要手动加载依赖库 libadd.so
            //      ② 6.0 以上的版本 : 无法使用 Android.mk 构建脚本加载第三方动态库
            //                         此情况下, 无论是否手动加载 libadd.so 都会报错
            //
            // 2 . 加载静态库的情况 : ( 必须注释掉下面的这行代码 )
            System.loadLibrary("add");
    
            System.loadLibrary("native-lib");
        }
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            TextView tv = findViewById(R.id.sample_text);
            tv.setText(stringFromJNI());
        }
    
        public native String stringFromJNI();
    }
    
    


    4 . C 代码示例


    #include <jni.h>
    
    #include <stdio.h>
    #include <stdlib.h>
    
    #include <android/log.h>
    
    
    //调用 libadd.so 动态库中的方法
    extern int add(int a, int b);
    
    JNIEXPORT jstring JNICALL
    Java_kim_hsl_mk_MainActivity_stringFromJNI(
            JNIEnv *env,
            jobject obj) {
    
        //调用动态库中的函数
        int sum = add(1, 2);
    
        // Logcat 打印计算结果
        __android_log_print(ANDROID_LOG_INFO, "JNI_TAG", "Native Caculate : %d + %d = %d", 1, 2, sum);
    
        //将加法运算转为字符串
        char str[50] = "0";
        //字符串格式化
        sprintf(str, "Native Caculate : Static Library : %d + %d = %d", 1, 2, sum);
    
        return (*env)->NewStringUTF(env, str);
    }
    
    


    5 . 运行结果 ( Android 4.3 手机 | 6.0 以上系统无法运行 )


    在这里插入图片描述



    X . 博客资源



    CSDN 博客地址 : 【Android NDK 开发】Android.mk 配置动态库 ( Android Studio 配置动态库 | 动态库加载版本限制 | 本章仅做参考推荐使用 CMake 配置动态库 )

    博客资源下载地址 : https://download.csdn.net/download/han1202012/12157107

    示例代码 GitHub 地址 : https://github.com/han1202012/006_NDK_Android_mk

    展开全文
  • 在函数外的其他任何地方都不能使用变量。自动变量是局部变量,即它的区域性是在定义他的函数内部有效。当然这说明自动变量也没有链接性,因为它也不允许其他的文件访问他。由于自动变量在定义他的函数的外面的任何...
  • 此时,很显然so只被加载了一份,那么,当这么多程序在运行调用该so时,该so中的全局变量的值会被覆盖来覆盖去么? 答案是不会。这是测试的答案。 现在知道原理了,尽管这是windows via C/C++中解
  • 最近看代码,发现一个在动态库中在全局变量A,我在动态库外部extern引用的时候总是提示undefined错误。首先确认在引用同一个动态库中的API函数B没有问题。首先看来下动态库中,readelf命令导出文件的信息,发现:1....
  • C++静态库与动态库详解与使用

    千次阅读 2016-09-30 09:07:40
    这次分享的宗旨是——让大家学会创建与使用静态库、动态库,知道静态库与动态库的区别,知道使用的时候如何选择。这里不深入介绍静态库、动态库的底层格式,内存布局等,有兴趣的同学,推荐一本书《程序员的自我修养...
  • 动态链接的全局变量与多线程

    千次阅读 2018-09-30 16:48:16
    最近对多线程调用时,动态链接的全局变量有了以下几点认识。 1、动态链接被同一进程的多个线程加载时,全局变量的值是进程有效。  例如:动态链接C.dll有一个全局变量 int g_iCount=0(初始值)。某一函数...
  • 使用第三方提供的,我们需要: 一、设置环境变量: 环境变量是属于操作系统的,而不是某个具体编译器的,环境变量的设置是全局有效的 以win xp系统系统为例:我的电脑——右键——属性——高级 点开环境变量: ...
  • cmake之链接外部动态库

    千次阅读 2016-05-30 11:40:54
    有两种方式,一种是cmake自己内置的find_package,另一种是使用pkg-config。
  • Linux下gcc生成和使用静态库和动态库详解

    万次阅读 多人点赞 2016-05-31 17:54:25
    Linux下gcc生成和使用静态库和动态库详解(原文链接) 本文在原文的基础上做一些详细验证,部分稍有改动, 一、基本概念 1.1什么是库 1.2库的种类 1.3库存在的意义 1.4库文件是如何产生的在linux下 1.5库文件...
  • java使用jna调用动态库踩的坑

    千次阅读 2019-07-19 23:44:51
    回顾去年项目需求上需要使用算法封装好的动态库,楼楼使用的是jna调取动态库。开发过程中,就是一个爬坑之旅,在此记录下爬过的坑。 1.位数问题 使用jna需要关注到动态库位数,服务器系统位数,为此选定合适的jdk。...
  • 基本内容概述 最近做项目时经常看到build.cs文件,就想研究一下UE4中第三方使用。通过网络以及wiki确实获取到不少有用的信息,但是没有一篇文章,让我看完就立刻明白的。所以,我在这里详细的描述dll与lib在UE4...
  • 因为新工程中静态库动态库非常多,非常不利于分析问题。 再因为并不是一个业务逻辑问题,而是一个语言层面的问题,所以我单独抽象出产生问题的环境,简化问题,更容易分析。 刚开始,是一个方案,五个工程,能够...
  • gcc 编译工具(下)— 外部库、共享库、静态库、动态库1. 头文件与库文件 在使用C语言和其他语言进行程序设计时,需要头文件来提供对常数的定义和对系统及函数调用的声明。 库文件是一些预先编译好的函数集合,那些...
  • Windows下使用静态库和动态库

    万次阅读 2016-05-10 23:26:39
    Windows下使用静态库和动态库
  • 这两天由于想要研究一下socket的相关内容,但是没想到引入外部库还有这么多门道。 根据维基百科定义:一个现代编译器的主要工作流程如下:源代码(source code)→ 预处理器(preprocessor)→ 编译器(compiler)→...
  • c语言中存在静态库(.a)和动态库(.so)。 静态库实际上是一些目标文件的集合,只用于链接生成可执行文件阶段。链接器会将程序中使用到函数的代码从库文件中拷贝到应用程序中,一旦链接完成生成可执行文件之后,在执行...
  • 动态库def文件的使用

    万次阅读 2018-03-04 13:24:41
    DLL中导出函数的声明有两种方式:一种为在函数声明中加上__declspec(dllexport),这里不再举例说明;另外一种方式是采用模块定义(.def) 文件声明,.def文件为链接器提供了有关被...) 指定,且注释不与语句共享一行。
  • C++又一坑:动态链接中的全局变量

    千次阅读 2017-03-20 22:12:27
     前几天我们项目的日志系统出现了一点...模块 a, 静态 a模块 b, 二进制 b, 静态引用a, 动态加载c模块 c, 动态链接c, 静态引用a 关键在于静态a里有一个静态全局变量,没错就是我们的日志模块。 原先的这个
  • 我做了一个动态链接,其中有一个导出类 CAdoReadData ,类中有一个静态成员变量 static int m_Code_End,动态链接编译通过后,在另外一个程序中调用,则出现了如下错误: 1>MainFrm.obj : error LNK2001: ...
  • 多进程引用的动态链接中的全局变量问题现有liba.so中定义一个全局变量char buf; libb.so 中的函数print会将buf进行输出。 进程A和进程B使用-lb进行编译链接,并在进程A和B中分别对buf进行初始化,如strcpy(buf,...
  • 1,建立一个静态库和动态库,提供HelloFunc函数供其他程序编程使用,HelloFunc 向终端输出Hello World字符串。 2,安装头文件与共享库。 3, 编写一个程序使用创建的共享库(静态库和动态库)。   cd /home/...
  • linux下生成动态链接使用使用cmake)

    万次阅读 多人点赞 2017-04-01 11:04:44
    使用cmake**生成**主要要注意三个文件夹 (1)源文件文件夹 (2)中间文件夹(编译生成的.o等...(2)在CMakeLists.txt或集成开发环境中指定库函数的动态链接或者静态链接所在的文件夹路径 (3)在CMake
  • C++静态库与动态库

    千次阅读 2016-10-20 09:50:56
    这次分享的宗旨是——让大家学会创建与使用静态库、动态库,知道静态库与动态库的区别,知道使用的时候如何选择。这里不深入介绍静态库、动态库的底层格式,内存布局等,有兴趣的同学,推荐一本书《程序员的自我修养...
  • 一、基本概念1.1什么是库在windows平台和linux平台下都大量存在着库。本质上来说库是一种可执行代码的二进制... 1.2库的种类linux下的库有两种:静态库和共享库(动态库)。二者的不同点在于代码被载入的时刻不同。静
  • gcc使用静态库和动态库

    千次阅读 2010-12-22 18:16:00
    函数库分为静态库和动态库两 种。静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库。动态 库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运 行时还需要...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 115,571
精华内容 46,228
关键字:

动态库能使用外部变量吗