Linux环境下创建并使用动静态库(动态链接与静态链接)

假设要通过printf函数打印“hello,world”,程序开始运行后,经过预处理、编译、汇编等过程,在链接阶段需要调用printf函数,那么就会去C语言库里找printf函数

Windows环境下,链接找的是 .lib 文件,运行找的是 .dll 文件;Linux环境下,链接和运行默认找的都是 .so 文件(可以调整)


目录

一、动态库和静态库的区别

1、静态库(静态链接)

2、动态库(动态链接)

二、创建静态库

1、生成 .o 文件

2、创建静态库(ar命令)

3、使用静态库

三、创建动态库

1、创建 .o 文件

2、创建动态库( gcc -shared )

3、使用动态库

4、查看执行文件依赖的动态库


一、动态库和静态库的区别

库是一个二进制文件,包含的代码可以被程序调用,如标准库、线程库。Windows 和 Linux下的库文件格式不兼容。

  • Windows环境:静态库是 .lib 文件,共享库是 .dll 文件
  • Linux环境:静态库是 .a 文件,共享库是 .so 文件(一般放在 /lib 或者 /usr/lib 目录下)

1、静态库(静态链接)

之所以称为静态库,是因为在链接阶段,把要用到的第三方库的代码加入到目标可执行文件中,这样的话,该可执行文件在运行时就无需去找库文件了。

可执行文件链接静态库的方式,称为静态链接。正是因为如此,这个时候的可执行文件会比较大。

静态库命令规则以 lib 作为前缀,以 .a作为后缀。如 libxxx.a

优点:程序中已经包含了代码,运行时不需要再加载静态库,运行速度更快

缺点:占用更多的磁盘空间,静态库升级以后,程序需要重新编译链接。

 

2、动态库(动态链接)

在编译链接时不会把要用到的库文件代码加入到可执行文件中,而是在链接阶段需要用到的时候,去找到对应的库,然后再调用库里的函数。和静态库不同,动态库中保存的是偏移位置,在要用的时候,根据偏移量找到对应的文件。

可执行文件链接动态库的方式,称为动态链接。避免了空间浪费,需要更新库的时候,无需更新执行文件。

动态库以 lib 作为前缀,以 .so作为后缀。如 libxxx.so

  • 程序不会包含库中代码,尺寸小
  • 多个程序可共享一个库
  • 库升级方便。无需重新编译程序

二、创建静态库

一个完整的库包含 库文件本身头文件说明文档,现在我们仅需要关注前两者。一般制作动静态库只需要让程序进行到汇编阶段即可,即生成 .o 文件就可以停下来了。因为到了链接阶段,编译器就会去执行 main 函数的内容,制作库的时候没有这个东西。

制作动静态库的本质:就是将所有的.o文件打包。——》使用ar或者gcc打包

1、生成 .o 文件

现在我们已经在一个目录下创建好了生成 .o 文件所需的依赖

我们在命令行输入 gcc -o hello.o -c hello.c

2、创建静态库(ar命令)

(1) ar 命令

一般通过 ar 命令来创建静态库, ar命令的选项解析如下:

选项含义
-c禁止在创建库时产生正常消息
-r如果指定的文件已经存在于库中,则替换它
-s无论 ar 命令是否修改了库文件内容,都强制重新生成库符号表
-v将建立新库的逐个文件的描述输出到标准输出(将生成新库过程中每个文件做了啥打印到终端)
-q将指定文件添加到库文件的末尾
-t将库的目录写至标准输出

(2) 使用 ar 命令生成静态库 

创建静态库时,使用上面的 -rsv 三个选项即可,创建静态库的命令如下:

# 静态库必须以 lib 为前缀,文件拓展名为 .a
ar -rsv libhello.a hello.o

3、使用静态库

假设我们在myTest.c中使用的了上述静态库中的函数,那么在使用 gcc 命令生成执行文件的时候就需要告诉编译器静态库在哪个目录下,静态库叫什么

在命令行输入如下命令:

# -L 表示添加库的搜索路径,. 代表当前目录
# -l 注意是小写的L,代表库的名称
    # 静态库的真正名称 = libhello.a 去掉前缀 lib 和 后缀 .a 
gcc -o myTest myTest.c -L. -lhello

三、创建动态库

编译器在链接动态库的时候,是去指定目录下寻找的,可执行文件因为不包含库中代码,所以在编译的时候即便是指定了搜索目录也没有意义。

1、创建 .o 文件

我们移除之前的静态库,依然使用之前的 hello.c 来生成目标文件

我们在命令行输入 gcc -fPIC -o hello.o -c hello.c  。如果 hello.c 用到了其他 .c文件,比如add.c、sub.c,相关文件也需要生成目标文件。

gcc -fPIC -o add.o -c add.c
gcc -fPIC -o sub.o -c sub.c
gcc -fPIC -o hello.o -c hello.c

注意:这里新增了 -fPIC 选项,实际上改变的是 hello.o 的符号表,我们可以使用 nm 命令查看hello.o的符号表,多出了一个全局偏移表,没有这个偏移表是无法动态编译的。

2、创建动态库( gcc -shared )

创建动态库使用的命令是

# gcc -shared -o libxxx.so xxx.o xxx.o ... 
gcc -shared -o libhello.so hello.o add.o sub.o

3、使用动态库

(1)使用动态库可能存在的问题

在链接阶段就会去找对应的动态库,但是此时即便我们添加了搜索路径也依然找不到动态库。

这是因为编译器只会去库目录环境变量中找动态库,Linux环境下的库文件一般都放在 /lib 或者 /usr/lib 目录下,所以如果我们要让程序能找到动态库,可以使用接下来说的两种方法。

(2)  让程序找到共享库的方法

方法一:将生成的动态库拷贝到 /usr/lib 或者 /lib 目录下(不推荐)

这种方法不大推荐,因为会污染系统库源

linux@linux:~/Templates/staticLib$ sudo cp libhello.so /usr/lib/
linux@linux:~/Templates/staticLib$ ./myTest 
hello. world!

方法二:修改环境变量 LD_LIBRARY_PATH

环境变量 LD_LIBRARY_PATH是动态库的搜索路径,一般情况下为空,可执行文件运行时,会去这个环境变量中搜索动态库路径

linux@linux:~/Templates/staticLib$ export LD_LIBRARY_PATH=./
linux@linux:~/Templates/staticLib$ ./myTest 
hello. world!

注意:第二种方法仅仅只是在当前 Shell 环境下有效,如果新开一个终端,相当于创建了一个新的Shell环境,该环境下的环境变量LD_LIBRARY_PATH是空的。

4、查看执行文件依赖的动态库

ldd 命令可以查看当前执行文件所链接的动态库

拓展:

还可以加 -r 选项查看更加详细的连接信息,有的时候可以通过这种方法发现库的隐藏问题

 如果发现了问题,可以输入 c++filt 符号名 来确定到底是哪个文件出现了问题,这里的符号名指的是_ZN10vacTestAcc16vacTestSampEnAccEPdiPKc

  • 5
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值