概念

什么是库

库是写好的,现有的,成熟的,可以复用的代码。现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常

本质上来说,库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。库有两种:静态库(.a)和动态库(.so)。

所谓静态、动态是指链接。回顾一下,将一个程序编译成可执行程序的步骤:

静态库

之所以称为静态库,是因为在链接阶段,会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中。因此对应的链接方式称为静态链接。

静态库特点:

  • 静态库对函数库的链接是放在编译时期完成的。

  • 程序在运行时与函数库再无瓜葛,移植方便。

  • 浪费空间和资源,因为所有相关的目标文件与牵涉到的函数库被链接合成一个可执行文件。

动态库

动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入。不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例,规避了空间浪费问题。动态库在程序运行时才被载入,也解决了静态库对程序的更新、部署和发布页会带来麻烦。用户只需要更新动态库即可,增量更新

动态库特点:

  • 动态库把对一些库函数的链接载入推迟到程序运行的时期。

  • 可以实现进程之间的资源共享。(因此动态库也称为共享库)

  • 将一些程序升级变得简单。

  • 甚至可以真正做到链接载入完全由程序员在程序代码中控制(显示调用)。

例程

文件准备

hello.c

#include <stdio.h>

void say_hello(char *name)
{
	printf("Hello %s\n", name);
}

hello.h

#ifndef _HELLO_H
#define _HELLO_H

void say_hello(char *name);

#endif

main.c

#include "hello.h"

int main()
{
	say_hello("hualai");
	return 0;
}

静态库

  1. 将.c文件编译为.o文件,执行:gcc -c hello.c,生成hello.o文件。

  2. 使用ar命令将.o文件打包成静态库。静态库文件名的命名规范是以lib为前缀,紧接着跟静态库名,扩展名为.a。例如:我们将创建的静态库名为hello,则静态库文件名就是libhello.a。执行:ar -crv libhello.a hello.o,生成libhello.a文件。

  3. 执行:gcc main.c -o hello_Hualai -L. -lhello。注意,-L.是指在当前路径下查找静态库;-lhello是指链接libhello.a,gcc会在静态库名前加上前缀lib,然后追加扩展名.a得到的静态库文件名来查找静态库文件。

  • 生成可执行文件hello_Hualai,8368字节,使用ldd hello_Hualai查看文件依赖库:
linux-vdso.so.1 (0x00007ffc987d6000)
	
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc917704000)
	
/lib64/ld-linux-x86-64.so.2 (0x00007fc917cf7000)

这里不会显示静态库的链接。

动态库

  1. 将.c文件编译为.so文件,执行:gcc -shared -fPIC hello.c -o libhello.so,生成libhello.so文件。-fPIC 创建与地址无关的编译程序(pic,position independent code),是为了能够在多个应用程序间共享。-shared是生成动态库的链接器选项。

  2. 将动态库移入系统库文件夹中,执行:sudo cp libhello.so /usr/lib/。如需指定路径,可声明环境变量,export LD_LIBRARY_PATH=

  3. 编译链接动态库的可执行文件,执行:gcc main.c -o hello_Hualai -lhello

  • 生成可执行文件hello_Hualai,8288字节,比静态库要小,使用ldd hello_Hualai查看文件依赖动态库,可以找到libhello.so的链接:
linux-vdso.so.1 (0x00007ffcb9104000)
	
libhello.so => /usr/lib/libhello.so (0x00007f9a903d1000)
	
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9a8ffe0000)
	
/lib64/ld-linux-x86-64.so.2 (0x00007f9a907d5000)

PS.如果想查询动态库实现了哪些接口,可以使用对应工具链的nm工具:

nm xxx.so

如果回复:no symbol:
动态库(elf)有两个符号表,“.symtab”和“.dynsym”。“.dynsym”只保留“.symtab”中的全局符号(global symbols )。命令strip可以去掉elf文件中“.symtab”,但不会去掉“.dynsym”。故而可使用如下命令查看:

nm -D xxx.so
readelf --symbols xxx.so
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