当前位置: 首页 > article >正文

Linux动态库和静态库

Linux动态库和静态库

  • Linux动态库和静态库
    • 动静态库的基本原理
      • 可执行程序的生成过程
      • 动静态库的本质
    • 认识动静态库
      • 背后的库支持
      • 动静态库的命名
      • 静态链接示例
    • 动静态库各自的特征
      • 静态库
      • 动态库
    • 静态库的打包与使用
      • 示例文件
      • 打包
        • 1. 生成目标文件
        • 2. 打包静态库
        • 3. 组织文件
        • 使用 Makefile
      • 使用
        • 方法一:使用选项
        • 方法二:拷贝到系统路径
    • 动态库的打包与使用
      • 打包
        • 1. 生成目标文件
        • 2. 打包动态库
        • 3. 组织文件
        • 使用 Makefile
      • 使用
        • 编译
        • 运行时问题
        • 解决方法
    • 总结


Linux动态库和静态库

在Linux开发中,动态库和静态库是代码复用和程序构建的重要工具。无论是编写小型工具还是大型项目,理解动静态库的原理和使用方法都能极大提高开发效率。本文将从基本原理出发,逐步带您认识动静态库,分析它们的特征,并通过具体示例演示静态库和动态库的打包与使用过程。让我们开始吧!


动静态库的基本原理

可执行程序的生成过程

要理解动静态库的本质,首先需要了解源代码如何变成可执行程序。在Linux下,这一过程分为四个步骤:

  1. 预处理:处理头文件展开、去注释、宏替换和条件编译,生成 .i 文件。例如,#include 会被替换为头文件内容。
  2. 编译:进行词法分析、语法分析、语义分析和符号汇总,将代码翻译成汇编指令,生成 .s 文件。
  3. 汇编:将汇编指令转换为二进制机器码,生成目标文件 .o
  4. 链接:将多个 .o 文件链接起来,生成最终的可执行程序。

假设有五个文件:test1.ctest2.ctest3.ctest4.cmain1.c,要生成可执行程序,我们需要:

  • 分别编译生成 test1.otest2.otest3.otest4.omain1.o
  • 将这些目标文件链接,生成最终程序。

如果另一个项目需要用 test1.ctest4.cmain2.c 生成新程序,过程相同。但如果这些文件频繁复用,每次都重新编译会很麻烦。这时,我们可以将 test1.otest4.o 打包成一个“库”,供不同项目直接链接使用。

动静态库的本质

动静态库本质上是目标文件(.o)的集合,是可执行程序的“半成品”。它们不包含主函数(main),只提供函数或方法的实现,供其他程序调用。库的出现解决了代码复用问题,避免了重复编译的繁琐。


认识动静态库

让我们通过一个简单程序认识动静态库:

#include <stdio.h>int main()
{printf("hello world\n"); // 调用库函数return 0;
}

编译并运行:

gcc -o mytest mytest.c
./mytest

输出:hello world

背后的库支持

这个程序能输出 hello world,是因为 gcc 在链接时自动引入了 C 标准库。可以用 ldd 查看依赖:

ldd mytest

输出示例:

linux-vdso.so.1 =>  (0x00007fff5f5ff000)
libc.so.6 => /lib64/libc.so.6 (0x00007f9c8e5b0000)
/lib64/ld-linux-x86-64.so.2 (0x00007f9c8e9b4000)

其中,libc.so.6 是 C 标准动态库的软链接。查看其真实文件:

ls -l /lib64/libc.so.6

输出:libc.so.6 -> libc-2.17.so

进一步检查文件类型:

file /lib64/libc-2.17.so

输出:ELF 64-bit LSB shared object, x86-64, ...

这表明 libc-2.17.so 是一个动态共享库(.so 后缀)。

动静态库的命名

  • Linux
    • 动态库:.so(shared object),如 libc.so.6
    • 静态库:.a(archive),如 libm.a
  • Windows
    • 动态库:.dll(dynamic link library)。
    • 静态库:.lib

库名规则:去掉前缀 lib 和后缀(.so.a)及版本号,剩下的是库名。例如,libc.so.6 的库名是 c

静态链接示例

默认情况下,gcc 使用动态链接。若要静态链接,添加 -static

gcc -o mytest-s mytest.c -static

检查依赖:

ldd mytest-s

输出:not a dynamic executable

静态链接的可执行文件不依赖动态库,体积明显更大:

ls -lh mytest mytest-s

