动静态库制作和使用

回顾之前提到过的内容

我们在gcc就讲过动静态库相关的,我们用.a来作为静态库的标识,我们用.so来标识动态库。那么我们静态链接和动态链接分别采用.a和,so。要静态链接必须得.a,要动态链接必须得.so。在Linux下默认是动态链接的!大部分环境里面都是动态链接的。如果你想静态链接,就必须得在gcc/g++选项当中,必须添加-static。
如果你的系统里既有动态库又有静态库,那么默认使用的是.so,如果你强制使用-static链接的就是静态库。换而言之,如果系统只有.so,没有.a你偏要-static那么链接就会报错。
我们说过,我们的云服务器没有安装C语言的静态库和C++静态库,但是有命令可以来安装。 #yum install -y glibc -static;

对哦我们来讲,静态链接和动态链接差别是什么呢?静态链接是你要的库的代码拷贝到你的代码当中;动态链接是把你的代码当中要调用的外部函数地址和你自己的可执行程序调用的地方两个关联起来。说白了就是通过地址来关联,关联之后,我们不用做拷贝,这就是动态链接。我们也验证过动态链接和静态链接,静态链接形成的可执行程序体积会非常大。

1.静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库
2.动态库(.so):程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。
3.一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文件的整个机器码(也就是你程序中有调用外部函数时,它里面写的其实是外部函数的地址,外部函数对应的具体实现还在库里面,当可执行程序运行的时候,外部函数机器码会从磁盘上,动态的加载到内存里。也就是说一个动态库,如果我们多软件是用C语言写的,那么当我们程序在启动的时候,我们程序一定会加载到内存里,当我们实际上运行库的时候,库的代码并没有加载到内存里,没关系当你需要的时候,把库当中的代码load到内存里帮我们去找。换句话说你有10几个C语言写的程序,系统里面动态库只有一份 )
4.在可执行文件开始运行以前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中,这个过程称为动态链接(dynamic linking)
5.动态库可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘空间。操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间。
在这里插入图片描述

设计库的工程师的角度

如何形成静态库

我有一个mymath.h,myprint.h,mymath.c,myprint.c。头文件mymath.h包含了一个我的函数声明,也就是我有一个方法,能帮我们[from,to]累加。
我们现在要制作一个库给别人用,首先面临第一个问题
❓库里面,需不需要main()函数????
答:你敢带main()函数吗?如果你带了,将来用户用库函数时,用户会写main()函数的!一旦编译就出现了main()函数冲突,所以不要带main()函数。

其实呢我们有了源代码就可以给别人用但我就是想要形成库。
接下来怎么形成静态库呢?
我们要形成一个静态库的话,不需要main()函数,只需要对应的头文件和源文件。
我们用的命令呢,首先是用gcc将我们的源文件.c形成我们对应的.o文件,所以用Makefile来帮助我们形成:
mymath.o:mymath.c
gcc -fPIC -c mymath.c -o mymath.o
myprint.o:myprint.c
gcc -fPIC -c myprint.c -o myprint.o
但是呢我们最终不是想形成.o,.o不是我们的目标,我们的目的是要形成一个静态库。

✳️我们不是知道,链接,不就是把所有的.o链接形成一个可执行程序吗!

