Linux操作系统关于动静态库的操作

一、动静态库的基本介绍

在Linux操作系统中静态库文件是以 .a 作为后缀的,动态库以 .so 作为后缀。

  • 静态库(.a):静态库的代码是在程序编译链接的时候就被链接到可执行文件当中的,在程序运行的时候就不需要静态库代码了。
  • 动态库(.so):动态库的代码是程序运行的时候才去链接的,多个程序可以共享使用动态库的代码。
  • 一个动态库链接的可执行文件只包含这个可执行文件用到的动态库内函数入口地址的一个表,而不是该函数所在目标文件的整个机器码。也就是说,当可执行文件用到动态库的某个函数时,链接到可执行文件当中的只有这些函数入口的地址,并没有这些函数的具体实现方法。
  • 动态链接是指在可执行文件运行之前,操作系统就会将该可执行文件运用到的动态库函数的具体实现代码从磁盘加载到内存里。
  • 静态链接是在可执行文件编译链接时就将静态库拷贝到可执行文件当中。
  • 动静态库的命名方式为 lib + 库名 + 后缀 ,例如libxxx.a表示静态库,libxxx.so表示动态库。

二、静态库

1.生成静态库

在写C++的STL模拟实现的时候,我们经常会定义三个文件,一个(.h)头文件用来放类和函数的声明,一个(.cpp)源文件来放函数的定义,一个(.cpp)文件来写main函数做测试或者使用类。我们可以举一个简单的例子来看一下平时我们是怎么做的。

创建mymath.h头文件用来声明addToVal函数:

在这里插入图片描述


创建mymath.c文件用来写addToVal函数的具体实现方法:

在这里插入图片描述


创建test.c文件写main函数,测试addToVal函数:

在这里插入图片描述


然后我们创建makefile文件,平常我们就是用这种方式来生成可执行文件的:

在这里插入图片描述

在这里插入图片描述

我们现在不想像以前那样生成可执行文件了,我们想要把头文件和源文件打包成一个静态库,我们在原有的mymath.h头文件和mymath.c源文件基础上,再增加myprint.h和myprint.c文件,把这四个文件打包成一个静态库。
首先我们要将(.c)源文件变成 .o 文件,输入指令gcc -c mymath.cgcc -c myprint.c,生成了对应的 .o 文件。

在这里插入图片描述

链接就是将所有的 .o 文件链接形成一个可执行程序。如果我们不打包,直接将所有的 .o 文件给别人,别人也可以用来生成可执行程序,例如:我们创建一个mytest.c文件作为测试代码调用myprint.h的函数,然后输入指令gcc -c mytest.c先生成自己的 .o 文件,然后输入指令gcc mymath.o myprint.o mytest.o,就可以生成一个可执行程序。

在这里插入图片描述

因此在链接的时候,其实就是将上面的所有 .o 文件合起来,拷贝到一起形成最后的可执行程序,这也就是所谓的静态链接。但是有个问题是,如果我们的 .o 文件有很多,我们每次生成可执行程序都要讲所有的 .o 文件写出来,这样会非常麻烦。所以我们要将 .o 文件进行打包形成静态库,就可以解决这个问题了。

打包成静态库我们需要用到 ar -rc命令。例如我们在makefile文件中生成静态库,使用指令ar -rc libmymath.a mymath.o myprint.o

在这里插入图片描述

我们可以使用make指令生成一下,我们会发现目录中出现了(.a)静态库和所有的(.o)文件,至此我们就完成了静态库的打包操作。

在这里插入图片描述

2.发布静态库

我们生成了静态库要怎么发布出去给别人能够使用呢?我们在使用一个库的时候,必须拥有该库的库文件以及头文件,其中库文件就是我们刚刚生成的(.a)静态库文件,头文件就是后缀为 .h 的文件,我们可以将这两种文件复制到一个目录下,最后将这个目录发布出去就可以了。

我们在makefile文件里再添加一个static_ouput的伪目标,表示静态库的发布命令,执行该命令的时候就会创建lib_static目录以及该目录下的lib目录和include目录,然后将所有的 .a 文件复制到lib目录下,将所有的 .h 文件复制到include目录下。

在这里插入图片描述

输入指令make static_ouput查看结果:我们可以看到lib_static目录确实被创建出来了,有了这个目录别人就可以使用我们打包好的静态库了。

在这里插入图片描述

4.使用静态库

当我们使用别人制作好的静态库时,我们拿到静态库,要在代码中使用,首先要拿到该静态库的头文件,引入相应的头文件即可。编译器寻找头文件的方式有两种:

  1. 在当前路径下寻找头文件。
  2. 在系统库文件路径下寻找头文件。

Linux系统库文件的头文件路径在usr/include,系统的下载好的库文件一般存放在/lib64/这个路径下。而当我们将打包好的静态库的目录放到当前目录下时,我们需要的头文件并不在当前目录下,而是在lib_static/include路径下。

在这里插入图片描述

(1)带路径的头文件

所以我们创建的mytest.c文件想要使用静态库时,需要带上路径包头文件:

在这里插入图片描述

但是这种方法太麻烦了,写头文件的时候带的路径太长了,我们希望用简单方便一点的方法。

(2)将库文件和头文件拷贝到系统路径下

第一种简单粗暴的方法就是:将静态库的头文件和库文件拷贝到对应的系统路径中去。

