小编个人主页详情<—请点击 小编个人gitee代码仓库<—请点击 linux系列专栏<—请点击 倘若命中无此运,孤身亦可登昆仑,送给屏幕面前的读者朋友们和小编自己! 
目录
-
- 前言
- 一、回顾知识
- 二、静态库的制作
- 三、静态库的使用
- 总结
前言
【linux】linux基础IO(六)软硬链接(软链接,硬链接)——书接上文 详情请点击<——,本文会在上文的基础上进行讲解,所以对上文不了解的读者友友请点击前方的蓝字链接进行学习 本文由小编为大家介绍——【linux】linux基础IO(七)静态库的制作与使用
一、回顾知识
libXXX.a(静态库)
libXXX.so(动态库)
二、静态库的制作
//mymath.h
#pragma once //防止头文件被重复包含
#include <stdio.h>
extern int myerrno;//声明错误码myerrno,这样在每一个.c文件中都可以定义使用myerrno变量不互相影响
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
#include "mymath.h"
int myerrno = 0;//错误码初始化为0,表示没有错误
int Add(int x, int y)
{
return x + y;
}
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; //返回-1表示出错了
}
return x / y;
}
lib=libmymath.a //定义lib变量,其实代表的是libmymath.a后面便于进行修改
$(lib):mymath.o //$(lib)的意思是libmymath.a, libmymath.a作为目标文件的依赖方法是mymath.o
ar -rc $@ $^ //使用ar归档工具, 将mymath.o打包成libmymath.a
mymath.o:mymath.c
gcc -c $^ //gcc -c $^不使用-o进行命名的时候, 进行汇编后的结果命名会形成mymath.c名称的同名.o后缀的名称,即mymath.o
.PHONY:clean //.PHONY伪目标clean既然可以执行rm指令,那么同样也可以执行其它指令
clean:
rm -rf *.a *.o lib
.PHONY:output //那么我们同样也可以执行其它指令
output:
mkdir -p lib/include //注意,这里不要将这里的lib跟第一行的lib混淆,第一行的lib只有使用
mkdir -p lib/mymathlib //$(lib)的时候才代表libmymath.a,这里的lib仅仅是一个名称,代表的就是lib,递归式建立目录
cp -rf *.h lib/include //将.h为后缀的头文件放到指定头文件目录路径下
cp -rf *.a lib/mymathlib //将.a为后缀的静态库放到指定库目录路径下

三、静态库的使用

#include "mymath.h"
int main()
{
printf("1 + 1 = %d\\n", Add(1, 1));
return 0;
}
如果想要运行main.c首先就要使用gcc编译形成可执行,那么我们使用gcc之后结果缺是下面这样,这究竟是什么原因?明显的,这个错误信息提示我们找不到头文件mymath.h,你逗我呢,gcc?明明这个mymath.h这个头文件就在当前目录的lib目录里面,你却告诉我找不到 
是的,用户,我gcc确实找不到,因为我gcc要求的头文件要在和main.c的同一级目录下,不能够是在和mian.c的同级目录lib的目录下,我gcc只会现在系统的头文件路径 /usr/include下,以及当前目录路径下的同级目录进行查找,我们提供的头文件即不在系统的特定头文件/usr/include路径下,同时也不在当前目录路径的同级目录,所以自然会找不到,那么怎么办呢?