❓那么如果我把我所有的.o给别人,别人能链接使用吗?
(我已经把我的源文件形成.o了,如果我把我的代码编译一半不去链接,我把每一个源文件编译成.o,那么我把我的.o给别人,别人能直接使用吗?)
那么我们来试试 :我们创建一个test.c里面就包含一下myprint.h(也就是不执行mymath.h的方法,执行,myprint.h方法来测试),该test.c是有main()函数的。我把别人写好的.o拿过来了,我自己呢写了一个test.c,接下来我想把别人的.o跟我的.c形成可执行程序能做到吗?
gcc -c test.c----➡️我先把我自己变成test.o
然后:
gcc my math.o my print.o test.o
最后程序执行成功!所以能形成可执行程序!
所以我把我所有的方法,不给你源文件。将自己所有的源文件编译成.o,把.o给别人,然后你自己写代码吧,然后最后你链接的时候你不用管,你直接把你要调用我方法的test.c也编译成test.o.然后把所有.o链接便形成了可执行程序了!
那么我再链接的时候,其实本质上就是把所有的.o合起来,拷贝合起来,形成一个可执行程序。这就叫做静态链接。
现在我已经知道了,我可以把我的程序编译成.o就能给别人用起来了。但是.o有很多,别人用的特别不方便,所以我打算把所有的.o打包形成一个库!也就是你直接给我.o,如果你源文件里你现在有两源文件,和两头文件 。如果你给我的东西里面。包含了一大堆几百上千源文件,那我就有几百上千的.o了,那么我链接的时候,太麻烦了,万一丢了一个怎么办?
所以我把他们做一个打包就可以了呀!

那怎么打包呢?也就是我们要说的静态库!
✳️ 我们打包用的命令是“ar”命令(归档),用的选项是-rc

✳️库的命名应以lib开头➕自己想定义的名字➕.a
所以在Makefile应这么写:libmymath.a:mymath.o my print.o(也就是说我这个.a依赖的是他两)
解下来就是用打包命令了:
ar -rc libmymath.a mymath.o myprint.o(依赖方法)
所以完整的Makefile如下:

libmymath.a:mymath.o myprint.o
	ar -rc libmymath.a mymath.o myprint.o
mymath.o:mymath.c
	gcc -c mymath.c -o mymath.o
myprint.o:myprint.c
	gcc -c myprint.c -o myprint.o

此后我们make之后,就会形成静态库libmymath.a
所以所谓的静态库本质是,你自己曾经的源文件,最终翻译成.o,把所有的.o打包起来就可以了。那么这就是静态库,
当别人想用我的时候,实际上就是在我的库里面找对应的.o把它拷贝到我们的可执行程序里面就行了。

✳️下面一步就是"发布":
相当于我们已经写了一个小产品,就是libmymath.a这个库,可以被用了。如果你想把你的库给别人用,
你在用库的时候,需要什么东西呢?
少不了:库文件、头文件(所以我们最终给别人做交付的时候,我只要把我的库文件和头文件给别人就行了,就可以形成对应的内容了)

此时我们再打开Makefile,添加:
.PHONY:static
static:
mkdir -p lib-static/lib
mkdir -p lib-static/include
cp *.a lib-static/lib
cp *.h lib-static/include

在Makefile里面添加好后,make一下,先形成我们的.a和.o文件
然后再make static-----➡️此时就有了一个lib-static目录,lib-static有我们的lib目录、include目录,然后所有的.a文件被拷贝到了lib目录下
也就是我此时库里面既有头文件又有所有.o打包后形成的.a

mymath.h
#pragma once
#include <stdio.h>
#include <assert.h>
//[from, to] -> 累加 -> reuslt -> return
extern int addToVal(int from, int to);

mymath.c
#include "mymath.h"
int addToVal(int from, int to)
{
    assert(from <= to);

    int result = 0;
    for( int i = from; i <= to; i++ )
    {
        result += i;
    }

    return result;
}

myprint.h
#pragma once
#include <stdio.h>
#include <time.h>
extern void Print(const char *msg);

myprint.c
#include "myprint.h"
void Print(const char *msg)
{
    printf("%s : %lld\n", msg, (long long)time(NULL));
}  

如何形成动态库

