GCC链接静态库和动态库详解

文章目录

1. 静态库和动态库

2. 静态库链接

3. 动态库链接


1. 静态库和动态库

链接(linking)是编译过程的最后一步,它将多个目标文件( .o 文件)和库文件结合在一起,生成一个可执行的二进制文件。链接的主要任务是解析符号引用,合并代码和数据段,并处理重定位信息。

对于整个gcc的编译过程命令解析查看下面这篇文章:

gcc命令以及GDB调试选项-CSDN博客

静态库和动态库是根据链接时机的不同来划分的,它们主要区别在于库文件在程序运行中的加载和使用方式。

静态库

静态库在编译和链接阶段就会被包含在可执行程序里,生成的可执行文件已经内嵌了所有的库代码,具备独立运行的能力。具体特点如下:

  1. 内嵌到可执行文件中:静态库的代码在编译时会被复制到最终的可执行文件中,程序运行时不需要依赖外部库文件。
  2. 独立性强:生成的可执行文件独立,不依赖外部库,方便分发和部署。
  3. 性能较好:由于不需要在运行时加载库,程序启动速度较快。
  4. 更新复杂:如果库代码有bug或需要升级,所有使用该库的程序都需要重新编译和链接,维护工作量较大。
  5. 空间浪费:每个使用静态库的可执行文件中都会包含一份库的代码,如果多个程序都使用同一个静态库,会导致空间浪费。

动态库

动态库在程序运行时才被加载,多个程序可以共享一份动态库,从而节省存储空间。具体特点如下:

  1. 运行时加载:动态库在程序运行时根据需要加载,不会在编译时被复制到可执行文件中。
  2. 共享性高:多个程序可以共享同一个动态库,节省内存和存储空间。
  3. 更新方便:如果动态库有bug或者需要升级,只需要替换新的库文件即可,不需要重新编译和链接使用该库的所有程序。
  4. 启动速度慢:由于在运行时需要加载库,程序启动速度相对较慢。
  5. 依赖性强:可执行文件运行时依赖外部的动态库文件,如果库文件缺失或版本不兼容,程序可能无法正常运行。

接下来创建三个文件 main.cadd.cadd.h 来讲解静态库链接和动态库链接的过程。

main.c

#include <stdio.h>
#include "add.h"

int main(int argc, char *argv[])
{
    printf("%d\n", add(10, 10));
    printf("%d\n", add(20, 20));
    return 0;
}

add.c

#include "add.h"

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

add.h

#ifndef __ADD_H
#define __ADD_H

int add(int a, int b);

#endif

2. 静态库链接

静态库的名字一般为 “libxxx.a”。利用静态库编译生成的可执行文件比较大,因为整个函数库的所有数据都被整合进了可执行文件中。

优点:

  1. 不需要外部函数库支持。
  2. 加载速度快。

缺点:

  1. 静态库升级时,程序需要重新编译。
  2. 多个程序调用相同库,静态库会重复载入内存,造成内存浪费。

静态库的制作步骤如下:

  1. 编译 add.c 文件为目标文件 add.o

    gcc add.c -o add.o -c
    
  2. 使用 ar 工具将目标文件 add.o 打包成静态库 libadd.a

    ar -rc libadd.a add.o
    

静态库的使用步骤如下:

1. 编译 main.c 文件,并链接静态库 libadd.a,生成可执行文件 output

gcc main.c -o output -ladd -L.
  • -L. 表示在当前目录(. 表示当前目录)中查找库。
  • -ladd 表示链接库名为 libadd.a(省略了前缀 lib 和后缀 .a)。

2. 运行生成的可执行文件 output

./output

运行结果: 

20
40
  • gcc add.c -o add.o -c:这条命令将 add.c 文件编译为目标文件 add.o
  • ar -rc libadd.a add.o:这条命令将目标文件 add.o 打包成静态库 libadd.a
  • gcc main.c -o output -ladd -L.:这条命令将 main.c 文件编译并链接静态库 libadd.a,生成可执行文件 output
    • -L. 选项用于指定库文件的搜索路径为当前目录。
    • -ladd 选项用于指定链接的库名为 libadd.a

静态库在编译期间被整合到可执行文件中,提供了加载速度快和独立性高的优点,但在库升级和内存利用方面存在一些缺点。

3. 动态库链接

动态库名字一般为 “libxxx.so”,又称共享库。动态库在编译时没有被编译进可执行文件,所以可执行文件比较小。程序运行时,操作系统帮我们找到库,并跟程序链接起来。

优点:

  1. 多个程序可以使用同一个动态库,节省内存。
  2. 库可以升级,而不需要重新编译应用程序。

缺点: 加载速度较慢,因为需要在运行时找到并加载库。

动态库的制作步骤如下:

1. 编译 lib.c 文件为动态库 libtest.so

gcc -shared -fPIC lib.c -o libtest.so

2. 将生成的动态库 libtest.so 复制到 /usr/lib 目录(需要超级用户权限):

sudo cp libtest.so /usr/lib/

动态库的使用步骤如下:

1. 编译 main.c 文件,并链接动态库 libtest.so,生成可执行文件 output

gcc main.c -L. -ltest -o output
  • -L. 表示在当前目录(. 表示当前目录)中查找库。
  • -ltest 表示链接库名为 libtest.so(省略了前缀 lib 和后缀 .so)。

2. 运行生成的可执行文件 output

./output

运行结果:

20
40
  • gcc -shared -fPIC lib.c -o libtest.so:这条命令将 lib.c 文件编译为动态库 libtest.so-shared 表示创建共享库,-fPIC 表示生成与位置无关的代码(Position Independent Code)。
  • sudo cp libtest.so /usr/lib/:这条命令将生成的动态库 libtest.so 复制到系统的库目录 /usr/lib 中。
  • gcc main.c -L. -ltest -o output:这条命令将 main.c 文件编译并链接动态库 libtest.so,生成可执行文件 output
    • -L. 选项用于指定库文件的搜索路径为当前目录。
    • -ltest 选项用于指定链接的库名为 libtest.so

动态库在编译时没有被编译进可执行文件,而是在程序运行时由操作系统加载,从而提供了节省内存和库可升级的优点,但在运行时加载速度较慢。

  • 27
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TENET-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值