一、库文件的概念
库是一组预先编译好的方法(.o文件)的集合。Linux系统存储的库的位置一般在:/lib 和 /usr/lib。
在 64 位的系统上有些库也可能被存储在/usr/lib64 下。库的头文件一般会被存储在/usr/include 下或其子目录下。
库有两种,一种是静态库,其命令规则为libxxx.a,一种是共享库,其命令规则为libxxx.so。
二、静态库和共享库
如果静态库和共享库同时存在,会优先选择使用共享库。
1.静态库的使用方法
直接把所要用到的静态库中方法的实现包含到一个可执行程序main中。
【例】
假如现在自己实现了两个方法add和max,这两个实现就在一个静态库文件中,假设这个库文件名为libfoo.a,然后自己写了一个程序main.c,在main.c中调用了add方法,首先要将main.c编译为main.o二进制指令文件。接下来到了链接的步骤,链接的时候,不止用到了存放自己实现的方法的库libfoo.a,把libfoo.a静态库中的方法拷贝一份用来链接。还会用到一些其他的库,其一,在执行主函数之前,我们需要执行一些代码,这些代码是直接从一些.o文件中链接过来的,在这些代码中才会调用主函数main程序,所以,我们自己要实现一个main的方法作为一个入口。其二,比如printf实现的方法所在的C库等一些标准库也需要链接。最终生成的可执行程序main就包括自己编写的.c文件和链接过来的库中的方法。
2.共享库的使用方法
只是标记共享库中使用到的方法,并不会把共享库中的方法的实现包含在一个可执行程序main中。
【例】
假如现在自己实现了两个方法add和max,这两个实现就在一个静态库文件中,假设这个库文件名为libfoo.so,然后自己写了一个程序main.c,在main.c中调用了add方法,首先要将main.c编译为main.o二进制指令文件。接下来到了链接的步骤,链接的时候,其一,在主函数执行之前会执行一部分代码,这些代码从一些.o文件中链接过来,其二,我们会把像C库这样的标准库链接过来,其三,标记用到共享库中的add方法。
现在有一个简单的main程序:
查看这个main程序的共享库,发现C库会默认链接,libc.so就是C库:
3.静态库和共享库的优缺点
(1)静态库
优点:
把所用到的库中的方法的实现都包含到自己的可执行程序中,它已经成为可执行程序的一部分了,运行的时候也不会去寻找所用到的库,把这个库删掉也没有影响。把所用到的库都包含到自己的可执行程序中,无论这个环境中有没有相应的库程序都可以执行。
缺点:
①所占内存大;
②库的更新不方便,在更新库的时候必须得重新编译程序。
(2)共享库
优点:
①所占内存小;
②库的更新非常方便,直接用新库覆盖旧库就可以了
缺点:
没有包含,要在运行的时候去寻找所要用到的库,要动态链接相应的库,所以在这个执行该程序的计算机上必须存在需要用到的所有共享库,一旦相应的库不存在,程序就无法运行。
三、静态库的生成和使用
头文件都在/usr/include
库文件都在/usr/lib
或者/lib
可执行程序都在/usr/bin
或者/bin
1.生成一个静态库的步骤:
示例:目前有一个add.c和max.c文件,add.c和max.c都被声明在一个头文件foo.h中:
(1)第一步,将所有的.c文件编译为.o文件:
(2)第二步,把.o文件打包到一个库中,使用ar命令将第一步编译的所有”.o”文件生成静态库
以下把add.o max.o
文件生成了一个静态库libfoo.a
:
对于ar crv libfoo.a add.o max.o
中的
ar
是一个命令
crv
中的:
c是创建库
r是将方法添加到库中
v显示过程
libfoo.a
是所创建的库名
add.o max.o
是将要打包到库中的.o文件
2.静态库的使用
(1)先建立一个目录liba
把头文件foo.h和静态库libfoo.a都拷贝到该目录下:
(2)创建一个main.c文件,写测试代码
(3)生成可执行文件并运行
①直接编译main.c文件(失败)
原因:该目录下没有add方法的实现。
②生成main.o文件后再编译main.c文件(失败)
失败原因:在gcc -o main main.o
链接时找不到add方法
③链接的时候指定静态库生成可执行文件(成功)
④直接通过main.c和静态库生成可执行文件(成功)
编译语句gcc -o main main.c -L -lfoo
中的
-L
:指定库的存储路径
-l
:指定库的名称(不需要前面的‘lib’和扩展名‘.a’)。
如果库在标准库中,那么在编译时就不需要指定该库的路径。
(4)删除静态库libfoo.a之后,可执行文件main仍然可以运行
四、共享库的生成和使用
1.共享库的生成
1.生成一个共享库的步骤:
示例:目前有一个add.c和max.c文件,add.c和max.c都被声明在一个头文件foo.h中:
(1)第一步,将所有的.c文件编译为.o文件
(2)第二步,把.o文件打包到一个库中,使用gcc命令将第一步编译的所有".o"文件生成共享库
生成共享库的命令gcc -shared -fPIC -o libfoo.so add.o max.o
中的:
gcc
代表命令
-shared
代表生成的是共享库
-fPIC
代表代码位置无关
-o
表示输出
libfoo.so
是生成的共享库的名称
add.o max.o
是将要打包到库中的.o文件
2.共享库的使用
(1)先建立一个目录liba
把共享库libfoo.so和头文件foo.h都移到liba中:
(2)创建一个main.c文件,写测试代码
(3)生成可执行文件
①直接编译生成可执行文件(失败)
失败原因:找不到add方法的实现,main.c中没有add方法的实现
②使用共享库“libfoo.so”和“main.c”生成可执行文件(成功)
在编译语句gcc -o main main.c -L. -lfoo
中:
-L
:指定库的存储路径
-l
:指定库的名称(不需要前面的‘lib’和扩展名‘.so’)
如果在库的存储路径有同名的共享库和静态库,gcc默认使用共享库。
(4)运行(失败)
失败原因分析:
首先,查看main程序用到了那些库:
发现libfoo.so没有找到,这是因为在运行的时候寻找库的时候只会去标准目录中寻找,gcc -o main main.c -L. -lfoo
中指定的路径是告诉gcc在编译的时候去这个路径寻找需要的库。
解决办法:
①通过一些环境变量来指定main程序在加载库的时候在当前的目录下去寻找所需要的库
先设置变量”LD_LIBRARY_PATH”为当前路径,此时仍然会运行失败:
然后将变量”LD_LIBRARY_PATH”设置为环境变量就可以运行成功:
②把所需要用到的库放到标准目录下(管理员模式下操作)
【注意】如果把动态库移到标准目录下,并且设置了环境变量,那么会优先选择环境变量来找到库的位置。
这时候发现libfoo.so被找到了,此时就可以运行main程序了:
(5)删除共享库libfoo.b之后,可执行文件main就不可以运行了