Linux —— 动态库和静态库
目录
一、认识动静态库 静态库:程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库,在Linux中静态库是以(.a)为后缀;动态库:程序在运行的时候才去
目录 一、认识动静态库 静态库:程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库,在Linux中静态库是以(.a)为后缀;动态库:程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。在Linux中静态库是以(.so)为后缀;一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文件的整个机器码;在可执行文件开始运行以前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中,这个过程称为动态链接(dynamic linking);动态库可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘空间。操作系统采用虚 拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间; 我们可以通过 [ ldd 可执行程序文件名 ]来查看可执行程序所依赖的库。 其中 /lib64/libc.so.6 就是可执行程序的库文件,它其实是一个软链接。我们可以通过以下命令来查看
如何辨别它采用的是哪一种库呢? 1.我们可以通过后缀来区分(在Linux中) 在Linux中,以 .so结尾的后缀,是动态库;以 .a 结尾的是静态库 在Windows中,以 .dll结尾的后缀,是动态库;以 .lib 结尾的是静态库 注: 库文件的名字:libxxx.so 和libxxx.a 库的真实名字:去掉lib前缀,去掉 .a 、.so后缀,剩下的就是库的名称。 2.我们还可以通过file命令查看 上图中分别使用了动静态库对同一个文件进行编译的,通过file命名可以查看到所对应的链接信息,如果为安装静态库,是编译不通过的,具体安装教程可以点这里Linux——环境基础开发工具的使用 二、回顾编译链接的过程 在Linux中,gcc的编译可以分为一下四个步骤:
从以上四个阶段来看,我们要使用自己制作的库或者别人的库,一定是汇编完后产生的.o文件,我们只需要对这个.o文件进行链接就可以了; 三、库的制作和使用 库是一个二进制文件,想要使用库(给别人使用自己的制作的库或者使用别人的库)一定是由三个部分组成:库文件、头文件、文档说明;一般这个库文件就是函数的定义,头文件就是函数声明,我们只需要将这些打包好,别人使用我们头文件所给的接口就行。 编写如下四个文件:其中源文件包含add.c和sub.c,头文件包含add.h和sub.h;用来制作静态库并打包
1.静态库的制作 1.生成二进制(.o)文件 首先将上面的.c文件生成.o文件 2.打包 我们将生成好的.o文件进行打包:
ar命令是gnu的归档工具,常用于将目标文件打包为静态库,下面我们使用ar命令的-r 选项和-c选项进行打包。 我们可以用ar命令的-t选项和-v选项查看静态库当中的文件。 3.发布静态库 静态库要发布出去供别人使用,只要库文件(所有的.o文件)是不够的,我们需要将其和头文件一起发布出去,别人只要看到头文件,就大致了解如何使用了 当然,我们也可以直接编写Makefile,就不需要我们一步一步的完成静态库的打包及发布 2.静态库的使用 方法一 上文中,我们已经有了静态库output了,别人该如何使用呢? 例如:想要在friend文件下使用这个库: 现在在friend目录下有一个mytest.c文件和一个静态库文件lib,mytest.c想要使用lib,我们先编写一下mytest.c代码:
进行编译: 编译后,报警告:没有头文件,可是明明在lib文件下有我们要的有文件以及库文件,这是为什么呢? 其实,编译器在编译的时候,会在当前的目录的文件中去找,不会去当前目录的文件夹中去找,lib目录下的头文件以及库文件,和mytest.c不是同级目录,所以编译会出错; 我们在编译的时候就需要告诉编译器,需要的头文件在哪个目录下。
此时,又有警告了:链接错误,未定义的两个函数?在lib目录下已经定义了两个函数,并且打包好了?为什么还是报错呢? 其原因和上面一样;所以我门还需要告诉编译器库文件在lib目录下:
头文件和库文件所在位置都告诉编译器了,怎么还是报错呢? 其实,头文件和库文件都在lib目录下,在mytest.c文件中,是明确的包含了,add.h和sub.h的,gcc在编译的时候能够认识,但不认识库文件,如果在lib目录下有多个库文件,gcc是不知道你想要使用哪个库的。所以我们还需要指明库的名字。
此时,整个程序才能够正确编译并运行 总结: 我们在使用静态库进行编译链接时,需要指定头文件的所在路径,库文件的所在路径以及所要掉用的库名称
同样,我们也可以编写Makefile: 方法二 对比我们之前在编译某个.c文件时,为什么有加上这些选项呢?。这是因为之前的库都是在系统的默认路径下,所以我们可以将我们做好的静态库拷贝到系统的默认路径下,也是可以达到不需要加这些选项的效果;但是严重不推荐。 3.动态库的制作 编写如下四个文件:其中源文件包含add.c和sub.c,头文件包含add.h和sub.h;用来制作动态库并打包
1.生成二进制(.o)文件 首先将上面的.c文件生成.o文件
-fPIC:作用是告知编译器 生成位置无关代码(编译产生的代码没有绝对位置,只有相对位置);从而可以在任意地方调用生成的动态库。 2.打包 我们将生成好的.o文件进行打包:
-shared:linux在gcc编译时加上 -shared 参数时,目的是使源码编译成动态库 .so 文件; 3.发布动态库 将库文件和所有的头文件组织起来linux动态库,放到lib目录下,这样就可以发布动态库了 当然,我们也可以直接编写Makefile,就不需要我们一步一步的完成静态库的打包及发布 4.动态库的使用 动态库的使用大致和静态库类似,但略有区别。我们先使用静态库的方法来实现动态库的链接。 能够成功编译,但是运行却报错了,为什么呢? 我们通过ldd命令列出动态库依赖关系,发现是not found。虽然已经告诉了编译器库文件和头文件的路径所在位置,但是当编译器编译好后,就与编译器无关了;当我们执行(运行)可执行程序a.out时,是由加载器来完成的。所以我们需要在运行时,告诉系统库文件在哪里; 方法一 拷贝到系统的默认路径下,一般指/usr/lib这里不做演示,严重不推荐; 方法二 更改LD_LIBRARY_PATH
LD_LIBRARY_PATH环境变量用于在程序加载运行期间查找动态链接库时指定除了系统默认路径之外的其他路径.注意,LD_LIBRARY_PATH中指定的路径会在系统默认路径之前进行查找; 添加好后,我们再次查看,发现路径已经指定好了 再次编译运行: 四、动态库与静态库特点总结 静态库的特点: 动态库的特点: (编辑:晋中站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |