技术标签: # Linux 运维 动静态库 linux 服务器
动静态库的本质就是可执行程序的"半成品"。
需要完成一个可执行程序需要经历以下四个步骤:
例如,用test1.c,test2.c以及main1.c形成可执行文件,需要先得到各个文件的目标文test1.o,test2.o以及main1.o,然后将这些目标文件链接起来,最终形成一个可执行程序。
如果在另一个程序main2.c中也需要用到test1.c和test2.c,那么可执行程序生成和上面的步骤一样。
实际上,对于可能频繁用到的源文件,比如这里的test1.c,test2.c,可以将他们的目标文件test1.o,test2.o进行打包,之后需要用到这两个目标文件就可以直接链接这个包当中的目标文件即可,上面的打包就可以称为一个库。库的本质就是一堆***.O集合,库的文件当中并不包含主函数而只是包含了大量写好的方法以供调用,因此,我们说动静态库是可执行程序的"半成品".
下面以我们最初学习的最简单的代码,初步认识动静态库
#include <stdio.h>
int main()
{
printf("hello world\n"); //库函数
return 0;
}
运行结果如下所示:
在这份代码中我们通过调用printf输出的hello world,主要原因是gcc编译器在生产可执行程序时,将C标准库链接进来.
在Linux下,可以通过ldd 文件名来查看一个可执行程序所以来的库文件
第一次打开可能可不懂,其实就是libc.so.6就是该可执行程序依赖的库文件,通过ls命令去发现libc.so.6实际上就只是一个软链接
实际上该软链接的源文件libc-2.17.so和libc.so.6在同一个目录下,为了进一步了解,可以通过file 文件名命令来查看文件类型
可以看到,实际上libc-2.17.so就是一个共享的目标文件库,准确来说,这还是一个动态库。说一下:
这里的libc.so.6实际上就是C动态库,库的名字就是,去掉前缀lib,再去掉后缀.so或.a及其后面的版本。
而g++编译器一般都是默认是动态链接的,若想进行静态链接,可以携带一个-static
此时生产的可执行程序就是静态链接了,可以明显观察到静态链接生成的可执行程序文件的大小,要比动态的要大的多。主要原因下面详细介绍。
静态库
Linux下,以.a为后缀的文件。程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候不再需要静态库。本质是在编译时把静态库中的代码复制到进程的代码中。因此使用静态库生成的可执行程序要比一般的程序大。
动态库
Linux下,以.so为后缀的文件。程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。一个动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文件的整个机器码。
在可执行文件开始运行前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中,这个过程叫做动态链接。动态库在多个程序间共享,节省了磁盘空间,操作系统采用虚拟内存机制允许物理内存中的一份动态库被调用到该库的所有进程共用,节省了内存和磁盘空间。
本质就是将代码编译成.o的二进制文件,然后进行打包。
为了更好的演示这个过程,创建add.c,add.h,sub.c和sub.h四个文件,内容如下所示:
add.h
#pragma once
extern int my_add(int x, int y);
add.c
#include "add.h"
int my_add(int x, int y)
{
return x + y;
}
sub.h
#pragma once
extern int my_sub(int x, int y);
sub.c
#include "sub.h"
int my_sub(int x, int y)
{
return x - y;
}
如下所示:
第一步:将所有源文件生成对应的目标文件
第二步:使用ar命令将所有目标文件打包为静态库
ar命令是gnu的归档工具,常用于将目标文件打包为静态库,下面我们使用ar命令的-r选项和-c选项进行打包。
此外,我们可以用ar命令的-t选项和-v选项查看静态库当中的文件。
第三步:将头文件和生成的静态库组织起来
当我们把自己的库给别人用的时候,实际上需要给别人两个文件夹,一个文件夹下面放的是一堆头文件的集合,另一个文件夹下面放的是所有库文件。
因此,在这里我们可以将add.h和sub.h这两个头文件放到一个名为Include的目录下,将生成的静态库文件libmymath.a放到一个名为lib的目录下,然后将这两个目录放到myliba下,此时就可以将myliba给别人使用了。
Makefile
当然,也可以将上述所要执行的命令全部写道Makefile中,后续当我们要生成静态库以及组织头文件和库文件时就可以一步到位了,不至于每次重新生成的时候都要敲这么多命令。
编写Makefile后,只需一个make就能生成所有源文件对应的目标文件进而生成静态库。
make output就能将头文件和静态库组织起来。
创建源文件main.c,编写下面这边简单的程序尝试使用我们打包好的静态库。
#include <stdio.h>
#include <add.h>
#include<sub.h>
int main()
{
int x = 20;
int y = 10;
int z = my_add(x, y);
int q=my_sub(x,y);
printf("%d + %d = %d\n", x, y, z);
printf("%d+%d=%d\n",x,y,q);
return 0;
}
经过调整后目录下只有main.c和我们刚刚打包好的静态库。
使用选项
此时使用gcc编译main.c生成可执行程序时需要携带三个选项:
具体操作如下:
注意:
为什么之前使用gcc编译的时候没有指明过库的名字?
因为我们使用的gcc编译的是C语言,而gcc就是用来编译C程序的,所以gcc编译的时候默认就找的是C库,但此时我们要链接的是哪一个库编译器是不知道的,因此我们需要使用选项,指明需要链接库文件路径下的哪一个库。
动态库的打包相对于静态库来说有一点点差别,但大致相同,还是以上面的四个文件为例子:
第一步:让所有源文件生成对应的目标文件
此时用源文件生成目标文件时需要携带-fPIC选项:
说明:
第二步:使用-shared选项将所有目标文件打包成动态库
与生成静态库不同的是,生成动态库时我们不必使用ar命令,只需使用gcc的-shared选项即可。
第三步: 将头文件和生成的动态库组织起来
与生成静态库时一样,为了方便别人使用,在这里可以将add.h和sub.h这两个头文件放到一个名为include的目录下,将生成的的动态库文件libcal.so放在一个名为lib的目录下,然后将这两个目录都放在mlib下。
使用Makefile
当然,生成动态库也可以将上述所要执行的命令全部写到Makefile当中,后续当我们要生成动态库以及组织头文件和库文件就可以一步到位了
编写Makefile后,只需一个make就能生成所有源文件对应的目标文件进而生成动态库。
一个make output就能将头文件和动态库组织起来
使用main.c来演示动态库的使用和我们刚打包好的动态库
使用该动态库的方法与刚才我们使用静态库的方法一样,我们既可以用-I,-L,-l这三个选项来生成可执行程序,也可以先将头文件和库文件拷贝到系统目录下,然后仅使用-l选项指明需要链接的库名字来生成可执行程序。下面仅以第一种方法为例进行演示。
与静态库不同的是,这里无法直接运行。
需要注意,这里使用-I,-L,-l这三个选项都是在编译期间告诉编译器我们使用的头文件和库文件在哪里以及是谁,但是当生成的可执行程序生成后就与编译器没有关系了,此后该可执行程序运行起来后,操作系统找不到该可执行程序所依赖的动态库。
既然找不到我们的库文件,那么我们直接将库文件拷贝到系统共享的库路径下,这样一来系统就能找到对应的库文件了。
文章浏览阅读745次,点赞12次,收藏21次。通过以上更具体的步骤和考虑因素,_rag最佳实践
文章浏览阅读3.1k次。python保存文本文件的方法:使用python内置的open()类可以打开文本文件,向文件里面写入数据可以用write()函数,写完之后,使用close()函数就可以关闭并保存文本文件了示例代码如下:执行结果如下:内容扩展:Python3将数据保存为txt文件的方法,具体内容如下所示:f = open("data/model_Weight.txt",'a') #若文件不存在,系统自动创建。'a'..._怎么保存python文件
文章浏览阅读196次。Windows下编译Oracle驱动打开工程:C:\Qt\4.8.1\src\plugins\sqldrivers\oci修改oci.pro:TARGET = qsqlociSOURCES = main.cppinclude(../../../sql/drivers/oci/qsql_oci.pri)include(../qsqldriverbase.pri)INCLUDEPATH += D:\o..._linux 编译 oci.pro
文章浏览阅读270次,点赞3次,收藏5次。PCF8591在板子上对应的是u16芯片。该芯片有4个ADC输入管脚,分别是AIN0~AIN3。AIN0对应的在排针J3上,AIN1对应的是光敏电阻与固定电阻R31的分压数值,AIN2不怎么考,AIN3对应的是旋转电位计的电压值。器件地址:1001 000(R/W非)表示51单片机从PCF8591读数据;表示51单片机向PCF8591写数据;另外,光敏电阻的阻值变化,光线越强,阻值越低;光线越暗,组织越高。对应的电压值,光线越暗,AIN1的电压越低。光线越强,阻值越高。_pcf8591ain3
文章浏览阅读521次。这个问题大多数是由于使用老版本torch导致的,github上有说这是某个版本的bug,再后续工作中已经进行了修复,要是非要使用该版本torch的话,我使用了一个比较笨拙的方法,写一个where代替torch.where()这个版本是xy不需要同维度的,不过肯定没有torch写的快,不过能运行了。这是复现muzic中的getmusic时遇到并解决的问题。_runtimeerror: expected scalar type int but found float
文章浏览阅读1.6k次,点赞12次,收藏7次。大家好!大四的同学们毕业设计即将开始了,你们做好准备了吗?学长给大家精心整理了最新的计算机毕业设计选题,希望能为你们提供帮助。如果在选题过程中有任何疑问,都可以随时问我,我会尽力帮助大家。在选择毕业设计选题时,有几个要点需要考虑。首先,选题应与计算机专业密切相关,并且符合当前行业的发展趋势。选择与专业紧密结合的选题,可以使你们更好地运用所学知识,并为未来的职业发展奠定基础。要考虑选题的实际可行性和创新性。选题应具备一定的实践意义和应用前景,能够解决实际问题或改善现有技术。
文章浏览阅读2.8k次。触摸屏属于一个标注的input dev.所以我们按照输入子系统的流程来实现驱动开发。 实际板子与CTPM的通讯连接基于IIC总线,所以我们需要把驱动挂载到IIC总线下面去,也就是注册IIC驱动到iic_core.c中去。 实例化一个IIC设备有多种方式,仿照上一次的24cxx IIC设备的创建,我们来实现ft5x06IIC设备的创建。 因实际板子上TS IC使用的是ft5x02,所以先实例化设_触摸屏a类协议和b类协议
文章浏览阅读5.2k次。关于html中下拉菜单select的样式的改变作者:菩提树下的杨过 日期:2006-06-12字体大小: 小 中 大 首先要告诉大家,如果你是用css的方法,除了箭头部分,其他都可以改变,这是很令人别扭的事,因为其他的样式改了,箭头部分改不了等于无用。下面举个css改select的例子 HTML代码 .box{border:1px solid#C0C0_html设置select选择显示和下来显示怎么能不一致
文章浏览阅读3.4k次。软件环境:WIN7_64 + ISE 14.4 (system_edition)硬件:Zedboard、USB-Cable线搭建图: 经过前几天的学习,查看数据手册、官方例程,笔者已经对Zedboard有了基本的了解,但是怎样才能充分发挥ZYNQ的优势呢?这个就不得不说下ZYNQ的基本架构了,它分为PS(Processing System)和PL(Progr_zedboard教程
文章浏览阅读430次。试用一下H2O全自动机器学习下载数据集天池练习赛"工业蒸汽量预测",下个数据集:https://tianchi.aliyun.com/competition/entrance/231693/introduction安装H2OH2O requirements:pip install requestspip install tabulatepip install ..._练习赛-蒸汽数据集
文章浏览阅读603次。vLSW1、vLSW2充当虚拟交换机,给数据添加vlan tag。由于模拟器PC不会主动发送ARP,需要用PC ping 网关地址。查看VPN实例中的路由,学习到32位主机路由。查看OSPF邻居是否建立,路由是否学习到。CE1上学习到32位主机路由(回城路由)查看BGP EVPN学习的5类路由。测试PC访问外部网络Server。查看BGP EVPN邻居关系。同子网,PC1 访问PC2。跨子网,PC1 访问PC3。查看EVPN的3类路由。查看EVPN的2类路由。查看3层VxLan隧道。查看VPN实例内路由。_vxlan分布式网关实验
文章浏览阅读545次。Mac用户在使用NTFS格式移动硬盘时,会遇到无法写入硬盘的情况。要想解决无法写入的问题,很多人选择使用Mac读写软件。面对市面上“众多”的读写硬盘软件,用户应该怎么选择呢?初次接触移动硬盘的伙伴可能不知道移动硬盘怎么和电脑连接,本文就来告诉大家mac读写硬盘的软件有哪些,mac如何使用移动硬盘。因为Mac电脑不能写入NTFS格式磁盘,但是多数用户使用的是NTFS格式的移动硬盘、u盘,因此很多NTFS for Mac软件应运而生。但是市面上很多NTFS for Mac软件很多,例如:Tuxera NTFS