1 静态库和动态库
1.1 什么是库
库文件是计算机上的一类文件,可以简单的把库文件看成一种代码仓库,它提供给使用者一些可以直接拿来用的变量、函数或类。
库是特殊的一种程序,编写库的程序和编写一般的程序区别不大,只是库不能单独运行。
库文件有两种,静态库和动态库(共享库),区别是:静态库在程序的链接阶段被复制到了程序中;动态库在链接阶段没有被复制到程序中,而是程序在运行时由系统动态加载到内存中供程序调用。
库的好处:
1.代码保密;
⒉方便部署和分发;
1.2 静态库
1 命名规则
Linux : libxxx.a
1ib :前缀(固定)
×xX :库的名字,自己起
.a :后缀(固定)
windows : 1ibxxx.1ib
2 静态库的制作步骤
- gcc获得.o文件
- 将.o文件打包,使用ar 工具(archive)
ar rcs libxxx.a xxx.o xxx.o
r-将文件插入备存文件中
c-建立备存文件
s-索引
3 制作静态库
库文件如下
tree,查看当前目录下,文件的目录结构
sudo apt install tree
下面是,已经建好的库的结构
准备工作:
在lesson03文件夹下,新建04_calc,
在04_calc下新建calc文件夹,
在calc下依次添加add.c, sub.c, mult.c, main.c, head.h,直接从上面的02_makefile文件下拷贝过来就行;
如下:
制作静态库过程:
ls
1. gcc获得.o文件
gcc add.c sub.c mult.c div.c -c #-c 汇编,生成目标文件.o
2. 将.o文件打包,使用ar 工具(archive)
ar rcs libxxx.a xxx.o xxx.o
#xxx.o xxx.o是列举目标文件,这样写太麻烦了,简写尾为 *.o
#libxxx.a库名,lib固定格式,后面xxx是库名,需自定义,,我们通常说的库名就是这个
r-将文件插入备存文件中
c-建立备存文件
s-索引
ar rcs libcalc.a *.o //生成静态库
静态库成功
在04_lib下创建library文件下;
library下创建include、lib、src文件夹
此时文件结构
将calc下面的库libcalc.a,拷贝到library的lib下;
将calc/head.h,拷贝到,library/lib/;
将calc/main.c,拷贝到,library/src/;
cp calc/libcalc.a library/lib/
cp calc/head.h library/include/
cp calc/main.c library/src/
gcc main.c -o app
编译生成可执行文件aap
找不到head.h,,因为在库目录library下,head.h和main.c不在同意文件夹下;
而终端当前目录是在libray/src下,所以要指定head.h的路径
-I directory 指定include包含文件的搜索目录
. ./上一级目录
gcc main.c -o app -I ../include/
此时,找到head.h文件;
但是,对于main中的 add、sub、mult、div函数未找到定义;
-l 在编译的时,指定使用的库
这里指定 calc库,即 ,-l calc
gcc main.c -o app -I ../include/ -l calc
制定了库名,,但找不到这个库
还要指定库的路径
-L 指定编译时,搜索库的路径
-L …/lib/
gcc main.c -o app -I ../include/ -l calc -L ../lib/
1.3 动态库
命名规则:
Linux : libxxx.So
lib:前缀(固定)
xxx∶库的名字,自己起
.so∶后缀(固定)
在Linux下是一个可执行文件
Windows : libxxx.dll
动态库的制作:
1.gcc得到.o文件,得到和位置无关的代码
gcc -c -fpic/-fPIC a.c b.c
#-fpic/-fPIC 大小写都可以,任意用一个
2.gcc得到动态库
gcc -shared a.o b.o -o libcalc.so
1 制作动态库
先删除所有.o 文件 rm *.o
1.gcc得到.o文件,得到和位置无关的代码
gcc -c -fpic *.c #汇编所有.c文件,-fpic并生成和位置无关的代码
2.gcc得到动态库
gcc -shared *.o -o libcaloc.so
删掉,library下之前静态库生成的文件
之后:
cp ../calc/head.h ./include/
cp ../calc/main.c ./src/
cp ../calc/libcalc.so ./lib/
编译main.c生成可执行文件 app
还是和静态库一样要指定 .h文件路径,库名,库路径
gcc main.c -o app -I ../include/ -l calc -L ../lib/
app生成成功;
但是执行./app出错
这由,动态库和静态库区别,导致的;
下面从二者工原理来解决;
1.4 静态库和动态库工作原理
静态库:GCC进行链接时,会把静态库中代码打包到可执行程序中;
动态库:GCC进行链接时,动态库的代码不会被打包到可执行程序中;,动态库在执行可执行文件时,会把代码单独加载到内存里,用完释放;好处,别的程序如果想用动态程序也可以直接调用;
·程序启动之后,动态库会被动态加载到内存中,通过Idd (list dynamic dependencies)命令检查动态库依赖关系
ldd app
如何定位共享库文件呢?
当系统加载可执行代码时候,能够知道其所依赖的库的名字,但是还需要知道绝对路径。此时就需要系统的动态载入器来获取该绝对路径。对于elf格式的可执行程序,是由ld-linux.so来完成的,它先后搜索elf文件的DT_RPATH段—一>环境变量LD_LIBRARY_PATH -->/etc/ld.so.cache文件列表―—>/libl,lusr/lib目录找到库文件后将其载入内存。
右键:复制会话,复制一个新的远程窗口
在 .bashrc文件中添加库路径
cd退回到家目录,用vim打开 .bashrc
vim .bashrc
在最下面加入,路径
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/luck/Linux/lesson03/04_lib/library/lib
a启动编辑,esc退出编辑模式,:wq保存并退出,:q直接退出,:!q强制退出
添加后,刷新
. .bashrc 同 source .bashrc,第一个点,就等同source
再次进入src就可以执行 ./app了
cd Linux/lesson03/04_lib/library/src
上面.bashrc是用户级文件;
也可以在系统文件里面添加路径;
不过这个文件是只读文件,在文尾添加路径后,无法保存,如果想要保存,需要修改文档权限,很麻烦,就不再试了。
1.5 区别
2 文件IO
2.1 标准C IO函数
读写,是站在内存(程序)的角度;
文件输入到内存,读,input;
内存输出到文件,写, output;
比如,我在记事本中写一行文;
没保存时,数据在内存上,按下保存后,数据写入文件(磁盘)。
当我们打开记事本,显示里面的内容时,,是读(输入)(加载),将文件存储的二进制内容,读入到内存,解析处数据,显示出来;
2.2 标准C库IO和Linux系统lO的关系
2.3 虚拟地址空间
2.4 文件描述符
在linux中,一切皆文件
文件描述符表,前三个描述符是终端的,0~3分别对应标准输入、标准输出、标准错误;
每打开一个新文件,就占用一个当前序号最小的空闲 文件描述符;
比如,新打开a.txt,描述符3;
再打开,b.txt,描述符4;
再打开,c.txt,描述符5;
此时释放,文件b,txt,吗,描述符4空闲了;
再打开,d.txt,这个时候,描述符4;
2.5 Linux系统IO函数(Linux系统api一般也成为系统调用)
Linux系统使用手册 manual ,
查看命令 man ls
查看某一章 man 数字 ls