库中是没有main函数的,我们也不能把main函数写入我们的库中。
头文件的查找是在当前目录下或者在系统的指定目录下查找的
但是如果我们像上面那样都进行编译形成可执行程序的话,那么每一个源文件都需要进行预处理、编译、汇编、链接的过程,就会显的很麻烦。但是如果我们把这些源文件进行编译汇编形成.o文件(可重定位目标文件)
对Makefile进行编辑
Test:Add.o Sub.o Mul.o Div.o TestMain.o
gcc -o $@ $^
%.o:%.c
gcc -c $<
.PHONY:clean
clean:
rm -f *.o Test
我们make一下就形成了对应同文件名的.o文件和可执行程序Test
也就是我们将
TestMain.c
形成.o
文件后,将其和.o和.c文件
链接后形成了可执行程序a.out
如果我们将所有的
.o文件
打一个包,将他交给使用者,使用者只需自己写出.c
并且将其编为.o
,然后和打包好的.o
进行链接就可以了。
如果.o文件
过少,我们使用上述gcc
处理还可以,但如果数量上去的话就有些麻烦,所以我们需要制作一个库文件、
ar -rc libmymath.a add.o sub.o
ar是gnu归档工具,rc表示(replace and create)
我们先修改一下Makefile
之后就形成了一个libmymath.a的静态库
静态库,本质就是将库中的源代码直接翻译成为.o目标二进制文件,然后打包
朴素做法
首先我们用上面的一段测试程序
然后我们想使用libmymath.a那个库
但是当前这个目录下没有库,编译都编不过(头文件报错)
对TestMain.c进行编译
我们都把所有东西给他了并且提供了这个库,但是还报错这是因为
gcc默认情况下是不认识第三方库的,虽然提供了,它能看见,但是不认识。
我们可以使用下面的指令
gcc TestMain.c -lmymath -L.
-l指定库名为mymath
-L指定库路径为当前目录下
我们平时所用的C标准库并没有用到 -l , -L选项,是因为gcc认识c标准库的,我们所写的libmymath.a叫做第三方库
查看一下a.out
的依赖库
并没有依赖我们的mymath
原因是因为这些依赖的库都只是动态库,而静态库已经把自己的代码拷贝到可执行程序里面了,没办法查。可执行程序既依赖了动态库,又依赖了静态库可执行程序依赖的库有动态链接的优先动态链接,如果又特定的库只提供静态库那也没办法,会把静态库拷贝到可执行程序,也就是说一个可执行程序依赖的库可以是动静态库混杂的现象。
gcc默认动态链接的,但个别库,如果你只提供a,gcc也没有办法,只能局部性的把你指定的.a,进行静态链接,其他库正常动态链接,如果-static,就必须要,a
用户使用我们的库,总不能发一堆.h和.a
我们应该静态库归静态库,头文件归头文件进行包装,我们再次修改Makefile
make形成对应的.a静态库文件,make output发布,形成了一个mymath_lib的库
将这个库打包
用户下载这个压缩包,解压之后我们就得到了一个库
如何使用???
首先我们需要知道
头文件,默认在/usr/include目录
库文件,默认在/lib64目录
如果我们把库安装到系统里了,我们只需写-l(指明链接的库名称);
动态库的生成
- shared: 表示生成共享库格式
- fPIC:产生位置无关码(position independent code)
- 库名规则:libxxx.so
动态库的生成和静态库是一样的,也是将源文件生成的.o文件
打包形成对应的动态库
gcc编译的时候要对源文件编译时使用的选项不再是ar -rc 了,而是要-fPIC选项(产生位置无关码)。
要将其打包成一个动态库,需要使用-shared,也就是让它生成共享库。
gcc不仅可以形成可执行程序,还可以形成动态库
首先,修改Makefile里的文件
make一下,就形成了一个.so的动态库
报错原因是:加载共享库(libmymath.so)的时候,不能打开这个文件
我们使用编译器的时候,我们所用的-I -lxxx -L
选项就告诉了编译器应该去哪里找这些头文件和库文件
前面使用静态库的时候,它会找到这些文件并且拷贝到可执行程序中,运行的时候就不用再找一遍了;
现在使用动态库的时候,编译时将库文件和头文件搜索路径都告诉了编译器,但当我们编译完成后,该./a.out
运行时程序就与编译器无关了,而是和系统有关可执行程序运行的时候去/lib64/lib
下去找。即使提供了动态库,但是系统并不会去其他目录下查找。
我们可以用以下方式来链接动态库
方法一:直接安装到系统中
两个默认的路径:/lib64和/usr/include中
如果同一组库提供动静态库两种库,gcc编译器默认优先使用动态库
gcc -fPIC xxx.c
上面的fPIC,什么叫做位置无关码?
首先我们需要知道在Linux下,可执行程序是ELF格式的,也就是说通过将源代码编译会形成ELF格式的可执行程序
我们的可执行程序在没有加载到内存的时候,就已经有了虚拟地址对应的概念了,比如说代码区中的A函数去调用B函数时,call后面跟的地址就是A函数的虚拟地址 ,其实我们一般把这样的地址叫做逻辑地址,逻辑地址其实就是基地址+偏移量这样的概念,也就是把0-FFFFFFF理解为:0(基地址)+[0,FFFFFFF](偏移量)
△x
;因为我们的可执行程序加载到内存的时候并不会加载到一个固定的位置,每次进来加载地址都会发生变,采用偏移量的方式来编址,除了起始地址变了,其他的偏移量都没有发生变化,这就是所谓的fPIC(位置无关码)。
在学校的时候,老师只知道计科2201班学生的学号,但并不知道他的宿舍,但是计科2201班的班长知道这个学号对应的宿舍,因为班长有一张表,映射这学号<—>宿舍;
好比,老师要找5号学生,班长一看表,嗯,5#123宿舍,也就是5号<—>5#123宿舍 ;
上面的,老师<—>指令寄存器、那张表<—>页表、学号<—>虚拟地址、宿舍<—>物理地址