库: 就是代码编译出来的一种形式
动态库,静态库
动态库: win系统上的dll文件, lin系统上的so文件.
代码编译成一个独立的库, 不专属于一个程序.任何程序都可以共用这个库. 这个库不管多少程序调用,只要在内存里存在一份就可以了
静态库: win上的lib文件, linux上的.a文件
静态库只能与其它的代码一起编译链接生成一个程序,不能像动态库作为一个独立的库使用. 如果多个程序使用这个静态库,
意味着多个程序里都得包含有这个库的代码.
动态库的优点: 多个程序共用时, 只需加载库的一个副本到内存中即可,
相对于静态库来说节省内存. 改变库里的算法时(函数名不能随便变),不会影响使用此库的程序. 动态库还可以多个版本共存
缺点: 发布程序时,需要连同动态库一起发布
静态库的优点:因静态库是与其它代码一起编译链接成一个程序的,所以发布这个程序时,不需要额外发布这个库
缺点: 多个程序使用时, 每个程序都得包含有这个库的代码, 相对于动态库来说浪费了空间, 并且库升级后, 程序需重新编译
静态库的生成:
1. 写库的功能代码: hello2.c , hello.c, hello.h
头文件里定义类型,声明函数
2. 编译hello2.c, hello.c生成.o文件
gcc hello.c -c -o hello.o -fPIC // -c 指只编译不链接, -o hello.o编译生成hello.o文件, -fPIC指定编译生成的代码是内存地址无关的代码.
gcc hello2.c -c -o hello2.o -fPIC
3. 把所有.o文件打包成一个.a文件
ar -cr libhello.a hello.o hello2.o
///使用静态库:
gcc test.c -lhello -L ./ -I ./ /* -lhello指定使用libhello库, -L指定库所在的目录, -I 指定头文件的所在目录 */
gcc test.c ./libhello.a -I ./ /*也可以这样编译链接*/
动态库生成:
1. 写库的功能代码: hello2.c , hello.c, hello.h
头文件里定义类型,声明函数
2. 把hello2.c, hello.c编译成动态库
gcc hello2.c hello.c -shared -fPIC -o libhello.so -I ./
///使用动态库:
编译时: gcc test.c -I ./ -lhello -L ./
程序执行时,如果报找不到库的错误时的解决方法:
1).可以把库放入下面的目录里
64位系统: /lib64; /usr/lib64; /usr/local/lib64
32位系统: /lib; /usr/lib; /usr/local/lib
2). 配置环境变量
export LD_LIBRARY_PATH=./
再执行程序: ./a.out
3). 配置动态库的加载路径(vim /etc/ld.so.conf)
直接把库的所在路径写到/etc/ld.so.conf文件里
然后更新: ldconfig
4). 编译时直接指定库的所在路径
gcc test.c ./libhello.so -I ./ /*这样,只要库与程序同一目录即可 */
//
用代码来加载动态库.
//dlopen加载filename指定的动态库到内存上, flag指定解析库里函数的地址等行为
void *dlopen(const char *filename, int flag);
用法 void *handle = dlopen("库名", RTLD_LAZY);
//查找库里函数的所在的内存地址. handle为dlopen得到的地址, symbol为函数名.成功则返回函数地址
void *dlsym(void *handle, const char *symbol);
//告诉系统,本进程已不再使用此库. 如果这个库没有其它进程使用,系统会把这个库从内存上去掉
int dlclose(void *handle);
Link with -ldl.
//
注意,如在C++程序里使用C实现的动态库,则需要声明哪些函数是由C代码实现。
因为在C程序里,源程序里的函数名编译完后函数名是不会变的。
在C++程序里,源程序的函数名编译完后会生成的函数名除了原名外还与参数的类型及个数有关.
在C++里声明C动态库里的函数:
extern "C" {
#include <mylib.h>; //包含C实现的动态库头文件
void func(); //声明函数
}