🌞1. Linux下静态库和动态库的基本概念
库(Library)是一组预先编写好的程序代码,它们被打包在一起以供其他程序使用,从而避免了重复编写相同的代码。库可以分为静态库和动态库两种类型:
静态库
- 作用:在程序编译的时候,将库编译进可执行程序中, 运行的时候不需要外部函数库
- 目录:默认库目录 /lib 或 /usr/lib 或 /usr/local/lib
- 后缀:libxxx.a
- 命名规范:静态库的名字一般为libxxxx.a,其中 xxxx 是该lib的名称
动态库
- 作用:在程序运行的时候,将库加载到程序中,运行的时候需要外部函数库
- 目录:默认的动态库搜索路径/lib;/usr/lib
- 后缀:libxxx.so
- 命名规范:动态库的名字一般为libxxxx.so.major.minor,xxxx 是该lib的名称,major是主版本号,minor是副版本号
使用库的主要目的是:
- 提高代码的重用性和可维护性
- 减少开发人员的工作量
- 并使程序更加模块化和易于扩展
常见的库包括:
- 标准库(如C标准库和C++标准库)
- 第三方库(如图形界面库、数据库访问库、网络通信库等)
- 自定义的库(根据项目需求编写的特定功能的库)
对.h头文件的理解 传送门:【头文件】对.h文件的理解-CSDN博客
🌞2. 动态库
🌊2.1 动态库如何生成
下面通过一个小栗子介绍如何生成一个动态库。
- 一个头文件: so_test.h
- 头文件接口实现的三个c文件:so_test_a.c so_test_b.c so_test_c.c
- 我们将这几个文件编译成一个动态库:libtest.so
🌍2.1.1 文件详情
我在路径/root/host/my_program/asoc/include下创建四个文件
一个头文件:
vi so_test.h
#ifndef SO_TEST_H #define SO_TEST_H int addTwoiNum(int a, int b); int subTwoiNum(int a, int b); int mulTwoiNum(int a, int b); #endif
三个.c文件:
vi so_test_a.c
#include "so_test.h" #include <stdio.h> int addTwoiNum(int a, int b) { return a + b; }
vi so_test_b.c
#include "so_test.h" #include <stdio.h> int subTwoiNum(int a, int b) { return a - b; }
vi so_test_c.c
#include "so_test.h" #include <stdio.h> int mulTwoiNum(int a, int b) { return a * b; }
🌍2.1.2 编译生成动态库
给文件附上权限:
chmod 777 so_test_a.c so_test_b.c so_test_c.c so_test.h
接下来,我们将编译这些文件成一个动态库。
在Linux系统中可以使用gcc
来完成这个任务。
gcc -c -Wall -Werror -fpic so_test_a.c so_test_b.c so_test_c.c gcc -shared -o libtest.so so_test_a.o so_test_b.o so_test_c.o
第一行命令 :
-c
选项告诉编译器只编译源文件,而不进行链接。-fpic
选项用于生成与位置无关的代码,这是动态链接库所必需的。第二行命令:
- 使用
-shared
选项将目标文件链接成一个共享对象(动态库)libtest.so
。
现在,会得到一个名为 libtest.so
的动态库文件。
🌊2.2 动态库如何使用
前面已经成功生成了一个动态链接库libtest.so,下面通过一个程序来调用这个库里的函数。
比如程序的源文件为:main.c【我创建的目录是/root/host/my_program/asoc/my_program】
#include <stdio.h> #include "so_test.h" int main() { int result_a, result_b, result_c; int x = 10, y = 5; // 调用动态库中的函数 result_a = addTwoiNum(x, y); result_b = subTwoiNum(x, y); result_c = mulTwoiNum(x, y); // 打印结果 printf("Result of add: %d\n", result_a); printf("Result of sub: %d\n", result_b); printf("Result of mul: %d\n", result_c); return 0; }
现在需要链接 libtest.so
到源文件。
下面是编译模板:
gcc -o main main.c -I/path/to/include -L/path/to/lib -ltest
模板参数说明:
-o main
:指定输出文件的名称为main
。main.c
:您的源文件。-I/path/to/include
:指定要搜索头文件的路径。-L/path/to/lib
:指定要搜索库文件的路径。-ltest
:指定要链接的库文件名称。这里假设动态库文件名为libtest.so
。请将
/path/to/include
和/path/to/lib
替换为实际的路径。
🌍2.2.1 案例
【案例】如果头文件路径是 /root/host/my_program/asoc/include/so_test.h
,动态库文件路径是 /root/host/my_program/asoc/include/libtest.so
,可以这样编译 main.c
文件:
gcc -o main main.c -I/root/host/my_program/asoc/include -L/root/host/my_program/asoc/include -ltest
在这个命令中:
-o main
:指定输出文件的名称为main
。main.c
:源文件。-I/root/host/my_program/asoc/include
:指定要搜索头文件的路径。-L/root/host/my_program/asoc/include
:指定要搜索库文件的路径。-ltest
:指定要链接的库文件名称。
链接完成会生成一个 main 的可执行文件,这个可执行文件到底有没有成功链接到动态链接库呢?
可以使用下面的命令来查看:
ldd main
这里说明虽然我们已经使用 -L
选项指定了库文件的搜索路径,但是系统加载器在搜索动态库时还是会按照默认的路径 /lib 或者 /usr/lib 的路径进行搜索,因此即使编译成功,但运行时仍找不到动态库。
要解决这个问题,可以尝试设置 LD_LIBRARY_PATH
环境变量来指定动态库的搜索路径。例如我的动态库.so是在路径/root/host/my_program/asoc/include下,则使用命令:
LD_LIBRARY_PATH=/root/host/my_program/asoc/include ./main
这样运行时就能够找到动态库 libtest.so+运行成功!
🌍2.2.2 动态库错误记录
这个错误是在动态库执行的时候经常会遇到,说找不到这个.so文件,如果放在/lib或者/usr/lib下,那么默认就能找到。如果放在其他目录下,有 3 种解决方案:
- 将.so 文件拷贝到 /usr/lib/文件夹下面
- 添加PATH环境变量【前面的案例就是使用这个解决】
export LD_LIBRARY_PATH=<动态库所在的绝对路径>- 修改配置脚本
将动态库所在的路径加到 /etc/ld.so.conf 文件里
vim /etc/ld.so.conf
- 添加后刷新
/sbin/ldconfig
🌞3. 静态库
🌊3.1 静态库如何生成
下面通过一个小栗子介绍如何生成一个静态库。
- 一个头文件: vi staticlib.h
- 头文件接口实现的三个c文件:staticlib.c
- 我们将这几个文件编译成一个静态库:libstatic.a
🌍3.1.1 文件详情
我在路径/root/host/my_program/asoc/include下创建下面的文件
vi staticlib.h
#ifndef __STATICLIB_H #define __STATICLIB_H int hello(); #endif
vi staticlib.c
#include "staticlib.h" #include <stdio.h> int hello(){ printf("hello,this is static lib\n"); return 0; }
🌍3.1.2 编译生成动态库
给文件附上权限:
chmod 777 staticlib.h staticlib.c
使用编译器将 staticlib.c
编译成目标文件(.o
文件):
gcc -c staticlib.c -o staticlib.o
使用 ar
命令将目标文件打包成静态库文件 libstatic.a
:
ar rcs libstatic.a staticlib.o
这样就生成了名为 libstatic.a
的静态库文件,其中包含了 staticlib.o
的内容。
🌊3.2 静态库如何使用
前面已经成功生成了一个动态链接库libtest.so,下面通过一个程序来调用这个库里的函数。
比如程序的源文件为:test.c【我创建的目录是/root/host/my_program/asoc/my_program】
内容如下:
#include <stdio.h> #include "staticlib.h" int main() { printf("Calling hello() function...\n"); hello(); return 0; }
接下来,需要编译 main.c
并链接静态库 libstatic.a
。
gcc test.c -o test -I/root/host/my_program/asoc/include/ -L/root/host/my_program/asoc/include/ -lstatic
参数说明:
-L
参数指定了编译器搜索库文件的路径-lstatic
指定了要链接的静态库名字(注意,lib
前缀和.a
扩展名都不需要在此处指定)
然后运行可执行文件 test
:
./test
说明静态库链接成功!