动态链接与静态链接

3 篇文章 0 订阅

静态库

Linux下的静态库通常以.a为后缀,用于创建.a的工具为ar(archive的缩写).静态库链接后会将所有数据会添加到调用程序, 因此使用静态库的程序体积可能较大,但是使用静态库的程序不需要外部依赖项.

举例

以hello.cpp、hello.h为例

  1. 生成目标文件
    g++ -c hell.c -o hello.o
  2. 生成静态库
    ar -crv libhello.a hello.o

    • -r:在库中插入模块(替换)。当插入的模块名已经在库中存在,则替换同名的模块。

    • -c:创建一个库。不管库是否存在,都将创建。

    • -v:该选项用来显示执行操作选项的附加信息。

    • -d:从库中删除模块。按模块原来的文件名指定要删除的模块。如果使用了任选项v则列出被删除的每个模块。

  3. 链接静态库
    g++ -o output main.cpp -L${D_LIB} -lhello
    其中D_LIB为libhello.a的路径

动态库

程序运行所需要的库,其默认的搜索路径一般为LD_LIBRARY_PATH所指定的路径,然后是/etc/ld.so.cache,再然后是/lib/和/usr/lib/.

隐式链接(静态加载)

隐式链接在编译/链接阶段完成,由编译系统根据动态库的头文件和库文件进行编译和链接,从而确定待调用的函数原形和地址。

显示链接(动态链接)

动态链接则是利用API函数实现加载和卸载共享库,获取带调用函数地址,获取错误信息等功能。

Linux 下符号的动态链接默认采用Lazy Mode方式(RTLD_LAZY),也就是说在程序运行过程中用到该符号时才去解析它的地址。这样一种符号解析方式有一个好处:只解析那些用到的符号,而对那些不用的符号则永远不用解析,从而提高程序的执行效率。

关于动态链接:https://github.com/tinyclub/open-c-book/blob/master/zh/chapters/02-chapter4.markdown

显示链接与隐式链接区别

  • 隐式链接要求调用者写的代码量少,调用起来和使用当前项目下的函数一样直接
    显式调用则要求程序员在调用时,指明要加载的动态库的名称和要调用的函数名称
  • 隐式调用由系统加载完成,对程序员透明
    显式调用由程序员在需要使用时自己加载,不再使用时,自己负责卸载。
  • 由于显式调用由程序员负责加载和卸载,好比动态申请内存空间,需要时就申请,不用时立即释放,因此显式调用对内存的使用更加合理, 大型项目中应使用显示调用。

举例

以hello.cpp、hello.h为例

  1. 生成目标文件
    g++ -c hell.c -fPIC -o hello.o
    • -fPIC是编译选项,PIC是 Position Independent Code 的缩写,表示要生成位置无关的代码,这是动态库需要的特性;
  2. 生成动态库
    g++ hello.o -shared -o libhello.so
    • -shared是链接选项,告诉gcc生成动态库而不是可执行文件。如果要调试动态库,也需要这个选项。
  3. 隐式链接动态库
    g++ -o output main.cpp -L${D_LIB} -lhello -Wl,-rpath=${D_LIB}
    其中D_LIB为libhello.so的路径
    注意main.cpp中需要包含导出函数的头文件,如hello.h

    • -Wl:这个是gcc的参数,表示编译器将后面的参数传递给链接器ld。
    • -rpath:
      1. 添加一个文件夹作为运行时库的搜索路径。在将ELF可执行文件与共享对象链接时使用此选项;
      2. 在链接时,一些动态库明确的链接了其他动态库, 则-rpath选项也可用于定位这些链接的动态库(没太理解这个);
      3. 在运行链接时,会优先搜索-rpath的路径,再去搜索LD_RUN_PATH的路径。
  4. 显式链接动态库
    g++ -o output main.cpp -lhello -ldl
    调用方需要头文件dlfcn.h

    • -ld:dlopen之类的函数需要连接ld库
    • -rdynamic:用来通知链接器将所有符号添加到动态符号表中(目的是能够通过使用 dlopen 来实现向后跟踪)
      可以用objdump -T [filename]来查看动态符号表
显示调用动态链接中的类成员函数

隐式链接时,由于包含了头文件,可以直接new一个类对象,但显示链接不行。

显示链接如果需要调用类成员函数,定义一个带有虚成员的接口类,然后定义一个实现了其虚成员的衍生类,通过接口类返回衍射类的实例,通过多态调用类成员函数。

参考:http://ahageek.com/blog/linux-library-compile-and-use/index.html

动态库与静态库的区别

  • 静态库是编译时就加载到可执行文件中
    动态库是在程序运行时完成加载
  • 使用动态库的程序的体积要比使用静态库程序的体积小,并且使用动态库的程序在运行时必须依赖所使用的动态库文件(.so文件)
    使用静态库的程序一旦编译好,就不再需要依赖的静态库文件了(.a文件)。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值