动静态库的基本概念
- 静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库
- 动态库(.so):程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文件的整个机器码
- 在可执行文件开始运行以前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中,这个过程称为动态链接(dynamic linking)
- 动态库可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘空间。操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间
静态库的制作与使用
创建add.c add.h sub.c sub.h ,函数定义放在.c 文件中,声明放在.h文件中。
add.c add.h sub.c sub.h 内容如下:
int add(int a,int b)
{
return a+b;
}
#pragma once
extern int add(int a ,int b);
int sub(int a,int b)
{
return a-b;
}
#pragma once
extern int sub(int a,int b);
打包
有了上面4个源文件和头文件,我们现在生成一个静态库。
第一步:让所有源文件(.c文件)生成目标文件
gcc -c add.c
gcc -c sub.c
当前目录文件:
add.c add.h sub.c sub.h add.o sub.o
第二步:使用ar命令将所有目标文件打包为静态库
ar 命令是gnu的归档工具,常用于将目标文件打包为静态库,下面我们使用ar 命令的-r 选项和-c 选项进行打包。
-r (replace):若静态库文件当中的目标文件有更新,则用新的目标文件替换旧的目标文件。-c (create):建立静态库文件。
ar -rc libcal.a add.o sub.o
当前目录文件:
add.c add.h sub.c sub.h add.o sub.o libcal.a
此外,我们可以用ar 命令的-t 选项和-v 选项查看静态库当中的文件。
-t :列出静态库中的文件。-v (verbose):显示详细的信息。
ar -tv libcal.a
第三步:将所有的头文件和静态库封装起来,目的为了给其他使用
mkdir -p mlib/include
mkdir -p mlib/lib
cp ./*.h mlib/include
cp ./*.so mlib/lib
mlib目录的tree结构
mlib
|---include
| -- add.h
| -- sub.h
|---lib
| -- libcal.a
使用makefile
如果你看不懂makefile
我们可以把上述的命令通过makefile的语法转换写到makefile文件里,通过make搭配的指令,生成静态库,封装静态库和头文件可以一步到位。
1 mylib=libcal.a
2 CC=gcc
3
4 %.o:%.c
5 $(CC) -c $<
6
7 $(mylib):add.o sub.o
8 ar -rc -o $(mylib) $^
9 .PHONY:clean
10 clean:
11 rm -rf ./*.o ./*.a
12
13 .PHONY:output
14 output:
15 mkdir -p mlib/include
16 mkdir -p mlib/lib
17 cp ./*.h mlib/include
18 cp ./*.a mlib/lib
1.生成静态库
make
2.封装
make output
3.清理
make clean
是不是很简单!
使用
假如你的朋友要使用你的静态库,假如你的朋友就是friend目录
mkdir friend
现在你要把静态库的包给你的朋友
cp mlib friend -r
现在你的朋友要使用一下你的库,你的朋友创建里一个main.c
touch main.c
#include<stdio.h>
#include"add.h"
#include"sub.h"
int main()
{
int a=10,b=11;
printf("a+b=%d\n",add(a,b));
return 0;
}
你的朋友写好main.c 了,
现在如何编译生成可执行文件?
第一步:gcc
此时使用gcc编译main.c生成可执行程序时需要携带三个选项:
-I :指定头文件搜索路径。-L :指定库文件搜索路径。-l :指明需要链接库文件路径下的哪一个库。(库名规则:libxxx.so )
gcc main.c -I./mlib/include -L./mlib/lib -lcal
此时生成的a.out即可使用;
动态库的制作与使用
打包
- shared: 表示生成共享库格式
- fPIC:产生位置无关码(position independent code)
- 库名规则:libxxx.so
过程如下:
当前目录文件:
add.c add.h sub.c sub.h
第一步:让所有的.c 文件生成 .o目标文件
在生成 ,需要加上-fPIC 选项;
gcc -fPIC -c add.c
gcc -fPIC -c sub.c
生成目标文件后,当前目录文件
add.c add.h add.o sub.c sub.h sub.o
关于-fPIC
第二步:使用-shared 选项将所有生成的目标文件进行打包为动态库
gcc -shared -o libcal.so add.o sub.o
生成库后,当前目录文件
add.c add.h add.o sub.c sub.h sub.o libcal.so
第三步:将头文件和动态cal 放到一个目标里
目的:为了方便给其他人用
mkdir -p mlib/include
mkdir -p mlib/lib
cp ./*.h mlib/include
cp ./*.so mlib/lib
生成目标后,当前目录文件
add.c add.h add.o sub.c sub.h sub.o libcal.so mlib
mlib目录包
mlib
|---include
| -- add.h
| -- sub.h
|---lib
| -- libcal.so
使用 makefile 生成
如果你看不懂makefile
1 mylib=libcal.so
2 CC=gcc
3
4 %.o:%.c
5 $(CC) -fPIC -c $<
6
7 $(mylib):add.o sub.o
8 $(CC) -shared -o $(mylib) $^
9 .PHONY:clean
10 clean:
11 rm -rf ./*.o ./*.so
12
13 .PHONY:output
14 output:
15 mkdir -p mlib/include
16 mkdir -p mlib/lib
17 cp ./*.h mlib/include
18 cp ./*.so mlib/lib
使用
现在我把mlib目录给我的朋友friend
mkdir friend
cp mlib friend -r
当前friend 目录文件:
mlib
现在我的朋友要使用我的库mlib
第一步:编写源文件main
写一个main.c 源文件
#include <stdio.h>
#include <add.h>
int main()
{
int x = 20;
int y = 10;
printf("%d + %d = %d\n", x, y, add(x, y));
printf("%d - %d = %d\n", x, y, sub(x, y));
return 0;
}
当前friend 目录文件:
mlib main.c
第二步:编译 main.c 生成可执行文件
gcc main.c -I./mlib/include -L./mlib/lib -lcal
此时使用gcc编译main.c生成可执行程序时,需要用-I 选项指定头文件搜索路径,用-L 选项指定库文件搜索路径,最后用-l 选项指明需要链接库文件路径下的哪一个库,只要库名即可(去掉lib以及版本号) 。
当前friend 目录文件:
mlib main.c a.out
与静态库的使用不同的是,此时我们生成的可执行程序a.out并不能直接运行。
需要注意的是,我们使用-I ,-L ,-l 这三个选项都是在编译期间告诉编译器我们使用的头文件和库文件在哪里以及是谁,但是当生成的可执行程序生成后就与编译器没有关系了,此后该可执行程序运行起来后,操作系统找不到该可执行程序所依赖的动态库,我们可以使用ldd 命令进行查看。
ldd a.out
显示部分如下:
libcal.so => not found
可执行程序没有找到依赖的动态库。
解决方案:
f1、拷贝.so文件到系统共享库路径下, 一般指/usr/lib
sudo cp mlib/lib/libcal.so /lib64
f2、更改 LD_LIBRARY_PATH
LD_LIBRARY_PATH 是程序运行动态查找库时所要搜索的路径,我们只需将动态库所在的目录路径添加到LD_LIBRARY_PATH 环境变量当中即可。
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/hoeme/linux_-lerning/lesson9/friend/mlib/lib
f3、ldconfig 配置/etc/ld.so.conf.d/,ldconfig更新
1.创建一个以.conf后缀的文件
touch my.conf
2.把库路径写入my.conf
echo /hoeme/linux_-lerning/lesson9/friend/mlib/lib >my.conf
3.把my.conf 拷贝到 /etc/ld.so.conf.d/
cp my.conf /etc/ld.so.conf.d/
4.更新一下配置文件
sudo ldconfig
Y_PATH=$LD_LIBRARY_PATH:/hoeme/linux_-lerning/lesson9/friend/mlib/lib
f3、ldconfig 配置/etc/ld.so.conf.d/,ldconfig更新
1.创建一个以.conf后缀的文件
touch my.conf
2.把库路径写入my.conf
echo /hoeme/linux_-lerning/lesson9/friend/mlib/lib >my.conf
3.把my.conf 拷贝到 /etc/ld.so.conf.d/
cp my.conf /etc/ld.so.conf.d/
4.更新一下配置文件
sudo ldconfig
然后就可以运行 a.out了-------
|