以Linux平台为基准进行分析
基本概念:
首先我们知道,在windows平台和linux平台下都大量存在着库。库中存着的就是我们需要使用的代码。
本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。
由于windows和linux的本质不同,因此二者库的二进制是不兼容的。通俗的说就是把这些常用函数的目标文件打包在一起,提供相应函数的接口,便于程序员使用。在使用函数时,只需要包对应的头文件即可。按照库的使用方式又可分为动态库和静态库,在不同平台下对应后缀也有所不同。
- WINDOWS下:.dll 后缀为动态库,.lib 后缀为静态库;
- LINUX下:.so后缀为动态库,.a后缀为静态库。
静态库与动态库
两者区别
静态库和动态库中内容都是我们需要的代码,但是两者的使用方式却稍有不同。
对于静态库,程序在编译链接时,将库的代码链接到可执行文件中,程序运行时不再需要静态库。在使用过程中只需要将库和我们的程序编译后的文件链接在一起就可形成一个可执行文件。
由于静态库存在浪费磁盘空间,以及更库文件时过于冗余,于是引出动态库,
动态链接是把程序按照模块拆分成各个相对独立部分,在程序运行时才将他们链接在一起形成一个完整的程序 而不是像静态链接那样把所有的程序模块都链接成一个单独的可执行文件。所以动态链接是将链接过程推迟到了运行时才进行。
这就是两者本质区别。
打包方式
比如现在有一个文件叫做 child.c
- 动态库:gcc - c - fPIC child.c -o child.o -> gcc -shared child.o -o libmychild.so
- 静态库:gcc - c child.c -o child.o -> ar -cr libmychild.a child.o
对动态库与静态库第一段代码进行解析:
使用gcc将源文件编译汇编成目标文件,但是动态库多了一个fPIC,关于fPIC简单说一下,其实就是生成位置无关代码的意思,避免我们使用的时候不受不同虚拟内存地址和代码指令地址之间冲突。
对动态库与静态库第二段代码进行解析:
动态库的要使用shared,生成的库以lib开头以.so结尾。
静态库使用ar -cr,lib开头以.a结尾。
使用方式
动态库的使用方式:
ldd 文件名 可以查看文件依赖的动态库
动态库要使用有两次操作,生成可执行程序时链接使用,运行可执行程序时加载使用。
比如我们使用main.c时要使用上面打包好的静态库和动态库。
生成可执行程序时链接使用:gcc main.c -o main -lmychild -l用于指定库名称
- 将库文件放到指定路径下 – /usr/lib64 /usr/lib
- 设置连接库的搜索路径环境变量,将当前文件的路径添加进去 export LIBRARY_PATH=$LIBRARY_PATH:.
- gcc -L选项指定库的搜索路径,gcc main.c -o main -L./ -lmychild
运行可执行程序时加载使用:动态库的特有动作。
- 将库文件放到指定路径下 – /usr/lib64 /usr/lib
- 设置加载库的搜索路径环境变量,将当前文件的路径添加进去 export LD_LIBRARY_PATH=$LD_IBRARY_PATH:.
只有我们在使用链接的第三种方式的时候才需要设置加载库时的路径。
静态库的使用只存在链接:
- 将静态库放在指定路径下,使用-L选项指定位置,gcc main.c -o main -L./ -lmychild
- 对于所有的库都使用静态链接 gcc -static main.c -o main -L./ -lmychild