形成动态库原理和静态库基本是一样的。
✳️第一步:形成.o时候,我们是需要用gcc多了一个选项 -fPIC
🌟fPIC:产生位置无关码。将来我编译的源代码内部的两个.c内部的代码(mymath.c和,myprint.c),它们和我们将来程序,把这两份.o文件加载到内存的任意位置,它都可以让我们的程序去执行它。其中呢它采用的是起始地址加偏移量的方式,是一种相对地址的方案。相对地址的方案呢,就可以在内存随意位置去加载访问。
曾经也说过一个程序编译好了,它内部是有地址的,它内部的地址是和我们所对应的,它永远认为我的printf函数相对于代码块的起始偏移量10000字节后就是我函数入口,将来我们.o文件加载到内存任意位置和某个程序关联的时候,都是以函数地址加偏移量访问内容的。
(我们刚刚做静态库的时候,我们把所有要用我方法的源文件,编译成.o,就可以让别人和我们去连接了。也可以理解成此时,所有的程序或者你未来要编译的程序,大家编译时,所采用的地址空间策略是一样的。大家都是在以4GB空间地址单位来对应的排布自己代码和数据的。所以生成的.o以4GB的地址空间方式把自己的程序编号,最后在形成链接的时候,把自己的方法和.o文件拷贝进目标未来生成可执行程序的地址空间对应的范围的某个区域当中就行了。这就是静态库,这种最终形成的代码叫做与位置码有关。也就是说mymath.o和myprint.o不能再内存的任意位置加载,必须得是拷贝进你的程序里面,在你的程序里面以地址空间绝对方案,呈现在进程的层面上,让我们系统去调用,这就是myprit.o和mymath.o采用的与地址有关码。)

第二步:还要再有一个选项 -shared(意思就是形成共享库的格式 )

现在来制作动态库,打开我们的Makefile :
前面已经制作了静态库,可以在其基础上加以改造。
记住所有的库的名称都是"lib"开头,然后动态库的后缀肯定是".so"结尾。
libmymath.so:mymath.o my print.o–(依赖文件)
gcc -shared -o libmymath.so mymath.o myprint.o-----➡️在有了依赖两个.o文件后,➕-shared是告诉编译器生成的动态库libmymath.so要是共享库的格式
mymath.o:mymath.c
gcc -fPIC --c mymath.c -o mymath.o-----➡️在生成.o的方法里➕-fPIC是告诉编译器生成的.o要是与位置无关码
myprint.o:myprint.c
gcc -fPIC -c myprint.c -o myprint.o

然后我们make之后,就形成了libmymath.so这么一个动态库。
我们像静态库一样再进一步的改造动态库,想要让我们的头文件 和 库文件集合在一起。
libmymath.so:mymath.o my print.o
gcc -shared -o libmymath.so mymath.o myprint.o
mymath.o:mymath.c
gcc -fPIC --c mymath.c -o mymath.o
myprint.o:myprint.c
gcc -fPIC -c myprint.c -o myprint.o
.PHONY:dyl
dyl:
mkdir -p lib-dyl/lib
mkdir -p lib-dyl/include
cp *.so lib-dyl/lib
cp *.h lib-dyl/include
.PHONY:clean
rm -rf *.o *.so lib-dyl

好了重新make一下,就会有与位置无关的libmymath.so文件动态库;
再 make dyl就有了lib-dyl的目录,里面还有其他我们创建的目录。
相当于就有了 头文件 和 动态库的集合

✳️再讲产生与位置无关码-fPIC:如果你形成静态库,那么你所形成的.o拷贝到你的程序里;但是动态库本身是你程序加载到内存里,它后续才慢慢加载。库可以是在内存任意位置加载 ,所以库里面代码必须与位置无关。加载到内存任意位置都能被所用到的程序访问到。所以就要有-fPIC

✳️我们再改造一下Makefile,想要一次形成动态库,完了之后又想形成静态库:
.PHONY:all
all:libmymath.so libmymath.a ----➡️也就是我要形成.so 和 .a

libmymath.a:mymath.o myprint.o
ar -rc libmymath.a mymath.o myprint.o
mymath.o:mymath.c
gcc -c mymath.c -o mymath.o
myprint.o:myprint.c
gcc -c myprint.c -o myprint.o
libmymath.so:mymath.o my print.o------➡️将mymath.o改成mymath_s.o不能和生成.a的一样,同理myprint.o下面的也要改哈。
gcc -shared -o libmymath.so mymath.o myprint.o
mymath.o:mymath.c
gcc -fPIC --c mymath.c -o mymath.o
myprint.o:myprint.c
gcc -fPIC -c myprint.c -o myprint.o