可能输出:

  • mytest:几十 KB(动态链接)。
  • mytest-s:几 MB(静态链接)。

动静态库各自的特征

静态库

  • 链接方式:编译时将库代码复制到可执行文件中。
  • 运行时:不依赖外部库。
  • 优点:独立性强,可单独运行。
  • 缺点:文件体积大;多个程序加载相同静态库时,内存中会有重复代码,浪费资源。

动态库

  • 链接方式:运行时才加载库代码,可执行文件中只包含函数入口地址表。
  • 运行时:由操作系统从磁盘加载到内存,多个程序共享同一份代码。
  • 优点:节省磁盘和内存空间,多个程序共享库时效率高。
  • 缺点:依赖动态库,若库缺失则无法运行。

静态库的打包与使用

示例文件

我们用以下文件演示:

  • add.h
    #pragma once
    extern int my_add(int x, int y);
    
  • add.c
    #include "add.h"
    int my_add(int x, int y) { return x + y; }
    
  • sub.h
    #pragma once
    extern int my_sub(int x, int y);
    
  • sub.c
    #include "sub.h"
    int my_sub(int x, int y) { return x - y; }
    

打包

1. 生成目标文件
gcc -c add.c -o add.o
gcc -c sub.c -o sub.o
  • -c:只编译,不链接,生成 .o 文件。
2. 打包静态库
ar -rc libcal.a add.o sub.o
  • ar:归档工具。
  • -r:替换已有文件。
  • -c:创建新库。
  • libcal.a:生成静态库。

验证:

ar -tv libcal.a

输出示例:

rw-r--r-- 0/0  1234 Mar 19 12:34 2025 add.o
rw-r--r-- 0/0  1234 Mar 19 12:34 2025 sub.o
3. 组织文件
mkdir -p mathlib/include mathlib/lib
mv add.h sub.h mathlib/include/
mv libcal.a mathlib/lib/

目录结构:

mathlib/
├── include/
│   ├── add.h
│   └── sub.h
└── lib/└── libcal.a
使用 Makefile
CC = gcc
AR = ar
CFLAGS = -c
TARGET = libcal.a
OBJS = add.o sub.oall: $(TARGET)
add.o: add.c add.h$(CC) $(CFLAGS) add.c -o add.o
sub.o: sub.c sub.h$(CC) $(CFLAGS) sub.c -o sub.o
$(TARGET): $(OBJS)$(AR) -rc $(TARGET) $(OBJS)
output:mkdir -p mathlib/include mathlib/libcp *.h mathlib/include/cp $(TARGET) mathlib/lib/
clean:rm -f *.o $(TARGET) mathlib -r
.PHONY: all output clean
  • make:生成库。
  • make output:组织文件。

使用

测试程序 main.c

#include <stdio.h>
#include <add.h>int main()
{int x = 20, y = 10;int z = my_add(x, y);printf("%d + %d = %d\n", x, y, z);return 0;
}
方法一:使用选项
gcc main.c -I./mathlib/include -L./mathlib/lib -lcal -o main
  • -I:头文件路径。
  • -L:库文件路径。
  • -l:指定库名(cal)。

运行:

./main

输出:20 + 10 = 30

