现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始。尽量不重复做别人已经做过的事,“站在巨人的肩膀上”做事情。
根据链接时期的不同,库又有:静态库和共享库(动态库)。
二者的不同点在于代码被载入的时刻不同, 静态库的代码在编译过程中已经被载入可执行程序,因此体积较大。共享库的代码是在可执行程序运行时才载入内存的,在编译过程中仅简单的引用,因此代码体积较小。
一般gcc在编译的时候默认使用动态库,可以直接添加-static强制使用静态库。
静态库的名字一般是libxxx.a(Linux).
动态库的名字一般是libxxx.so(Linux),有时候也是 libxxx.so.major.minor,xxxx是该lib的名称,major是主版本号, minor是副版本号。
1 file命令
file程序是用来判断文件类型的,并且可以查看文件是否使用了动态库。
where@ubuntu:~$ file /bin/ls /bin/ls: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=de9c5af34773e23cf554e0da78320e76a3b85120, stripped
2 ldd命令
ldd是英文List dynamic dependencies的缩写,用来查看动态库,如果目标程序没有链接动态库,则打印“not a dynamic executable” (不是动态可执行文件)
where@ubuntu:~$ ldd /bin/ls Linux-gate.so.1 => (0xb7765000) libseLinux.so.1 => /lib/i386-Linux-gnu/libseLinux.so.1 (0xb772a000) libacl.so.1 => /lib/i386-Linux-gnu/libacl.so.1 (0xb7721000) libc.so.6 => /lib/i386-Linux-gnu/libc.so.6 (0xb7572000) libpcre.so.3 => /lib/i386-Linux-gnu/libpcre.so.3 (0xb7534000) libdl.so.2 => /lib/i386-Linux-gnu/libdl.so.2 (0xb752f000) /lib/ld-Linux.so.2 (0x800d3000) libattr.so.1 => /lib/i386-Linux-gnu/libattr.so.1 (0xb7529000)
3 编译动态库
编写mylib.h
int test();
编写mylib.c
int test() { printf("mytest\n"); }
编译成mylib.o文件
gcc -fPIC -c mylib.c
-fPIC 作用于编译阶段,告诉编译器产生与位置无关代码(Position-Independent Code), 则产生的代码中,没有绝对地址,全部使用相对地址,故而代码可以被加载器加载到内存的任意 位置,都可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的。
链接成动态库libmy.so
gcc -shared mylib.o -o libmy.so
编译跟链接一起执行
gcc -shared -fPIC mylib.c -o libmy.so
4 调用动态库
调用动态库,编写调用代码test.c
int main() { test(); return 0; }
编译时带上库路径
gcc -o test test.c libmy.so
或者指定链接路径
gcc -o test test.c -L./ -lmy
设置环境变量LIBRARY_PATH
export LIBRARY_PATH=$LIBRARY_PATH/homw/where/lib #/home/where为我当前库路径 gcc -o test test.c -lmy
或者把库拷贝到系统库路径中
mv libmy.so /usr/lib #或者 /lib /usr/local/lib gcc -o test test.c -lmy
gcc默认查找动态的顺序:
1、-L参数指定的路径 2、LIBRARY_PATH环境变量指明库搜索路径 3、gcc内定库/lib、/usr/lib、/usr/local/lib
5 头文件引用
gcc test.c -o test -lmy
指定包含的文件路径
gcc test.c -o test -I./
修改C_INCLUDE_PATH
export C_INCLUDE_PATH=$C_INCLUDE_PATH:/home/where/lib gcc test.c -o test
gcc默认查找头文件的顺序
1、当前编译路径 2、-I 指定的路径 3、C_INCLUDE_PATH,CPLUS_INCLUDE_PATH环境变量等路径 4、再找系统内定目录如/usr/include、/usr/local/include
6运行时库查找
1、在配置文件/etc/ld.so.conf中指定动态库搜索路径
sudo vi /etc/ld.so.conf.d/mylib.conf #新建mylib.conf写入你自己的库路径,如/home/where/lib sudo ldconfig #更新一下缓存才能生效
2、通过环境变量LD_LIBRARY_PATH指定动态库搜索路径
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/where/lib
3、默认的动态库搜索路径/lib、/usr/lib
7 编译静态库
编写mylib.h
int test();
编写mylib.c
int test() { printf("mytest\n"); }
编译成mylib.o文件
gcc -c mylib.c
使用ar生成静态库
ar rcs libmy.a mylib.o
参数r:#在库中插入模块(替换)。当插入的模块名已经在库中存在,则替换同名的模块。如果若干模块中有一个模块在库中不存在,ar显示一个错误消息,并不替换其他同名模块。默认的情况下,新的成员增加在库的结尾处,可以使用其他任选项来改变增加的位置。 参数c:#创建一个库。不管库是否存在,都将创建。 参数s:#创建目标文件索引,这在创建较大的库时能加快时间。
8 调用静态库
使用静态库编译
gcc -o test test.c libmy.a
或者
gcc -o test test.c -L. -lmy
在静态动态库都存在的情况,强制使用静态库
gcc -o test test.c -L. -lmy -static