库
日常编程中,常有一些函数在多个文件中使用(如数据库输入/输出操作或屏幕控制等标准任务函数)。可以事先对这些函数进行编译,然后将它们放置在一些特殊的目标代码文件中,这些目标代码文件就称为库,供其它程序使用(代码的复用)
库文件中的函数可以通过连接程序与应用程序进行链接,这样就不必在每次开发程序时都对这些通用的函数进行编译了。库从本质上来说是一种可执行代码的二进制格式,可以被载入内存中执行。
库分静态库和动态库两种,一般的静态编译即可以理解为加载静态链接库,静态链接库在程序编译时会被链接到目标代码中,程序运行时将不再需要该静态库;动态编译理解为加载动态链接库,在程序运行时才被载入,因此在程序运行时还需要动态库存在。下面分别进行阐述总结
一、Linux下的动态库和动态编译
动态函数库的扩展名一般为(.so),这类函数库通常名为libxxxx .so 。与静态函数库被整个捕捉到程序中不同,动态函数库在编译的时候,在程序里只有一个“指向”的位置而已,也就是说当可执行文件需要使用到函数库的机制时,程序才会去读取函数库来使用;也就是说动态库在可执行程序运行时才载入内存。
一般,在程序第一次执行或者第一次调用的时候,可能会在加载链接库的时候慢点,但这样减少看每个可执行文件的长度, 而且其他的程序如果发现内存中已经存在这个链接库的时候就不需要再次加载了。
另外,动态库链接的时候,它只是保留接口,将动态库与程序代码独立,这样就可以提高代码的可复用度,和降低程序的耦合度,也就是说使用共享库的可以使用库函数来迭代更新,应用程序将无需更改,只要函数的接口不变。
示例
1、使用gcc动态编译printf(“Hello,world”);生成动态链接库myhello
gcc hello.c -fPIC -shared -o libmyhello.so
- -shared:指定生成动态连接库
- -fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的,导致动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。
动态库的名字一般是libxxxx .so,其中xxxx是该lib的名称
2、动态编译main.c,链接myhello动态库,即指明动态链接库为myhello
gcc -o hello main.c -L. -lmyhello
其中-L选项,告诉hello库的位置在当前目录下
3、上面的测试结果可以发现,提示无法找到libmyhello,因为Linux系统默认从/usr/lib中找动态链接库,而该链接库在当前目录,自然找不到。解决这个问题主要有三个途径:
- 可以把当前路径加入 /etc/ld.so.conf中然后运行ldconfig,或者以当前路径为参数运行ldconfig(要有root权限才行)
- 把当前路径加入环境变量LD_LIBRARY_PATH中
- 直接把该动态库复制到usr/lib目录中后运行
ldconfig
更新库
测试中使用的是第三种方式,方便,不容易引起混乱。
二、Linux下的静态库和静态编译
静态函数库一般扩展名为(.a),这类的函数库通常扩展名为libxxx.a 。这类函数库在编译的时候会直接整合到程序中,所以利用静态函数库编译成的文件会比较大,这类函数库最大的优点就是编译成功的可执行文件可以独立运行,而不再需要向外部要求读取函数库的内容;但是从升级难易度来看明显没有优势,如果函数库更新,需要重新编译。
示例
1、编译.c文件为.o文件gcc -c hello.c
2、把目标文件归档ar -r libmyhello.a hello.o
程序 ar 配合参数 -r 创建一个新库 libmyhello.a ,并将hello.o插入。如果库不存在的话,参数 -r 将创建一个新的库,而如果库存在的话,将用新的模块替换原来的模块。
3、链接静态库libmyhellogcc -o test main.c -L. -lmyhello -static
-L与动态链接命令中的一致,指明动态链接库在当前目录中,注意命令尾部还有一个-static说明,表明是静态编译。
4、直接运行可执行文件test
三、静态编译相关静态库的安装
1、先直接静态编译,看能否成功。
2、如果不成功,则先动态编译,生成可执行文件
3、ldd 可执行文件名
命令查看该可执行文件依赖哪些动态库
4、找到缺失的动态库,使用rpm -qf
查看该文件对应的包
5、使用yum search
搜索该缺失的包对应的库文件6、根据描述选择相应的静态库更新安装
7、完成上述步骤后重新进行回到步骤1,直到静态编译成功为止