对库的初步了解---------是一个不能直接运行的二进制机器码文件

一、对库的初步了解 --- 是一个不能直接运行的二进制(机器码)文件

一般能让机器运行的程序是二进制文件(机器码文件),反过来:二进制文件不一定都能被系统运行。因为库和.o也是二进制,但是他不能运行,
它是没有被链接的,也没有main函数。库是一种二进制文件(机器码文件,但是不能独立运行),即也是用gcc(动态库),ar(静态)编译器工具编译出来的文件。
库文件虽然不能直接运行,但是里面存放的都是功能函数接口。使用的时候你只需要写一个main函数去调用就行(记得声明)
库也是用C写出来也可以用c++写出来,然后拿去编译生成的二进制文件,但是一般不能运行。库里面没有main函数。

库的分类:

库的后缀   .a  静态库    libxxx.a,静态库用ar编译出来。
库的后缀: .so 动态库    libxxx.so,动态库用gcc或者__arm-linux-gcc__编译出来。
库的前缀: lib
库的名字: xxx
库的后缀:.a或者.so

库文件的作用:
一般库里面是没有main函数,里面都是功能函数,提供给其他人用函数去嵌套调用。

eg: 我想在屏幕打印输出字符串,一开始我需要自己写一个函数来实现,但是你学了c之后,就知道了原来由c标准库libc.so libc.a里面提供了
一个函数叫做printf
我自己在写代码的时候只需要写个main,在main里面调用printf即可。库只是库,只是二进制,看不到里面的源码的。

.c 变.o
.o 直接变可执行的程序(有main)
.o 编译成动静态库(不用main)

tips:所有的库文件都是从.o编译生成的。 写一份.c ---> 生成.o --> 库文件


二、静态库的编译制作与使用

制作编译使用步骤 ---- 先体验,之后再分析:
第一步:先写一份用来编译库文件的.c,如下图
image


第二步: 先把hello.c编译生成.o文件 ,如下图 注意:所有的库制作,都是先生成.o文件,再把.o生成对应的库文件。
image


第三步: 用ar编译工具把.o编译生成.a静态库文件,如下图。
image


第四步:再写一份有main函数的.c在main函数里面调用libhello.a库中的接口,如下图。
image


第五步:把调用库的.c文件和.a库文件一起编译生成程序,最终运行程序,如下图 静态库静态编译。
image


注意:使用静态库需要把库文件里面代码和调用库的.c文件一起融合编译,把两边的代码合在一起。

坏处:程序文件变大。
好处:你这个程序可以在任意主机上运行,因为程序本身自己就有库编译进去了,所以以后再也不需要这个库也能运行。


分析 ar 命令中的rcs参数

r: 在库中加入成员文件,如果需要加入的成员已经存在库中,就被替换掉。

c:创建一个库。

s:无论ar命令是否修改了库的内容,都强制重新生成库符号表。

tips:无论库对应的.c文件中的code是否被修改,都会重新更新库符号表(与库的.c源文件对应)

关于s参数,库符号表的理解,这个表里面存放的是库中成员(函数,变量)的定位和索引需要的位置。
image

个人理解:在制作动态库的时候,中间有一个库符号索引表,是在后面使用库里面的成员(这个成员就是函数或者是变量),负责链接定位成员,因此s是生成库生成的时候,把库里面的这个符号索引表更新到最新,保证符号表中的链接都是最新的、有效的。


三、动态库(共享库)的编译制作与使用

制作编译使用步骤 ---- 先体验,之后再分析:
第一步:先写一份用来编译库文件的.c,如下图:
image


第二步: 先把hello.c编译生成.o文件 ,如下图:
image


第三步:把 .o编译生成.so文件,如下图:
image


第四步:如何使用这个动态库 ---- 动态库动态编译 所有动态库动态编译就是通过-l和-L指定库名和库路径:
image


分析:-fPIC、-shared参数:

-fPIC:动态链接代码,让代码与内存地址无关。可在任意内存地址中执行代码。( 默认情况下代码在编译之后是由固定内存位置执行的)。
-shared :创建动态库(共享库)。

-fPIC:运行程序时候,cpu给你执行程序,其实就是读取机器码(代码编译过来),静态库或者普通编译的情况下代码的位置是固定的(这个代码位置和调用源码结合算出来的位置)。

简述:让库代码和内存地址无关,就是为了让代码能够再内存的任意位置上运行,实现动态的意义。

一般情况下,普通编译和静态库静态链表编译,只固化好符号表,更具符号表在对应的内存地址中加载对应的机器码。
不支持编译好的程序直接换系统平台运行。
而-fPIC就是让我们的代码段运行(加载位置)和内存的固定位置不管。可以在任意的内存地址上面运行。

动态库与静态库的区别

使用静态库的时候,静态库是和调用者main.c融合在一起编译生成程序的。这里的程序较大。(如果是gcc换电脑,需要重新再新电脑里面重新)。因为静态库静态编译出来的程序已经包含本身的程序+静态库的程序,所以可以在系统上独立运行。

使用动态库的时候,动态库没有和调用者融合在一起编译生成程序,只是链接让编译器自己去看库里面的代码而已,
这里生成的程序较小,动态库动态编译出来的程序只包含调用者本身的并没有包含库代码,不能独立运行
在运行程序的时候需要通过动态库的环境变量来动态链接库才能运行。(拖家带口)

tips:我们在运行需要链接动态库的程序的时候,往往会运行失败,系统提示· 找不到这个动态库。
image


常见的解决方法:

① 把你的动态库直接移动或者拷贝到系统的/lib。
② 或者直接设置系统的动态库环境变量:就是把动态库的路径: 拓展
生效一次:export LD_LIBRARY_PATH=/mnt/hgfs/GZFX05/动静态库/001/:$LD_LIBRARY_PATH

     永久生效:export LD_LIBRARY_PATH=/mnt/hgfs/GZFX05/动静态库/001/:$LD_LIBRARY_PATH添加到~/.bashrc配置文件中的最后一行添加进去

补充使用库的方式

要用方式一:  静态库的__静态__编译    (库和调用库的代码是一起融合编译生成程序的,也就是说程序中已经包含了整个静态库)
    把库和调用的.c一起编译:
            gcc xxx.c libhello.a -o xxx

方式二:libface.a 静态库的__动态___编译  (库和调用库的代码是一起融合编译生成程序的,也就是说程序中已经包含了整个静态库)
             gcc  xxx.c -o xxx  -L. -lhello (没有人用)

libface.so    动态库的_动态__编译
要用方法三: gcc main.c -o face -lface -L./     只是链接动态库的位置而已,并没有把动态库加到程序
    -L:指定库的路径
    -l:指定库的名字

方法四: 动态库的_静态_编译                 只是链接动态库的位置而已,并没有把动态库加到程序
    gcc main.c libhello.so -o main(没有人用)

动态库决定了使用库的时候的编译模式,不管外部动态编译还是静态编译,内部一定是用动态编译。
静态库决定了使用库的时候的编译模式,不管外部动态编译还是静态编译,内部一定是用静态编译。

posted @ 2024-08-10 14:47  WJnuHhail  阅读(77)  评论(0)    收藏  举报