「Linux 系统编程」静态库与动态库

1 静态库与动态库简介

1.1 静态库介绍

静态库(Static Library)是编译时被 完整复制到目标程序中 的库文件,程序运行时不再依赖原库文件。

在 Linux 系统中,静态库文件以 .a 为扩展名,例如 libmath.a

当静态库文件被改动,需要重新编译链接程序才能生效。


1.2 动态库介绍

动态库(Dynamic Library,又称共享库 Shared Library)在程序编译时仅记录引用信息,程序运行时才被加载到内存并共享使用

在 Linux 系统中,动态库文件以 .so 为扩展名,例如 libmath.so

当动态库更新后,无需重新编译程序(只要接口兼容),但运行时需保证库存在且路径正确。


1.3 静态库与动态库对比

静态库在编译时 “嵌入” 程序,运行独立但体积大;动态库在运行时 “共享”,体积小但依赖外部文件。

通常来说,静态加载的速度会快一些,而动态库速度慢一些,但是节省内存。


1.4 gcc 编译默认链接的动态库

在用 gcc 编译 .c 程序后,可以通过 ldd 命令查看可执行文件依赖的动态库:

1
2
3
4
5
# 编译一个程序
gcc test.c -o test

# 查看依赖的动态库
ldd test

可以看到,libc.so.6ld-linux-x86-64.so.2 就是默认链接的核心动态库。

libc.so.6 提供 C 语言标准函数(如 printf、scanf、malloc、free、字符串处理函数等),是几乎所有 C 程序的 基础依赖

ld-linux-x86-64.so.2动态链接器相关库,负责在程序运行时加载所需的动态库(包括上述 libc.so 等),并解析库中的函数引用。



2 Linux 静态库制作

2.1 制作步骤

  • 创建源代码文件

    写了一些函数,分别保存在 add.csub.chello.c 文件中。

    1
    2
    3
    4
    // add.c
    int add(int a, int b){
    return a + b;
    }
    1
    2
    3
    4
    // sub.c
    int sub(int a, int b){
    return a - b;
    }
    1
    2
    3
    4
    5
    6
    // hello.c
    #include <stdio.h>

    void hello(){
    printf("Hello, Marisa!\n");
    }

  • 创建头文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // marisalib.h
    #ifndef _MARISA_H_
    #define _MARISA_H_

    int add(int, int);
    int sub(int, int);
    void hello();

    #endif

    此处增加了 头文件保护符,避免重复包含头文件内容,防止出现重定义错误、潜在的逻辑错误等。


  • 将源代码编译为目标文件

    1
    2
    3
    gcc -c add.c -o add.o
    gcc -c sub.c -o sub.o
    gcc -c hello.c -o hello.o

  • 打包成静态库

    1
    ar rcs libmarisa.a add.o sub.o hello.o
    • ar: 归档工具
    • rcs: r(替换旧成员)、c(创建库)、s(添加索引)

    静态库名格式必须为 lib[库名称].a


在完成上述工作后,可以通过 ar -t libmarisa.a 命令查看库中的内容:



2.2 使用示例

写一个测试程序 test.c

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
#include "marisalib.h" // 引入头文件中的函数声明

int main(){
hello();
printf("3 + 4 = %d\n", add(3, 4));
printf("7 - 3 = %d\n", sub(7, 3));

return 0;
}

通过以下命令进行编译链接:

1
gcc test.c -o test -L./ -lmarisa
  • -L./: -L 指定查找库的路径。在当前目录查找库
  • -lmarisa: -l 指定链接库的名称。链接 libmarisa.a,名称需要省略 lib.a

最后运行程序:

1
./test



2.3 注意事项

如果头文件、库所在的路径不在测试程序所在目录,例如 .h 头文件位于 ./include 中,.a 库文件位于 ./libs 中。此时,需要用 -I 指定查找头文件的路径

1
gcc test.c -o test -I./include -L./libs -lmarisa


假如存在静态库与动态库同名,此时之前的编译命令会优先链接动态库。如果要强制使用静态库,需要改成如下命令形式:

1
gcc test.c -o test -L./ -l:libmath.a


3 Linux 动态库制作

3.1 制作步骤

  • 创建源代码文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // marisaops.c
    #include <stdio.h>
    #include "marisalib.h"

    int add(int a, int b){
    return a + b;
    }

    long long mul(long long a, long long b){
    return a * b;
    }

    void hello(){
    printf("Hello, Kirisame Marisa!\n");
    }

  • 创建头文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // marisalib.c
    #ifndef _MARISA_H_
    #define _MARISA_H_

    int add(int, int);
    long long mul(long long, long long);
    void hello();

    #endif

  • 编译成位置无关代码

    1
    gcc -c -fPIC marisaops.c -o marisaops.o

    -fPIC:生成位置无关代码(Position Independent Code),是动态库必需的特性。


  • 生成动态库

    1
    gcc -shared -o libmarisa.so marisaops.o
    • -shared:指定生成共享库
    • 命名规范lib[库名称].so(如 libmarisa.so

上述工作完成后,可以查看动态库信息:

1
nm -D libmarisa.so  # 查看导出符号



3.2 使用示例

写一个测试程序 test.c

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
#include "marisalib.h"

int main(){
hello();
printf("5 + 3 = %d\n", add(5, 3));
printf("2 * 2 = %lld\n", mul(2, 2));

return 0;
}

编译链接动态库:

1
gcc test.c -o test -L./ -lmarisa
  • -L./:指定库搜索路径(当前目录)
  • -lmarisa:链接 libmarisa.so(省略 lib 前缀和 .so后缀)

此时直接运行 ./test 会出现找不到动态库位置的错误:


在程序 运行阶段,需要为动态链接器 提供动态库所在目录位置

  • 临时设置(仅当前终端有效)

    在编译之后,执行如下命令:

    1
    export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH

    然后再运行程序 ./test 即可。

    export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH 指定动态链接器在运行时搜索共享库(.so 文件)的路径为当前路径。

    其中 . 表示当前工作目录(点号.代表当前目录),确保程序首先在当前目录中查找需要的动态库。$LD_LIBRARY_PATH 引用该变量当前已有的值。这样可以在添加新路径的同时保留原有的搜索路径。


  • 永久设置(添加到用户配置文件)

    任何编辑器都行,打开 ~/.bashrc

    1
    gedit ~/.bashrc  

    将这 export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH 添加到文件中,并执行:

    1
    source ~/.bashrc  # 使配置文件立即生效


需要注意的是,如果动态库的路径被修改了,在重新编译过后,~/.bashrc 文件中的运行时指定动态库路径命令也需要修改。



3.3 系统配置链接方法

可以通过配置系统文件 /etc/ld.so.conf 来实现动态库链接,相比临时设置 LD_LIBRARY_PATH,具有永久性、系统级和更安全的优点。

用任意编辑器打开 /etc/ld.so.conf

1
sudo gedit /etc/ld.so.conf

动态库绝对路径 写入保存:


然后执行 sudo ldconfig -v(更新系统库缓存)使得配置文件生效,其中 -v 增加生效可视化过程。之后再执行 ./test 程序:



「Linux 系统编程」静态库与动态库
https://marisamagic.github.io/2025/08/12/20250811/
作者
MarisaMagic
发布于
2025年8月12日
许可协议