动态库、静态库
什么是函数库:
库文件是函数的具体实现,库文件是通过目标文件(.o)制作成的,所以库文件是多个目标文件的集合。
生成可执行程序分为四个阶段:预处理、编译(.s)、汇编(.o)、链接
库文件就用于链接阶段。
如果一个项目有多个源程序,会将这些源程序经过编译器生成对应的目标文件(这时就有多个源文件对应的目标文件,即多个.o文件),如果源程序又用到其他人实现的函数,
且这些函数通过库文件(.o文件的集合)提供,最后会将这些.o文件通过链接器生成可执行文件。
静态函数库:
在链接时,链接器会从库文件中提取所需的代码,拷贝到生成的可执行文件中,这样调用一次就要拷贝一次。
优点:因为在连接时已经在可执行文件中包含了要用的代码,所以无需依赖静态库就可执行(移植性强)
缺点:如果程序中多次调用库文件的同一模块,则会拷贝多次该模块的代码,生成的可执行文件就会包含多段完全相同的代码,将造成代码冗余。
动态库:
在链接时,哭文件的内容不会进入到可执行文件中,而是将要调用函数的位置信息记录到文件中,然后生成可执行文件,这样可执行文件就要依赖动态库了优点:可执行文件记录的是要调用函数的地址,真正的实现代码会在程序运行时被载入内存,所以即便是调用了多次同一的模块,使用的都是同一实现代码
缺点:可执行文件不能独立执行,必须依赖对应的动态库(可移植性差)
库文件和头文件的联系:
编译和汇编目的是将一个个源程序汇编成对应的目标程序(即.o程序,这里还不会去调用函数),所以在一个源文件中调用另一个源文件的函数时,如果没有包含那个源文件的头文件,将会有警告:warning: implicit declaration of function ‘xxxx’。所以头文件的作用就体现出来了,就是申明这个函数,告诉这个源程序xxxx函数一定存在,放心使用。
在链接时会明确要使用的库文件和源文件对应的目标文件,这样才能找到具体的函数实现。如果在链接的时候没有指定要用的库文件,将会报错:
undefined reference to 'xxx'
/usr/bin/ld:cannot find -lxxx
xxx.h:No such file or directory
https://blog.csdn.net/high_high/article/details/7193264
http://blog.chinaunix.net/uid-27575921-id-4078661.html
这里就可以引入makefile的使用了。
静态库的制作:
1. gcc cal.c -o cal.o 生成.o文件
2. ar rcs libcalfun.a cal.o 用生成的.o文件生成libcal.a静态库。libcalfun.a就是静态库,库名为calfun
静态库的使用:
gcc main.c -I ../myliclude -lcalfun -L ./ -o main // -I是指定头文件所在的路径,“”是在当前目录下找,没找到就从/usr/include或/usr/local/include下找,
这样都不会找到,因为头文件再上层路径下的myinclude中,所以手动告诉gcc头文件的搜索路径,加-I选项
-l是指定要用的静态库,后面跟库名
-L是告诉链接器从指定的路径下找静态库。默认是从/usr/lib或/usr/local/lib下找
可直接运行可执行文件:./main
动态库的制作:
gcc -share -fpic cal.c -o libcalfun.so 生成libcalfun.so动态库
动态库的使用:
gcc main.c -lcalfun -L ./ -o main 生成可执行文件,但是直接执行./main会报错
解决此错误:
使用命令:export LD_LIBRARY_PATH="动态库所在的路径" //指定main程序在运行时,到LD_LIBRARY_PATH所指定的路径下去找库文件。
这样有个弊端,就是只有运行了这条命令的终端才可以执行可执行程序,如果在新的终端中执行该程序,程序还是会报错。
所以可以在一个脚本文件(main.sh)中写:
export LD_LIBRARY_PATH="动态库所在的路径"
./main
再给这个脚本一个可执行权限,这样就可以执行这个脚本了