.PHONY:lib
lib:
mkdir -p lib-static/lib
mkdir -p lib-static/include
cp *.a lib-static/lib
cp *.h lib-static/include
mkdir -p lib-dyl/lib
mkdir -p lib-dyl/include
cp *.so lib-dyl/lib
cp *.h lib-dyl/include

.PHONY:clean
clean:
rm -rf *.o *.a *.so lib-static lib-dyl

那这样行不行呢?我们来make一下。
发现不行!
原因是我们当前两个源文件都要形成.o,但是我们两个形成.o的格式是不一样的!然后一个是与位置码无关的,另一个是与位置码有关的,一旦形成.o之后呢,我们形成的.o不一样。一旦生成.o后,去编译生成.a它去当前路径下找有没有.o他说有呀,有了之后他会不会再自己编呀?就不会了!所以有问题。那么就改掉一方的名字。
在这里插入图片描述

使用库的人的角度,使用这个库

如何使用静态库.a

假设我们现在给别人就是头文件和库文件。我们先#touch mytest.c,来用用我们的静态库。那我怎么用呢?
首先我怎么知道有哪些方法,你就需要你知道你库里面给你提供有哪些头文件,然后通过了解头文件就能知道有哪些方法了。
我们知道有哪些头文件后,就在我们mytest.c将他们包进来。
但是按我们正常去包#include "./lib-static/include/my math.h"和#include “./lib-static/include/my print.h”,但是这样是不是太low了。我们就那样包#include "my math.h"和#include “myprint.h”。
然后正常往下写代码,调用头文件里面的方法进行编码。
我们把要写的代码写完后。到命令行#gcc mytest.c会发现说找不到头文件#include "mymath.h"和#include “my print.h”.

✳️头文件的搜索路径:""和<> 它们都是怎么找的?
“”:是在当前路径下查找头文件
<>:是在系统头文件路径下查找头文件;(系统的头文件在/usr/include/里面)

首先我们写的mymath.h和my print.h一定不在系统头文件路径下;有人说你当前头文件在当前路径下呀。在吗?不在呀!它应该是在./lib-static/include/这路径下。(./是mytest.c所处的路径哈!)
❓谁在找头文件?编译器:VS2019、gcc—>进程在找;

可现在既不在当前路径下,也不再系统头文件路径下。那怎么办呢?
✳️第一种做法:将自己的头文件和库文件拷贝到系统路径下。----也称“库的安装”
所以我们执行该命令:#sudo cp lib-static/include/* /usr/include/ ----➡️将头文件拷贝到系统头文件路径下
#sudo cp lib-static/lib/* /lib64—➡️将我们的静态库拷贝到系统库文件路径下

然后我们再去gcc mytest.c后,发现还是报错了。这次报的不再是说头文件找不到了,而是说使用的头文件里面的方法没有。而为什么没有呢?
✳️这是一个链接错误!其实,我们之前没用过任何第三方库!(你一直用的是C/C++的库,而gcc/g++默认就认识C/C++库,所以你不用告诉我链哪个库)
但是今天你要链接形成可执行,你必须得告诉我你要链接哪个库!我们已经拷贝了库文件到系统的库文件路径下了,但是gcc/g++不认识这个库,他不是C标准库 。
我们得gcc mytest.c -lmymath(要指明库名,我们也说过了,库名是要去掉前缀lib和后缀.a,剩下的是库名!)----其中是带了选项-l➕mymath(库名。 )
所以我们就指明了要链什么库,必须得手动。因为这是属于第三方的库!
说白了我们写了一个库,写完之后怎么用呢?很简单呀!拷贝到系统库文件路径下,然后后面链接的时候带选项-l➕库名就能用了!
但是现阶段不推荐。因为其一我们可以用其他选项;其二,你写的库不一定很好,能直接放到系统里面给别人用了吗?别人将你的库下载下来,然后你再写一个安装的小脚本,让别人install去拷贝到对应路径下就可以用了。但是你会污染系统的头文件和库。
所以sudo rm -rf /usr/include/mymath.h
	    sudo rm -rf /usr/include/mymath.h
	   sudo rom -rf /usr/lib64/lib-static
	   (就是卸载!)