输入指令sudo cp lib_static/include/* /usr/include/将库的头文件拷贝到系统库的头文件路径下,输入指令sudo cp -rf lib_static/lib/* /lib64/将库文件拷贝到系统库文件路径下。然后我们就可以在mytest.c里不带路径地包头文件,我们再输入指令gcc mytest.c生成可执行程序。

但是我们却发现依旧是无法生成可执行程序,只不过现在报错就不再是找不到头文件了,而是出现了链接错误,找不到函数。这是因为gcc或者g++编译器默认会链接C/C++语言的库文件,但我们这种第三方库gcc和g++编译器是不认识的。

在这里插入图片描述

所以我们在编译的时候需要加上-l库文件名这个选项,库文件名就是去掉前缀lib和去掉后缀剩下的部分,例如我们的库文件,输入指令gcc mytest.c -lmymath。这样我们就可以生成可执行程序了。

在这里插入图片描述

我们上述的将库文件和头文件拷贝到系统路径下的做法就叫作库的安装。

(3)指定头文件和库文件的搜索路径

既然我们是gcc或者g++编译器去寻找头文件的,那么编译器还提供了可以指定头文件搜索路径的选项。这个选项是-I 头文件的搜索路径,或者是-I头文件的搜索路径(意思就是-I后面可以带空格也可以不带)。这样就可以手动地指定头文件的搜索路径。

头文件搜索路径指定了以后,还需要告诉编译器库文件的路径,否则会有链接错误。所以还需要使用选项-L 库文件搜索路径,这样就可以指定库文件的搜索路径。

最后,我们还需要告诉编译器在库文件的搜索路径下需要链接哪一个库文件(因为可能存在多个库文件在同一路径下的情况),所以使用选项-l库文件名,即可链接库文件。

输入指令gcc mytest.c -I ./lib_static/include/ -L ./lib_static/lib/ -lmymath即可生成可执行文件。

在这里插入图片描述

三、动态库

1.生成动态库

动态库和静态库一样也是要先形成 .o 文件,但是动态库需要形成与位置无关的 ** .o** 文件,所以需要加上-fPIC选项,输入指令gcc -fPIC -c mymath.c -o mymath.ogcc -fPIC -c myprint.c -o myprint.o生成 .o 文件,然后输入指令gcc -shared -o libmymath.so mymath.o myprint.o将所有的 .o 文件打包。

在这里插入图片描述

2.发布动态库

发布动态库和静态库的操作方法是一样的:

在这里插入图片描述

3.使用动态库

使用动态库的方法和静态库一样,要么是使用带路径的头文件,要么是将库文件和头文件拷贝到系统路径下,要么是指定头文件和库文件的搜索路径。前两种方法都不太经常使用,下面演示一下第三种方法。输入指令:gcc mytest.c -I ./dyl/include/ -L ./dyl/lib/ -lmymath,即可生成可执行文件。

在这里插入图片描述

虽然是生成了可执行文件,但是与静态库不同的是,我们直接运行这个可执行文件会报错。它报错的是动态库文件没有找到。

在这里插入图片描述

我们再输入指令ldd a.out查看程序依赖的动态库文件,发现我们自己写的库文件没有被找到。

在这里插入图片描述
这是因为我们前面gcc带的选项让编译器找到了库头文件和库文件的搜索路径从而生成了可执行程序,但是动态链接不像静态链接那样在编译器链接的时候就已经将代码拷贝进了可执行文件当中,而是在程序运行的时候也要依赖动态库,所以我们还需要让可执行程序在运行的时候能够找到我们的动态库。当然如果我们直接将库安装到系统路径下,这些问题都可以解决。如果不安装到系统路径下,可以使用下面这几种方法:

(1)导入环境变量

我们输入指令echo $LD_LIBRARY_PATH查看这个环境变量:

在这里插入图片描述
然后我们将我们库文件路径导入进去,注意要使用绝对路径,并且只需要导入库文件的路径,不用导入头文件的路径。

  1. 输入指令export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/hkx/study23.01.17/linux_blog/mklib/test/dyl/lib
  2. 导入进去之后再输入指令echo $LD_LIBRARY_PATH查看这个环境变量:环境变量导入成功。

在这里插入图片描述
最后再运行可执行程序,此时就可以成功地运行了。但是这种方法有一个不好的点就是,当我们关闭xshell,再次进入的时候,环境变量又被清空了。

在这里插入图片描述

(2)添加系统配置文件

Linux操作系统下有一个路径是存放配置文件的,输入指令ls /etc/ld.so.conf.d/可以查看一下这个路径下的配置文件:

在这里插入图片描述

我们要做的也是非常简单,在系统的这个路径下创建一个配置文件,配置文件里写上我们动态库的库文件存在路径即可。

  1. 输入指令sudo touch /etc/ld.so.conf.d/mymath.conf创建一个我们自己的配置文件
  2. 输入指令sudo vim /etc/ld.so.conf.d/mymath.conf编辑我们的配置文件,将我们的库文件路径写到配置文件中
  3. 最后输入指令sudo ldconfig让我们的配置文件生效即可

此时,我们可以输入指令ldd a.out查看一下我们的可执行文件依赖的库文件:现在就可以找到库文件的路径了。

在这里插入图片描述
最后运行程序,可以成功运行了。

在这里插入图片描述

(3)在系统库文件路径下建立软链接

如果前面两种方法都觉得特别复杂,可以尝试一下第三种方法。我们在lib64路径下建立一个软链接,链接上我们写的库文件的路径即可。输入指令sudo ln -s /home/hkx/study23.01.17/linux_blog/mklib/test/dyl/lib/libmymath.so /lib64/libmymath.so即可创建软链接。这样也可以正常运行可执行程序。

四、一个makefile文件一次生成多个目标文件

这个是非常常用到的,我们要定义一个伪目标为all,将我们想要同时生成的目标文件写在一起即可,例如我们想要一次性生成一个动态库和一个静态库,就可以将makefile文件改写成下面的样子:

在这里插入图片描述

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值