有办法,其中第一个办法是在mian.c源文件中直接将头文件的名称加路径直接写入,即从#include "mymath.h"变成#include "lib/include/mymath.h"但是这样就有点不好,因为我常规使用c语言的头文件的时候都是直接使用#include <stdio.h> 以及#include <stdlib.h>等等,都没有带路径,我用户要使用你这个头文件还要带路径,那么如果我用户要是使用10多个头文件,那我得多麻烦,写很多个路径,所以我用户不想这样通过头文件的名称中加入路径的方式调用头文件,那么又该如何办呢?
第二个方法,gcc -I 路径,即gcc添加选项I,I是大写的i,-l的意思是include,即头文件的意思,在这个选项后面跟上头文件的路径即可,这样gcc在搜索头文件的时候,就回去我们指定的路径下去搜索头文件了 
观察上图,此时我们给gcc使用 I 选项添加上头文件的搜索路径后,此时gcc可以找到头文件#include "mymath.h"了,可是怎么又出现问题了?错误提示在mian函数中找不到Add,Add函数方法未定义,这又改如何理解,此时我们看到下面的错误提示中有一个cc5Aooqk.o 
此时我们应该敏感起来,以.o为后缀的一定是链接错误,其实为什么我们日常在进行c/c++编写,使用c/c++库的方法的时候,使用gcc/g++进行编译形成可执行的时候没有出现过这个链接错误,因为系统中早就已经在特定的系统路径下 /lib64下早已经提前安装好了对应的c/c++的库,所以gcc/g++在进行搜索的时候,就会去指定的系统路径下搜索c/c++的库进行链接,以静态库为例,链接的时候,将main函数中用到的库函数方法从静态库中拷贝到main函数中,这样就链接完成,也不会报错 
但是我们自己提供的第三方库并没有在这个库中,所以gcc去/lib64这个系统路径下自然也没有办法进行链接,如何解决呢?我们可以给gcc类似于头文件一样提供搜索路径,即gcc -L 库文件路径,这个-L选项中的L是lib库的意思,这样使用-L选项gcc就回去指定的路径下去搜索我们的库了 
小编,可是上面的结果为什么还是找不到Add对应的函数实现,无法进行链接呢?gcc,我告诉了你头文件路径,告诉了你静态库的路径,让你去搜索对应的静态库你还是找不到,还是无法链接,逗我呢?是的用户,这样我确实还是找不到对应的静态库,因为你没有告诉我要链接哪一个静态库,因为当前路径下库可能有很多个库,gcc无法确定要链接哪一个。
那么同样的,对于头文件,我也仅仅是告诉了你gcc去哪一个路径下去找,你gcc可以找到对应的头文件,到了静态库这里告诉你gcc去哪一个路径下去找,你却找不到。是的确实找不到,因为对于头文件,其实你是告诉了我gcc要找哪一个头文件,因为你用户包的头文件就是我gcc要找的头文件,但是目前用户却没有告诉我要在你用户指定的路径下去找哪一个静态库 
所以此时作为用户,我们不光应该使用-L选项告诉gcc去哪一个路径下去找静态库,同时还应该使用-l选项(这里的l是小写的l)告诉gcc去找哪一个静态库,以libXXX.a为例,那么静态库的真实名称是XXX,并且使用-l选项的时候,一般将要搜索的库名称和-l放在一起,即-lXXX这种形式,所以我们再使用-l选项告诉gcc去找哪一个静态库,看gcc是否可以找到静态库并链接形成可执行 
如上,历经千辛万苦,终于是让gcc找到了对应的头文件,以及静态库进行链接形成可执行,此时我们执行可执行,运行成功,使用成功了我们提供的库函数方法
小编可是你这种形式gcc -I ./lib/include main.c -L ./lib/mymathlib -lmymath 形成可执行未免也太过长了,我作为用户在命令行中想要简洁一点,不想使用这种方法,有其它的方法吗?有的
直接将我们提供的头文件安装在系统的头文件路径/usr/include下,将我们提供的静态库安装在系统的库路径/bin64 下,由于是向系统路径中进行写入,并且我们使用的是普通用户,所以需要sudo提权才能以普通用户的身份向系统级路径下进行写入安装
这样就可以在命令行中不带搜索头文件以及静态库的搜索路径了,因为gcc会去系统的头文件路径/usr/include下以及系统的库路径/bin64 下去进行搜索,此时我们已经将我们提供的头文件以及静态库安装在了系统的路径下,所以gcc自然可以搜索到,但是由于系统的库路径下存在很多库,同样的gcc并不知道要搜索链接哪一个,所以对于库的名称我们仍然需要使用-l(l是小写的l)选项告诉gcc我们要在库路径下搜索链接哪一个库 
所以我们通过拷贝安装的方式,将我们提供的头文件安装在系统的头文件路径/usr/include下,将我们提供的静态库安装在系统的库路径/bin64 下,此时通过,-l(l是小写的l)选项告诉gcc我们要在库路径下搜索链接哪一个库,就可以编译链接形成可执行程序a.out了,此时进行执行无误,但是通常来讲,我们并不会将不成熟的第三方库直接安装在系统的指定路径下,因为不成熟的第三方库可能会对系统特定的路径目录造成污染,但是对于成熟的第三方库我们可以直接安装在系统的特定路径下,所以现在由于小编编写的第三方库仅仅是一个为了配合小编讲解静态库的第三方库,并不成熟,所以下面小编将我们自己的第三方库sudo提权rm卸载一下 
当小编卸载了第三方库之后,此时再去使用gcc main -lmymath自然而然就没有办法找到对应的头文件以及静态库了,因为此时头文件以及静态库已经不在系统的特定目录下了
小编小编,有没有办法可以不拷贝第三方库到系统的特定路径下,而是采用一种链接的方式,有的,我们可以通过软链接的方式将第三方库以链接的形式安装到系统的特定路径下 
所以此时我们通过软链接的方式将第三方库以链接的形式安装到系统的特定路径下,这样同样通过,-l(l是小写的l)选项告诉gcc我们要在库路径下搜索链接哪一个库,就可以编译链接形成可执行程序a.out了,此时进行执行无误
同样的由于小编也将软链接文件sudo unlink卸载一下,卸载软链接之后,无法使用gcc main.c -lmymath形成可执行程序了,因为gcc进行搜索的时候,无法在系统的特定路径下找到对应的头文件以及静态库了 
那么接下来我们测试一下除零错误处理
#include "mymath.h"
int main()
{
printf("5 / 0 = %d, errno = %d\\n", Div(5, 0), myerrno);
return 0;
}
运行结果如下
奇怪,小编明明使用的是我们自己的除数Div方法,此时进行了除零错误,应该将myerrno设置为1,表示出现除零错误,可是这里为什么errno仍然是0呢?
#include "mymath.h"
int main()
{
int ret = Div(5, 0);
printf("5 / 0 = %d, errno = %d\\n", ret, myerrno);
return 0;
}
运行结果如下
所以此时除零错误返回-1,表示结果出错,但是如果没有显示的打印出5 / 0,此时我们就无法区分这个结果-1究竟是正确结果还是出错返回的-1,所以类似的我们就提供了一个全局变量myerrno,当myerrno不为0的时候用于表征出现错误,myerrno具体是哪一个数字表示出错的原因
总结
以上就是今天的博客内容啦,希望对读者朋友们有帮助 水滴石穿,坚持就是胜利,读者朋友们可以点个关注 点赞收藏加关注,找到小编不迷路!