我们不要对库和系统软件安装感到恐惧!说白了就是拷贝和删除。

✳️gcc -l(指明我要链接的第三库的名称)(是小写l,而不是大写L)

✳️第二种做法:指定路径 头文件搜索路径和库文件搜索路径,使用-I(大写)➕指定头文件搜索路径;用到-L选项:指定你的库的搜索路径
#gcc mytest.c -o mytest -I ./ lib-static/include/(- I(是大写)选项,而不是小写i)
输入这段命令后,发现报错,报的不是头文件找不到了。而是说方法未定义引用,是一个链接错误。所以头文件此时找到了。
我们手动指定头文件搜索路径了,可还是不行呀,可还是报链接错误呀!
这是因为你的库也没有在系统的默认路径下,而是在自定义的路径下。那怎么办呢?
那么我们用到-L选项:指定你的库的搜索路径
#gcc mytest.c -o mytest -I ./ lib-static/include/ -L ./lib-static/lib/
回车之后,看到还是报错!但是已经让我们找到对应的库了。还是报的是方法未定义的链接错误。
你现在是告诉我你的库在此./lib-static/lib/路径下了,但是我们还是要用到选项
选项 -l➕库名(要指明库名,我们也说过了,库名是要去掉前缀lib和后缀.a,剩下的是库名!)
#gcc mytest.c -o mytest -I ./ lib-static/include/ -L ./lib-static/lib/ -lmymath
(所以-l帮我们找到头文件路径,-L帮我们找到库文件路径,-l帮我们在搜索某个库的时候指定哪一个库)
便形成了可执行程序mytest!
在这里插入图片描述

如何使用动态库.so

和静态库一摸一样
怎么做呢?
第一种:把你的库文件和头文件分别拷贝到系统默认的库文件搜索路径和系统默认的头文件搜索路径下。这种用法最简单,但不推荐。

第二种:指定路径 头文件搜索路径和库文件搜索路径,使用-I(大写)➕指定头文件搜索路径;用到-L选项:指定你的库的搜索路径
#gcc mytest.c -o mytest -I lib-dayl/include/ -L lib-day/lib/ -lmymath
便形成了可执行程序mytest!
但是不好意思,报错了!说找不到此libmath.so文件
此时我们#ldd mytest 查看我们可执行程序依赖的库文件。发现它说 libmath.so没有被找到!
你这不是扯蛋吗?我们刚刚编译的时候,都已经全部指定好了的!你怎么还是不认识呀。

请问-I和-L和-l时谁的选项?都是gcc编译器的选项!换句话说,这些选项以及关于,库文件和头文件查找属性本身是告诉gcc你在哪里找头,在哪里找对应的lib,找的是哪一个lib。我gcc已经帮你形成了可执行程序mytest。接下来形成可执行程序之后,和我gcc还有关系吗?没有关系了!
那么和你曾经告诉gcc头文件,库文件和依赖哪一个库有什么关系呢?所以你只是告诉编译器gcc这些,那么我程序一旦./运行起来变成进程了。
但是谁又告诉我进程这个库在哪里呢?没有!
所以在gcc编译的时候告诉,和我程序一旦运行起来找这个库是两码事,是完全不一样的!
换而言之,你的程序在启动的时候,那么你启动时候找不到库呀!只是在你自己定义的路径下,没有在系统默认的路径下。

✳️动态库的运行搜索路径
在这里插入图片描述
上面第一个一堆选项是告诉编译器gcc怎么去找
下面的报错是进程找不到对应的动态库。和我的gcc是无关的。

❓那么静态库的时候为什么没有这个问题呢?
因为静态库在形成可执行程序之后,以及把需要的代码拷贝进我的代码中!运行时,不依赖你的库!—不需要在运行时查找了。

