Linux 中 动态库和静态库编译和使用
为了更好的表述,这里写了一个简单的示例代码 示例代码 源代码链接
代码目录结构为:
.
├── hello # 写的一个hello示例库
│ ├── hello.c
│ ├── include
│ │ └── hello.h
│ └── makefile
├── main.c # 使用main函数去使用上面的库
└── makefile
其中 hello.c内容:
#include "include/hello.h"
void say_hello(char * name){
printf("Hello, %s!\n", name);
}
其中 hello.h内容:
#include<stdio.h>
void say_hello(char *name);
其中 main.h内容:
#include<hello.h>
int main(){
say_hello("Tom");
}
静态库编译
切换目的到hello, 执行一下命令可生成静态库
gcc -c -o hello.o hello.c -fpic # 编译源文件hello.c 到目标文件hello.o
ar -rc libhello.a hello.o # ar 打包成一个静态库
其中gcc的 -fpic 标志含义是:生成使用相对地址无关的目标代码
注意: 静态库要以lib开头,和.a结束 的方式命名
动态库的编译
切换目的到hello, 执行一下命令可生成动态库
gcc -c -o hello.o hello.c -fpic # 编译源文件hello.c 到目标文件hello.o
gcc -shared -fpic -o libhello.so hello.o # 生成动态库
注意: 动态库要以lib开头,和.so结束 的方式命名
如果你下载我提供的代码,也可以直接使用make编译
静态库的使用
切换目录回到主目录, 编译main.c 并使用刚才编译好的静态库
gcc -c -o main.o main.c -Ihello/include # 这里-Ihello/include 指定头文件查找目录为相对路径hello/include
# 这一定要指定头文件查找目录的,不然找不到main.c中使用的hello.h
gcc -o main_a main.o -Lhello -lhello -static
# 这里 -Lhello 指定库查找目录为相对路径hello
# -lhello 指定需要链接的库为hello, 优先链接libhello.so,如何找不到就链接libhello.a
# -static 指定要链接静态库, 因为hello目录中同时存在静态库和动态库,所以需要特别指定
最后生成 main_a , 可以直接通过 ./main_a
运行
动态库的使用
切换目录回到主目录, 编译main.c 并使用刚才编译好的动态库
gcc -c -o main.o main.c -Ihello/include
gcc -o main_so main.o -Lhello -lhello -Wl,-rpath=./hello
相比使用静态库,使用动态库需要指定的查找目录 -Wl,-rpath=./hello
这里指定的目录,是编译完成的程序运行的时候,去找依赖的动态库的路径,如果你没有指定,程序会
到系统默认的路径去找,如果没有找到会报错(如下)
./main_so: error while loading shared libraries: libhello.so: cannot open shared object file: No such file or directory
最后生成 main_so , 可以直接通过 ./main_so
运行
动态库和静态库的区别
- 链接时不同
静态库链接的时候,会把静态库中自己需要的代码复制到自己的程序里面去。
动态库链接的时候,只会检查一下动态库只是否有自己程序需要的代码,不会复制。 - 运行时不同
静态库因为链接时已经把相关代码复制进程序了,所以运行时不再依赖静态库。
相反,使用动态的程序在运行时需要去找依赖的动态库,如果找不到会导致无法运行。
静态库优点
- 运行效率高些,无需依赖,简单方便。
动态库的优点
- 节约内存(主要体现在:因为动态库可多个程序共享一份,当多个程序都在使用这个动态库时,内存中只加载一份)
-
节约时间(如果库修改代码,只需要重新编译动态库,然后替换掉原先的库。相反静态库需要编译所有使用这个库的程序)
网友评论