方法二:拷贝到系统路径
sudo cp mathlib/include/* /usr/include/
sudo cp mathlib/lib/libcal.a /lib64/
gcc main.c -lcal -o main
  • 注意:仍需 -lcal 指定库名。

动态库的打包与使用

打包

1. 生成目标文件
gcc -c -fPIC add.c -o add.o
gcc -c -fPIC sub.c -o sub.o
  • -fPIC:生成位置无关码,动态库必需。
2. 打包动态库
gcc -shared -o libcal.so add.o sub.o
  • -shared:生成共享库。
3. 组织文件
mkdir -p mlib/include mlib/lib
mv add.h sub.h mlib/include/
mv libcal.so mlib/lib/
使用 Makefile
CC = gcc
CFLAGS = -c -fPIC
TARGET = libcal.so
OBJS = add.o sub.oall: $(TARGET)
add.o: add.c add.h$(CC) $(CFLAGS) add.c -o add.o
sub.o: sub.c sub.h$(CC) $(CFLAGS) sub.c -o sub.o
$(TARGET): $(OBJS)$(CC) -shared -o $(TARGET) $(OBJS)
output:mkdir -p mlib/include mlib/libcp *.h mlib/include/cp $(TARGET) mlib/lib/
clean:rm -f *.o $(TARGET) mlib -r
.PHONY: all output clean

使用

编译
gcc main.c -I./mlib/include -L./mlib/lib -lcal -o main
运行时问题

运行 ./main 可能报错:

./main: error while loading shared libraries: libcal.so: cannot open shared object file

检查依赖:

ldd main

输出:libcal.so => not found

解决方法
  1. 拷贝到系统路径

    sudo cp mlib/lib/libcal.so /lib64/
    ./main
    
  2. 设置 LD_LIBRARY_PATH

    export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/user/mlib/lib
    ./main
    
  3. 配置 /etc/ld.so.conf.d/

    echo "/home/user/mlib/lib" > mylib.conf
    sudo mv mylib.conf /etc/ld.so.conf.d/
    sudo ldconfig
    ./main
    
    • ldconfig:更新动态库缓存。

总结

  • 静态库:打包用 ar,生成 .a 文件,编译时嵌入代码,独立性强但体积大。
  • 动态库:用 gcc -shared,生成 .so 文件,运行时加载,节省空间但依赖库文件。
  • 使用差异:静态库无需运行时配置,动态库需确保库路径可访问。

通过本文,您应该已经掌握了Linux下动静态库的原理和实践。希望这些知识能在您的开发中派上用场!


相关文章:

Linux动态库和静态库

Linux动态库和静态库 Linux动态库和静态库动静态库的基本原理可执行程序的生成过程动静态库的本质 认识动静态库背后的库支持动静态库的命名静态链接示例 动静态库各自的特征静态库动态库 静态库的打包与使用示例文件打包1. 生成目标文件2. 打包静态库3. 组织文件使用 Makefile…...

13 IO流:字节流、字符流、缓冲流、文件复制(字节/字符/缓冲区)、字符转换流、打印流、IO框架(黑马Java视频笔记)

文章目录 IO流 >> 读写数据的方案1. 认识IO流1&#xff09;IO流的分类2&#xff09;IO流的体系 2. 文件字节输入流2.1 创建文件字节流对象2.2 读取文件1&#xff09;使用read()方法一个一个字节的读取2&#xff09;使用字节数组读取数据:byte[]3&#xff09;使用字节流读…...

深入理解 TypeScript 中的迭代器(Iterators)与生成器(Generators)

一、为什么需要迭代协议&#xff1f; 在现代 JavaScript/TypeScript 开发中&#xff0c;我们经常需要处理各种集合型数据&#xff1a;数组、Map、Set 甚至是自定义数据结构。ES6 引入的迭代协议&#xff08;Iteration Protocols&#xff09;正是为了解决统一遍历机制的问题。通…...

靶场(十四)---小白心得思路分享---Extplorer

启程&#xff1a; 开始扫描端口服务&#xff0c;发现什么都没有&#xff0c;果断进行下一步目录扫描 PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | 3072 98:4e:5d:e1:e6:97:29:6f:…...

逆向中常见的加密算法识别

1、base64及换表 base64主要是将输入的每3字节&#xff08;共24bit&#xff09;按照每六比特分成一组&#xff0c;变成4个小于64的索引值&#xff0c;然后通过一个索引表得到4个可见的字符。 索引表为一个64字节的字符串&#xff0c;如果在代码中发现引用了这个索引表“ABCDEF…...

【初学者】怎样学习、使用与研究算法?

李升伟 整理 学习、使用与研究算法是一个系统化的过程&#xff0c;涉及理论学习、实践应用和深入研究。以下从学习方法、使用技巧和研究方向三个方面进行详细阐述&#xff1a; 一、学习方法 1. 分阶段学习 初级阶段&#xff1a;掌握经典算法&#xff0c;如最短路径算法&…...

【愚公系列】《高效使用DeepSeek》018-错题本整理

🌟【技术大咖愚公搬代码:全栈专家的成长之路,你关注的宝藏博主在这里!】🌟 📣开发者圈持续输出高质量干货的"愚公精神"践行者——全网百万开发者都在追更的顶级技术博主! 👉 江湖人称"愚公搬代码",用七年如一日的精神深耕技术领域,以"…...

Linux上的`i2c-tools`工具集的编译构建和安装

源码复制到Ubuntu系统中并解压 的i2c-tools工具集的源码百度网盘下载链接&#xff1a; https://pan.baidu.com/s/1XNuMuT1auT1dMzYo3LAFmw?pwdi6xe 终端进入源码目录 cd /home/book/mybuild/i2c-tools-4.2执行编译构建命令 运行下面的命令进行编译构建 make CC${CROSS_COM…...

langgraph简单Demo(使用langserve实现外部调用)

前言 这个示例是研究如何使用langserve实现外部调用 接入大模型参考文章&#xff1a;接入阿里云百炼 1、安装依赖 pip install langserve fastapi uvicorn pip install sse_starlette 2、代码实现 from fastapi import FastAPI from langchain_core.messages import HumanM…...

【C#高阶编程】—单例模式详解

C# 单例模式 单例模式是一种设计模式&#xff0c;用于确保一个类只有一个实例&#xff0c;并提供一个全局访问点来访问该实例。单例模式常用于需要全局唯一对象的场景&#xff0c;比如配置文件管理、日志记录、数据库连接池等。 单例模式的核心特点 私有构造函数&#xff1a;…...

折叠树报表

折叠树报表中包含了三种信息: 1.树组织信息-可展开、收拢 2.节点的统计信息(汇总求和) 3.每个节点对应的数据信息 一、准备数据 mysql8 数据库中存在两张表 org和store表。 org表和部分数据如下,其中orgname是组织的名称,codepath是完整的组织代码,seq是每个节点的顺序,可…...

Python个人学习笔记(16):模块(os)

四、os模块 主要用于文件夹处理 &#xff08;一&#xff09;文件夹相关 os.makedirs(‘dirname1/dirname2’) &#xff1a;创建文件夹目录&#xff0c;不能重复创建&#xff0c;用的多 代码&#xff1a; os.makedirs(a/b/c)结果&#xff1a; os.removedirs(‘dirname1’)&…...

虚拟地址空间(下)进程地址空间(上)

一.关于页表组成 1.权限&#xff08;rwx) 作用&#xff1a;如1.让代码区变成只读的 2.写时拷贝的实现&#xff1a;子进程创建时其页表指向的父进程代码和数据权限都是只读的&#xff0c;子进程试图修改&#xff0c;触发错误&#xff0c;系统开始写时拷贝。 来源&#xff1a;…...

【数据集分享】青藏高原两次强震玛多地震和漾濞地震的震源过程

2021年5月21日&#xff0c;5小时内在青藏高原不同区域发生了漾濞6.4级和玛多7.4级强烈地震&#xff0c;表明印度板块和欧亚大陆板块的碰撞汇聚作用下青藏高原持续和频繁的 剧烈构造运动和地震活动。本研究利用地震记录和空间对地观测同震位移资料&#xff08;InSAR&#xff09;…...

jmeter环境搭建及使用

Meter 是一个开源的性能测试工具&#xff0c;用于测试静态和动态资源的性能。 1、安装 官网下载&#xff1a; 下载地址&#xff1a;Apache JMeter - Download Apache JMeter 网盘下载&#xff1a; 通过百度网盘分享的文件&#xff1a;apache-jmeter-5.6.3.rar 链接&#x…...

Python 鼠标轨迹算法 - 防止游戏检测

一.简介 鼠标轨迹算法是一种模拟人类鼠标操作的程序&#xff0c;它能够模拟出自然而真实的鼠标移动路径。 鼠标轨迹算法的底层实现采用C/C语言&#xff0c;原因在于C/C提供了高性能的执行能力和直接访问操作系统底层资源的能力。 鼠标轨迹算法具有以下优势&#xff1a; 模拟…...

网络编程--服务器双客户端聊天

写一个服务器和客户端 运行服务器和2个客户端&#xff0c;实现聊天功能 客户端1和客户端2进行聊天&#xff0c;客户端1将聊天数据发送给服务器&#xff0c;服务器将聊天数据转发给客户端2 要求&#xff1a; 服务器使用 select 模型实现 &#xff0c;客户端1使用 poll 模型实现…...

yum软件包乾坤大挪移(Yum Package Qiankun Great Migration)

yum软件包乾坤大挪移 背景 由于很多的生产环境是无法连接外网的&#xff0c;因此用yum或者dnf命令来安装软件包常常是一个比较麻烦的事情&#xff0c;原因是很多软件的依赖很复杂&#xff0c;如果要一个个下载、拷贝、再安装&#xff0c;这往往是一个非常繁琐冗杂的过程&…...

Java:读取中文,read方法

public static void main(String[] args) throws IOException {FileReader fr new FileReader("C:\\aaa\\a.txt");//字符流的底层也是一个字节一个字节读取的&#xff0c;遇到中文就一次读多个&#xff0c;GBK一次读两个&#xff0c;UTF-8一次读三个字节//idea默认U…...

[GHCTF 2025]真会布置栈吗?

题目是一个聊天室,我们先按照题目使用 /help Help: /help 显示此帮助信息 /msg [text] 在当前频道发送消息 /nick [name] 更改你的用户名 /list 列出可用的频道 /join [channel] 切换到不同的频道 /channel …...

集合的练习1-2

//练习1&#xff1a; import java.util.ArrayList;public class ArraylistTest1 {public static void main(String[] args){ArrayList<String> listnew ArrayList<>();//需求&#xff1a;定义一个集合&#xff0c;添加字符串&#xff0c;并进行遍历//遍历格式&…...

英语词性--数词

文章目录 数词概念数词分词基数词序数词 基数与序数词的区别基变序的规律 数词概念 数词&#xff08;Numerals&#xff09; 是英语中用于表示 数量&#xff08;基数&#xff09;或顺序&#xff08;序数&#xff09; 的词类&#xff0c;通常用于描述数字、计数、顺序等。 例如&…...

面试整理--一个报告生成的方案解析

最近又快到了年后找工作的时间&#xff0c;近期写点工作积累&#xff0c;供大家参考。 欢迎关注公主号【测试开发备忘录】&#xff0c;交流职场技巧和经验 首先从工作中一个报错来展开: Start directory is not importable: 错误信息 "Start directory is not importable…...

C#零基础入门篇(18. 文件操作指南)

## 一、文件操作基础 在C#中&#xff0c;文件操作主要通过System.IO命名空间中的类来实现&#xff0c;例如File、FileStream、FileInfo等。 ## 二、常用文件操作方法 ### &#xff08;一&#xff09;文件读取 1. **使用File.ReadAllText方法读取文件内容为字符串** …...

Linux 一步部署DHCP服务

#!/bin/bash #脚本作者和日期 #author: PEI #date: 20250319 #检查root权限 if [ "$USER" ! "root" ]; then echo "错误&#xff1a;非root用户&#xff0c;权限不足&#xff01;" exit 0 fi #防火墙与高级权限 systemctl stop firewa…...

如何打造安全稳定的亚马逊采购测评自养号下单系统?

在当今的电商领域&#xff0c;亚马逊作为全球领先的在线购物平台&#xff0c;其商品种类繁多&#xff0c;用户基数庞大&#xff0c;成为了众多商家和消费者的首选。而对于一些需要进行商品测评或市场调研的用户来说&#xff0c;拥有一个稳定、安全的亚马逊账号体系显得尤为重要…...

【大模型学习】第二十四章 生成式人工智能(GAI)简介

目录 一、什么是生成式人工智能&#xff08;GAI&#xff09;&#xff1f;‌ 二、核心技术原理‌ ‌三、典型应用场景‌ ‌四、技术特点与挑战‌ 五、训练优化策略 六、关键性能指标&#xff08;2025年基准&#xff09; ‌七、技术演进方向‌&#xff1a; 一、什么是生成式…...

Pytorch中layernorm实现详解

平时我们在编写神经网络时&#xff0c;经常会用到layernorm这个函数来加快网络的收敛速度。那layernorm到底在哪个维度上进行归一化的呢&#xff1f; 一、问题描述 首先借用知乎上的一张图&#xff0c;原文写的也非常好&#xff0c;大家有空可以去阅读一下&#xff0c;链接放…...

YOLO11报错:AttributeError: module ‘torch‘ has no attribute ‘OutOfMemoryError‘

事情是这样的&#xff1a;前几天YOLO11的代码还是可以训练的&#xff0c;昨天训练了一天&#xff0c;今天换模型就报这个错。 AttributeError: module torch has no attribute OutOfMemoryError我查了一下&#xff1a;YOLO11官方代码issues里面也有人有同样的问题&#xff0c;…...

基于java的ssm+JSP+MYSQL的高校四六级报名管理系统(含LW+PPT+源码+系统演示视频+安装说明)

作者&#xff1a;计算机搬砖家 开发技术&#xff1a;SpringBoot、php、Python、小程序、SSM、Vue、MySQL、JSP、ElementUI等&#xff0c;“文末源码”。 专栏推荐&#xff1a;SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;Java精选实战项…...