❓为什么动态库会有这个的问题?
我们既然是动态库,那么程序和动态库是分开加载的!
我们曾经讲过task_struct,struct mm_struct,页表、物理内存
地址空间自底向上:代码区、已初始化全局区、未初始化全局 、堆区、栈区。
其中呢我们知道把我们的代码呢经过页表、数据经过页表、各个区域经过页表映射到物理内存的位置,从而能够找到进程的相关位置。
曾经说过栈向下生长,堆向上生长。可是我们从来没讲过堆栈之间是什么鬼呢?
我们形成的动态库libmymath.so(静态库就不说了,它本来就是链接成可执行,就在代码区里面已经编码了)说人话,它本来就是一个文件。
你还有自己的可执行程序,当你要启动你的程序加载到内存的时候,所以系统是帮我们构成PCB,地址空间、页表,然后加载代码和数据帮我们建立映射关系。
可又是动态链接,我的可执行程序里面有一部分代码,是需要跳转到库中运行的!我们自己的代码里面用了动态库,我们和动态库产生了关联,所以库呢在我们自己执行我们的程序时,跳转到库里面运行的。
谁运行呢?是CPU要跑我们的库中的代码,跳转到库里面运行,前提条件是:必须将你的库加载到内存中,其中对我们来讲,加载内存到哪加载?无所谓。
库中所有的代码是与地址无关的地址。所以库加载到内存里随便加载。你用多少加载多少,也不一定把整个都加载进来。
反正我肯定要将库里的加载进来。加载进来我是要让我的进程执行库的代码和我进程自己的代码,库的代码通过已经加载到物理内存再由页表映射到我的进程的地址空间的栈和堆的中间区域(共享区)。
执行库的代码怎么办呢?那就要通过页表将我们对应的库代码映射到我进程地址空间的堆栈之间(共享区)。
所谓执行我进程自己的代码它就在我地址空间代码区,当我需要跳转到库的代码时,那就跳转到共享区去执行。执行完之后,在返回到我们进程的代码区去执行。
我就可以在自己的地址空间中,可以执行所有的代码(自己的和库的)。
此时又创建了一个进程,也有自己的PCB、地址空间、页表,那怎么办?
它也是C语言写的,它的地址空间也使用了库的代码怎么办呢?只要把已经加载到内存的库映射进自己的共享区里面。要执行自己的代码就在代码区找到去执行,要执行库的代码就跳转到共享区去执行库的代码。
所以这个进程也可以在自己的进程地址空间当中去执行所有的代码(自己的和库里的)。
由此再来回答这个问题:
我们既然是动态库,那么程序和动态库是分开加载的!当你形成程序,程序变成进程把你的程序代码加载到内存里,你是不是也要把你的库加载到内存里,然后通过页表映射到你内存中。把磁盘文件的动态库加载到内存,前提条件是进程运行的时候,要动态加载他所需要的库,先找到这个库在哪里呀!所以找不这个库就会报错。
静态库是程序运行之后,库就在程序的代码里面了,不需要说找库了,在自己代码里面找就行了。动态库我们要加载的,你进程得先找到,系统帮我们去找,通过页表建立物理内存和进程地址空间的关系。所以你现在让我找,你得先告诉操作系统你这个库在哪里,系统说我默认知道他在什么路径下,但是没找到,你得告诉我你在哪里。

请添加图片描述
❓所以在系统物理内存里面库需要几份?
对我们来讲这个进程可以去执行我们库代码,那个进程也可以执行我库的代码,他只需要将已经加载到物理内存库代码通过页表映射进自己的地址空间的共享区。
所以整个内存当中只需要有一份就够了。
你可以加载10几20个甚至上百个使用这个库的进程。但对不起,这个库只有一份!
你看如果是静态链接,每个进程都有一份库代码,是不是将库的代码编译到自己的代码中。是不是有几百个进程,就会有几百份库的代码。
所以动态库叫做的shared libraries。因为它可以在运行之间被多个进程所共享,所以叫做共享库!
库也不用全部加载到内存,用多少加载到多少。因为有页表嘛,大不了操作系统通过置换算法,将数据置换出去。

