作者主页: 作者主页
本篇博客专栏:Linux
创作时间 :2024年10月22日
一.库的定义
什么是库,在windows平台和linux平台下都大量存在着库。
本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。
由于windows和linux的本质不同,因此二者库的二进制是不兼容的。
本文仅限于介绍linux下的库。
二.库的种类
1. 在windows中
.dll 动态库
.lib 静态库
2. 在linux中
.so 动态库
.a 静态库
二者的不同点在于代码被载入的时刻不同。
静态库的代码在编译过程中已经被载入可执行程序,因此体积较大。
共享库的代码是在可执行程序运行时才载入内存的,在编译过程中仅简单的引用,因此代码体积较小。
三.库存在的意义
库是别人写好的现有的,成熟的,可以复用的代码,你可以使用但要记得遵守许可协议。
现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常。共享库的好处是,不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例。
四.库文件是如何产生的在linux下
静态库的后缀是.a,它的产生分两步:
Step 1.由源文件编译生成一堆.o,每个.o里都包含这个编译单元的符号表
Step 2.ar命令将很多.o转换成.a,成文静态库
动态库的后缀是.so,它由gcc加特定参数编译产生。
五.程序在不同环境下运行时怎么寻找库
1. Linux系统默认到哪里找命令,如果命令不在那里,该怎么设置?
(1) Linux在运行一条命令时,默认会到 /bin , /sbin ,, /usr/bin, /usr/sbin目录下去找;如果找不到则报command not found
(2)如果命令存放在其他路径下,我们可以通过export PATH导出,不过这样只是临时生效;
(3) 如果想让所有用户生效,则修改/etc/profile,里面通过export PATH导出路径;
(4) 在PC上如果只想对本用户生效,则修改~/.bash_profile
2. LInux程序在运行时到哪里找动态库, 如果动态库不在那里,该怎么设置?
(1)若是在开发板程序运行时:修改/etc/profile,export LD_LIBRARY_PATH添加库的其他存放路径。
(2)若是在片PC上程序运行时:动态库默认路径为/usr/lib和/lib,可在/etc/ld.so.conf中添加指定动态库搜索路径,通过LD_LIBRARY_PATH(LD_LIBRARY_PATH是Linux环境变量名,该环境变量主要用于指定查找共享库(动态链接库)时除了默认路径之外的其他路径)命令指定,假如现在需要在已有的环境变量上添加新的路径名,则采用如下方式:
LD_LIBRARY_PATH=NEWDIRS:$LD_LIBRARY_PATH.(newdirs是新的路径串)。
注:在linux下可以用export命令来设置这个值,比如
在linux终端下输入:export LD_LIBRARY_PATH=/opt/au1200_rm/build_tools/bin: $LD_LIBRARY_PATH:
然后再输入:export,即会显示是否设置正确
export方式在重启后失效,所以也可以用 vim /etc/bashrc ,修改其中的LD_LIBRARY_PATH变量。
六.如何知道一个可执行程序依赖哪些库
ldd命令可以查看一个可执行程序依赖的共享库
七:重点
1.静态库:
1.1、怎么做静态库:
在Linux环境下,通常使用GCC(GNU Compiler Collection)编译器来编译源代码,并使用
ar
(archiver)工具来创建静态库
编写源代码:首先,你需要有一些源代码文件,比如 x.c ,y.c ,z.c
编译源代码为对象文件:使用GCC编译器将源代码编译为目标文件(.o文件)。
创建静态库:使用
ar
工具将对象文件打包成静态库。
头文件是一个手册,提供函数的声明,告诉用户怎么用;.o提供实现,我们只需要补上一个main函数,调用头文件提供的方法,然后和.o进行链接,就能形成可执行。
头文件是一个手册,提供函数的声明,告诉用户怎么用;.o提供实现,我们只需要补上一个main函数,调用头文件提供的方法,然后和.o进行链接,就能形成可执行。
mymath.h
#pragma once // 防止头文件重复包含
#include <stdio.h>
int Add(int x,int y);
mymath.c
#include "mymath.h"
int Add(int x,int y)
{
return x + y;
}
mystdio.h
#pragma once
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define LINE_SIZE 1024
#define FLUSH_NOW 1
#define FLUSH_LINE 2
#define FLUSH_FULL 4
typedef struct _myFILE
{
unsigned int flags;
int fileno;
// 缓冲区
char cache[LINE_SIZE];
int cap;// 容量
int pos;// 下次写入的位置
}myFILE;
myFILE* my_fopen(const char* path,const char* flag);
void my_fflush(myFILE* fp);
ssize_t my_fwrite(myFILE* fp,const char* data,int len);
void my_fclose(myFILE* fp);
mystdio.c
#include "mystdio.h"
myFILE* my_fopen(const char* path,const char* flag)
{
int flag1 = 0;
int iscreate = 0;
mode_t mode = 0666;
if(strcmp(flag,"r") == 0)
{
flag1 = O_RDONLY;
}
else if(strcmp(flag,"w") == 0)
{
flag1 = (O_WRONLY | O_CREAT | O_TRUNC);
iscreate = 1;
}
else if(strcmp(flag,"a") == 0)
{
flag1 = (O_WRONLY | O_CREAT | O_APPEND);
iscreate = 1;
}
else
{}
int fd = 0;
if(iscreate)
fd = open(path,flag1,mode);
else
fd = open(path,flag1);
if(fd < 0) return NULL;
myFILE* fp = (myFILE*)malloc(sizeof(myFILE));
if(fp == NULL) return NULL;
fp->fileno = fd;
fp->flags = FLUSH_LINE;
fp->cap = LINE_SIZE;
fp->pos = 0;
return fp;
}
void my_fflush(myFILE* fp)
{
write(fp->fileno,fp->cache,fp->pos);
fp->pos = 0;
}
ssize_t my_fwrite(myFILE* fp,const char* data,int len)
{
// 写入的本质是拷贝,条件允许就刷新
memcpy(fp->cache + fp->pos ,data,len);// 考虑扩容与越界问题
fp->pos += len;
if((fp->flags&FLUSH_LINE) && fp->cache[fp->pos-1] == '\n')
{
my_fflush(fp);
}
return len;
}
void my_fclose(myFILE* fp)
{
my_fflush(fp);
close(fp->fileno);
free(fp);
}
main.c
#include "mymath.h"
#include "mystdio.h"
#include <string.h>
#include <stdio.h>
int main()
{
int a = 10;
int b = 20;
printf("%d + %d = %d\n",a,b,myAdd(a,b));
myFILE* fp = my_fopen("log.txt","w");
if(fp == NULL) return 1;
const char* message = "这是我写的...\n";
my_fwrite(fp,message,strlen(message));
my_fclose(fp);
return 0;
}
编译并执行程序
将.c文件(源文件)编译成.o文件(目标文件) [ -c
选项告诉GCC只编译和汇编,但不链接]
使用.h 文件和.o 文件编译main.c程序
gcc main.c 只编译了main.c文件,并没有包含对mymath.o 和 mystdio.h 的链接操作,因为main.c 依赖于mymath.h 和 mystdio.h 中声明的函数,因此仅编译main.c是不够的。
解决办法一:
将.o文件 和.c文件一起编译链接。
解决办法二:
将main.o也编译成.o文件
解决方法三:通过ar指令将所有.o文件打包:
ar -rc libmyc.a *.o # 将所有.o文件打包成libmyc.a文件
1.2、怎么使用静态库
- 方式一:直接使用打包的文件
为了更好的使用静态库,我们把前面打包的文件拷贝到另外的目录进行操作。
这里我们创建一个other目录并cd进去
然后将之前形成的libmystdio.a文件以及两个.h头文件拷贝过来拷贝过来
这样就可以了
- 方式二:将打包的文件拷贝到系统库中(严重不推荐)
通过这几步操作就将这些文件拷贝到啦目录底下
但是直接使用gcc编译还是会报错,因为该方法的实现是我们自己写的,gcc/g++不认识,所以直接编译会报错。
在gcc编译.c文件之后需要加参数,-l libmyc.a,且需要去掉lib和.a,因此正确的命令是gcc main.c -lmyc (-l后面可以加空格也可以不加空格)
第二种方式不推荐,因此演示完之后最好将拷贝的文件给删除掉。
方式三:通过命令链接静态库
为什么不能直接使用 gcc main.c myc.a 因为告诉了gcc/g++编译器,但是没有告诉操作系统!!!
使用静态库:在编译其他程序时,可以通过-I(指定用户自定义头文件搜索路径) -L(指定用户自定义库文件搜索路径)和 -l
(执行确定的第三方库名称,去掉前缀lib
和后缀.a
)选项来链接静态库。
最后:
十分感谢你可以耐着性子把它读完和我可以坚持写到这里,送几句话,对你,也对我:
1.一个冷知识:
屏蔽力是一个人最顶级的能力,任何消耗你的人和事,多看一眼都是你的不对。
2.你不用变得很外向,内向挺好的,但需要你发言的时候,一定要勇敢。
正所谓:君子可内敛不可懦弱,面不公可起而论之。
3.成年人的世界,只筛选,不教育。
4.自律不是6点起床,7点准时学习,而是不管别人怎么说怎么看,你也会坚持去做,绝不打乱自己的节奏,是一种自我的恒心。
5.你开始炫耀自己,往往都是灾难的开始,就像老子在《道德经》里写到:光而不耀,静水流深。
最后如果觉得我写的还不错,请不要忘记点赞✌,收藏✌,加关注✌哦(。・ω・。)
愿我们一起加油,奔向更美好的未来,愿我们从懵懵懂懂的一枚菜鸟逐渐成为大佬。加油,为自己点赞!