呢图网站,装饰网站建设的背景,个人养老保险,wordpress说明文档交接文章目录 1. 静态库2. 动态库3. 动态库的加载 本章代码gitee仓库#xff1a;动静态库 1. 静态库
Linux开发工具gcc/g篇#xff0c;此篇文章讲过动静态库的基本概念#xff0c;不了解的可以先看一下这篇文章。
现在我们先来制作一个简单的静态库
mymath.h
#pragma once#i… 文章目录 1. 静态库2. 动态库3. 动态库的加载 本章代码gitee仓库动静态库 1. 静态库
Linux开发工具gcc/g篇此篇文章讲过动静态库的基本概念不了解的可以先看一下这篇文章。
现在我们先来制作一个简单的静态库
mymath.h
#pragma once#includestdio.hextern int meyerrno;
int add(int x,int y);
int sub(int x,int y);
int mul(int x,int y);
int div(int x,int y);mymath.c
#includemymath.hint myerrno 0;
int add(int x,int y)
{return xy;
}
int sub(int x,int y)
{return x-y;
}
int mul(int x,int y)
{return x*y;
}
int div(int x,int y)
{if(y 0){myerrno -1;return -1;}return x/y;
}我们要是想把我们这个方法提供给不然用2种方法 直接将源文件给别人 将源代码打包成库 - 库.h文件 这里头文件是是必须要给的这个头文件就相当于我们库的一份说明书
别人要使用我们的方法其就是将我们的这个.c文件全部编译成.o然后链接起来形成可执行现在我们不给源文件我们自己先编译成.o然后全部打包给人家人家就只需要编译自己的.c文件然后结合我们这个打包文件即可 指令ar -rc lib.o test1.o test2.o将编译好的.o文件打包起来 这时候就已经将库打包好了要将其发布我们只需再包装一下即可 将这个打包好的库使用一下 我们这里包含完整路径告诉这个头文件在哪儿但一般我们都是直接包含头文件的名称不会带上路径
#includemymath.h
int main()
{printf(11%d\n,add(1,1));return 0;
}但是这样的话编译就不通过了找不到这个头文件 在gcc中它会在当前目录和系统里面搜索这个当前目录指的是和源代码在同一级目录下 我们可以采用gcc main.c -I ./lib/include告诉gcc去这个路径里面找我们的头文件 这里的路径不需要再跟上我们的mymath.h,因为我们代码中已经包含了 再继续编译这里没有报找不到头文件的错误而是报的的是链接错误 这里我们可以测试一下让他生成目标文件不进行链接这里是没有问题的 这是因为找不到我们打包好的静态库这个原因也是gcc只会去默认的库路径或者是当前目录找库。
所以我们还要带上gcc main.-I ./lib/include/ -L ./lib/mymathlib/告诉gcc去这个路径找执行发现还是错误 报错还是一样这里是因为我们并没告诉gcc要链接哪个库我们后面还要跟上gcc main.c -I ./lib/include/ -L ./lib/mymathlib/ -l mymath 小写-l后面简易紧跟库名称库的真实名称是去掉前缀去掉后缀 这些选项带着看着有点冗余我们之前写的代码是纯C的代码gcc能在系统中找到这些动静态库。 而我们现在用的库属于第三方库所以要带上这些选项如果想这样做我们可以将这个库的头文件拷贝到系统的include将库文件拷贝到系统的lib64目录中然后指定-l编译如果不想这样我们可以建立软链接 Tips 我们这里写的库中对除零错误进行了判定 printf(11/0 %d errno %d\n,div(11,0),myerrno);这段代码的myerrno并没有改变这是因为传参是从右向左传递的传递myerrno的时候div函数还未调用所以myerrno没有改变 当我们链接完毕之后可采用指令ldd a.out查看所依赖的动态库这里却并没有mymath.c gcc默认动态链接我们这里只提供了静态库所以gcc只能对这个库进行静态链接。 这里动静态库都链接了这也说明如果需要gcc可以同时链接多个动静态库 接下来我们将我们的库文件拷贝到系统路径 然后不带上I、L这些选项编译发现并没有出现找不到头文件的错误出现的是链接错误 还是需要链接gcc main.c -lmymath 我们上面的对库进行拷贝本质上就是对这个三方库进行安装所谓的下载就是在系统路径下去掉这个库。 这里第三方库必须要指明库名称 当然这里并不是很建议将自己写的库安装到系统路径我们也可以采用软连接的方式
sudo ln -s /home/Pyh/linux/study/lib_11_15/test/lib/include /usr/include/myinc
sudo ln -s /home/Pyh/linux/study/lib_11_15/test/lib/mymathlib/libmymath.a /lib64/libmymath.a这两种方式都可以但是对于第三方库我们还是需要安装他们都说明书来进行安装 2. 动态库
不管是形成动态库还是静态库第一步都是先将源文件生成目标.o文件 采用指令
gcc -fPIC -c myprint.c
gcc -fPIC -c mylog.c然后将其打包ar指令是专门打包静态库的。形成动态库直接采用的是gcc
gcc -shared -o libmymethod.so *.o生成可执行程序就是将所有的.o文件链接可是我们的这两个.o里面并没有main函数都是提供的方法所以要跟上shared表示生成共享库动态库 这里形成的动态库是有可执行权限的而静态库是没有的 静态库是提供源代码的在形成可执行的时候它的作用就是将需要的内容拷贝过去并不会加载到内存 对于动态库来说它要和可执行程序产生关联当可执行程序运行时要访问动态库的内容要跳转到动态库那么动态库就必须加载到内存当中所以要有可执行权限 我们可以使用Makefile一次性生成我们的动静态库
dynamic-liblibmymethod.so
static-liblibmymath.a.PYONY:all
all:$(dynamic-lib) $(static-lib)$(static-lib):mymath.oar rc $ $^
mymath.o:mymath.cgcc -c $^$(dynamic-lib):mylog.o myprint.ogcc -shared -o $ $^
mylog.o:mylog.cgcc -fPIC -c $^
myprint.o:myprint.cgcc -fPIC -c $^.PHONY:clean
clean:rm -rf *.o *.a *.so mylib.PHONY:output
output:mkdir -p mylib/includemkdir -p mylib/libcp *.h mylib/includecp *.a mylib/libcp *so mylib/lib这个单独使用静态库还是和上面一样就不做演示了。我们来使用动态库看看方法也是一样 生成可执行程序没有问题但是运行的时候报错了。
我们先看一下依赖的动态库ldd a.out 发现这里是not found我们在file a.out看一下这个程序是使用共享库的 那么问题就是出现在了这个not found 我们这里是动态库我们只是告诉了编译器这个库的路径在哪里。可是动态库是要加载到内存的系统的加载器并不知道它在哪儿。 这也可以想静态库一样直接安装到系统路径下这里就不演示了。 方法1拷贝到默认库路径 方法2建立软链接 sudo ln -s /home/Pyh/linux/study/lib_11_15/test/mylib/lib/ /lib64/libmymethod.so方法3将自己库所在的路径添加到系统环境变量LD_LIBRARY_PATH export LD_LIBRARY_PATH$LD_LIBRARY_PATH:/home/Pyh/linux/study/lib_11_15/test/mylib/lib如果重新登录那么这个配置的环境变量就失效了要是想长久有效可以将其添加到系统启动时候的脚本里面~/.bash_profile 方法4在目录/etc/ld.so.conf.d里面加上后缀位.conf的路径文件然后ldconfing即可需要root权限 这里不用添加库名字因为我们这个程序在编译的时候已经知道了库的名字所以系统知道链接哪个库
其实在实际情况下我们用的库都是别人成熟的库都采用直接安装到系统当中 推荐库ncurses这个是基于终端的可提供一些图形化界面的库 3. 动态库的加载
动态库在程序运行的时候会被加载到内存当中而静态库没有创建的动态库被所以的可执行文件动态链接都要使用所以动态库也叫共享库。
所以动态库在系统加载之后会被所有的进程共享。 那这个动态库是怎么加载的呢 动态库也是文件文件都是存储在磁盘上。如果我们要执行这个程序需要访问这个库的代码那么这个库就会加载到内存当中。 而进程访问内存是页表映射的方式那么这个加载到内存的库就会映射到页表然后页表再映射到进程地址空间的共享区里面这时候代码区要访问这个库就跳转共享区拿到要的方法执行完毕之后再返回代码区。所以在建立映射之后我们执行的任何代码都是在进程地址空间中执行的。 一个共享库可以给多个进程使用而一个进程也可以使用多个共享库这就说明在系统当中一定会有多个动态库操作系统要将这些库管理起来也是六个字先描述再组织。所以这个共享库有没有加载到内存当中操作系统是十分清楚的。 这里还有个问题动态库中可能会存在全局变量例如errno这样的如果我们的进程将其修改了会不会影响其他的进程呢 这肯定是不会的如果这个进程要修改这个全局变量就需要对这个变量进行写入写入的过程会发生写时拷贝。这也是进程为什么具有独立性的一个原因