✳️如何解决呢?想办法让进程找到动态库即可!
方法一:动态库拷贝到系统路径下/lib64(其实详细的话是/usr/lib64或者/lib64或/local/lib64,简单就是/lib64)—安装(上面已经讲过了,不推荐!)
方法二:通过导入环境变量的方式,环境变量是LD_LIBRARY_PATH—程序运行的时候,会在环境变量中查找自己需要的动态库路径
(不对呀,我怎么以前没有见过和感受到,那是因为你以前写的程序全部都是用C/C++库,库都是给你安装好了,所以没有感受到。那么今天程序动态运行加载第三方库,这个环境变量是LD_LIBRARY_PATH)
方法三:系统配置文件来做
方法四:其他方法,下面讲:用软链接来查找动态库。

✳️我们来讲讲方法二:
我们可以先来看看环境变量LD_LIBRARY_PATH
#echo KaTeX parse error: Expected 'EOF', got '#' at position 94: …。接下来,导入环境变量: #̲exprot LD_LIBRA… LD_LIBRARY_PATH:➕库文件的绝对路径
然后#echo $LD_LIBRARY_PATH可以看到我的路径已经添加到了里面去了
再#ldd mytest查看当前可执行程序依赖的库文件,可以查看到动态库libmymath.so已经可以在指定的路径下找到了!
但是这个环境变量配置有一点问题,一旦我们将xshell关掉重启,LD_LIBRARY_PATH环境变量里面没有了我们指定的路径。所以命令行式的导入环境变量的方法,只在当前的shell中有效。 退出之后就没了。环境变量这东西当shell启动时是从配置文件里面读的。

✳️来讲讲方法三:通过配置文件来向其表明在哪里进行搜索。
我们系统里面有一个路径:/etc/ld.so.conf.d/,这个路径下呢,它表明的是什么呢?
它表明的是:系统里面如果你自定义了动态库,那么此时我们系统在扫描系统的路径时,除了在系统默认的库文件路径下扫描对应的库之外,还去该路径/etc/ld.so.conf.d/下一个一个去读取配置文件内容,来找到对应的动态库。
这文件看起来好复杂,但实际上非常简单。
我们#sudo touch /etc/ld.so.conf.d/my-104.conf。此时就会在该路径下有我们创建的配置文件my-104.conf了。但是现在是空的怎么办呢?
#sudo vim /etc/ld.so.conf.d/my-104.conf,打开之后,将我们的动态库文件的绝对路径粘贴进去!那么这里面就是保存我们自己写的库所在的绝对路径。
我们#ldd mytest查看当前可执行程序依赖的库文件,但是还是说没有找到libmymath.so动态库。没事,我们只要:
#ldconfig,ldconfig命令是让这个配置文件生效。说人话就是ldconfig命令把我们的my-104.conf配置文件会加载到系统对应的内存空间里;
然后再#ldd mytest查看当前可执行程序依赖的库文件,此时就能找到libmymath.so了!
现在我们甚至关掉xshell再重启也能照样可以运行mytest。
这就是我们所对应的在配置文件当中进行添加路径,添加什么路径?添加库路径,即可让我们程序在运行的时候找到对应的库!

✳️方法四:用软链接来查找动态库。
#sudo ln -s /home/whb/104/phase-104/lesson23/mklib/lib-dyl/lib/libmymath.so /lib64/libmymath.so
此时我们就在系统的路径下/lib64创建了一个软链接libmymath.so指向我们对应的库
我们再#ldd mytest查看当前可执行程序依赖的库文件,便显示可以找到我们的动态库libmymath.so
然后我们再形成的mytest可执行程序也就能跑起来了!
这就是我们用软链接来查找动态库。
我不把我的库拷贝到系统默认的库文件路径下,我建立软链接可以吧!
一旦我们建立了软链接,我们就只要:
#gcc mytest.c -I lib-dyl/include/ -lmymath就能形成可执行程序了。
就不用指明你的库在哪里了。请添加图片描述

推荐安装的第三方库

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值