1. 静态函数库
这类库的名字一般是libxxx.a;利用静态函数库编译成的文件比较大,因为整个 函数库的所有数据都会被整合进目标代码中,他的优点就显而易见了,即编译后的执行程序不需要外部的函数库支持,因为所有使用的函数都已经被编译进去了。当然这也会成为他的缺点,因为如果静态函数库改变了,那么你的程序必须重新编译。
2. 动态函数库
这类库的名字一般是libxxx.so;相对于静态函数库,动态函数库在编译的时候 并没有被编译进目标代码中,你的程序执行到相关函数时才调用该函数库里的相应函数,因此动态函数库所产生的可执行文件比较小。由于函数库没有被整合进你的程序,而是程序运行时动态的申请并调用,所以程序的运行环境中必须提供相应的库。动态函数库的改变并不影响你的程序,所以动态函数库的升级比较方便。
linux系统有几个重要的目录存放相应的函数库,如/lib /usr/lib。
编译静态库和动态库 :
无论是静态库还是动态库 ,都是由.o文件组成。因此我们可以先编译出.o文件 。
下面提供两个小程序 :
sum.h #ifndef SUM_H_ #define SUM_H_ int add (int ,int ) ; #endif
sum.cpp #include <iostream> #include "auth.h" int add (int x ,int y ) { int sum = x + y ; return sum ; }
#include "sum.h" #include<iostream> int main() { int k = add(8,10); std::cout<<"k= "<< k<<std::endl; return 0 ; }
首先编译.o文件:
g++ -c sum.cpp ------>生成.o文件
编译.so 文件 :
g++ -shared -fPIC -o libsum.so sum.o ------>生成libsum.so文件
编译.a 文件 :
ar rcs libsum.a sum.o - ----> 生成libsum.a 文件
编译测试文件并测试 :
g++ -c test.cpp
g++ -o test test.o -lauth -L./
ok,测试结果显示k = 18 ;
然而 在linux64位的系统中,这个问题就出来了 。
如果依然按照上面的命令进行编译 ,会出现以下错误 :
/usr/bin/ld: sum.o: relocation R_X86_64_32 against `a local symbol' can not be used when making a shared object; recompile with -fPIC
auth.o: could not read symbols: Bad value。
auth.o: could not read symbols: Bad value。
碰到这个错误 ,你可以去检查下,对应的文件在编译的时候是不是用了-fPIC这个参数哦 。
-fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。
在生成.o文件的时候 加上参数 -fPIC ,这个错误就可以搞定了 ,在编译动态库时,必须指定这个参数 ,主要是因为代码的重定向的问题 。如果没有这个参数 ,编译的代码加载的时候不能够重定向。
g++ -fPIC -c sum.cpp
那么,如果我希望指定执行文件链接静态库怎么办呢 ??
默认情况下,如果在某个目录下.so 和.a 同时存在的时 ,gcc会优先选择.so 。
我们一般通过 -I引入包含文件 ,-L引入库目录 ,-l指定依赖的库文件。当在静态库和动态库同时存在时,gcc选择.so ,如果你在能够将.
so和.a分开的情况下 ,使用-lname (name为lib的名字)来指定库文件(无论静态库还是动态库都可以),如果静态库和动态库在同一目录下 ,可以使用 path/libname.a 来指定依赖的库文件 。
Linux下约定所有库都以前缀lib开始静态库以.a结尾,动态库以.so结尾。再编译程式时,无需带上前缀和后缀。
在编译过程中,-L指定的路径是编译路径 ,而在运行时需要动态的搜索库文件 ,这两个路径不是一个概念 。因此经常会出现这样的问题 :
”明明已经将库的头文件所在目录 通过 “-I” include进来了,库所在文件通过“-L”参数引导,并指定了“-l”的库名,但通过ldd命令察看时,就是死活找不到你指定链接的so文件,这时你 要作的就是通过修改LD_LIBRARY_PATH或者/etc/ld.so.conf文件来指定动态库的目录。通常这样做就可以解决库无法链接的问题 了。