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

Linux下动静态库的制作与使用

文章目录

    • 一 :star2:​动静态库介绍
      • :dizzy: 静态库
      • :dizzy: 动态库(共享库)
    • ​二 . :crescent_moon: 静态库的制作和使用
      • :sparkles:静态库的制作
        • 1. :sparkles: **编写源文件**
        • 2. :sparkles:**编译生成目标文件**
        • 3. :sparkles:**创建静态库**
      • :key: 静态库的使用
        • :key: 1. 编写调用静态库的源文件,和提供声明的头文件
        • :key: 2. 编译链接静态库
        • :key: 3. 运行可执行文件
    • 三 :balloon:​动态库的创建和使用
      • :rocket:动态库的制作
        • :rocket:1. 编写源文件
        • :rocket:2. 生成目标文件
        • :rocket:3. 创建动态库
      • :trident: 动态库的使用
        • :trident: 1. 编写调用动态库的源文件,和提供声明的头文件
        • :trident: 2. 编译链接动态库
        • :trident: 3. 运行可执行文件

在这里插入图片描述

一 🌟​动静态库介绍

💫 静态库

  1. 链接方式:在编译链接阶段,链接器将静态库中被程序调用的函数和数据,完整地复制到可执行文件中。一旦链接完成,可执行文件与静态库就不再有依赖关系,运行时无需静态库支持。
  2. 文件命名:遵循特定命名规则,通常以 lib 为前缀,以 .a 作为后缀,如 libexample.a

💫 动态库(共享库)

  1. 链接方式:动态库在程序运行时才被加载到内存。编译链接时,可执行文件仅记录对动态库中函数和数据的引用信息,而非实际代码。程序运行时,系统动态加载器负责将动态库映射到进程地址空间,供程序调用。
  2. 文件命名:同样以 lib 为前缀,但以 .so(Shared Object)作为后缀,如 libexample.so

​二 . 🌙 静态库的制作和使用

✨静态库的制作

编写Makefile构建静态库并使用

# 定义编译器和编译选项
CC = gcc
CFLAGS = -Wall -g

# 定义源文件和目标文件
SRCS_LIB = add.c sub.c
OBJS_LIB = $(SRCS_LIB:.c=.o)
LIB_NAME = libmath.a

SRCS_MAIN = main.c
OBJS_MAIN = $(SRCS_MAIN:.c=.o)
EXEC = main

# 默认目标
all: $(LIB_NAME) $(EXEC)

# 生成静态库
$(LIB_NAME): $(OBJS_LIB)
    ar rcs $@ $^

# 生成可执行文件
$(EXEC): $(OBJS_MAIN) $(LIB_NAME)
    $(CC) $(CFLAGS) -o $@ $^ -L. -lmath

# 编译源文件为目标文件
%.o: %.c
    $(CC) $(CFLAGS) -c $< -o $@

# 清理生成的文件
clean:
    rm -f $(OBJS_LIB) $(OBJS_MAIN) $(LIB_NAME) $(EXEC)

在Linux系统下制作静态库通常需要以下几个步骤:

1. ✨ 编写源文件

首先编写实现具体功能的C语言源文件。例如,创建两个源文件 add.csub.c,分别实现加法和减法功能:

// add.c
int add(int a, int b) {
    return a + b;
}
// sub.c
int sub(int a, int b) {
    return a - b;
}
2. ✨编译生成目标文件

使用 gcc 编译器的 -c 选项将源文件编译为目标文件(.o 文件)。目标文件包含编译后的机器代码,但还不能直接执行,因为它可能还未解决外部符号引用等问题。在包含 add.csub.c 的目录下执行以下命令:

gcc -c add.c sub.c

这会生成 add.osub.o 两个目标文件。

3. ✨创建静态库

使用 ar 工具(GNU归档工具)将目标文件打包成静态库。静态库文件命名通常以 lib 前缀开头,以 .a 作为文件扩展名。执行以下命令创建名为 libmath.a 的静态库:

ar rcs libmath.a add.o sub.o

ar 命令的选项含义如下:

  • r:将文件插入到归档文件中,如果文件已存在则替换它。
  • c:创建一个新的归档文件,如果归档文件已存在,不会报错。
  • s:为静态库创建索引,以加快链接速度。

🔑 静态库的使用

🔑 1. 编写调用静态库的源文件,和提供声明的头文件

制作math.h头文件,它包含 addsub 函数的声明。

// math.h
#ifndef MATH_H
#define MATH_H

int add(int a, int b);
int sub(int a, int b);

#endif

使用以上制作出的静态库 libmath.a,它包含 addsub 函数的实现。现在编写一个 main.c 文件来调用这些函数:

#include <stdio.h>
#include "math.h"
// 声明要调用的函数
int add(int a, int b);
int sub(int a, int b);

int main() {
    int result1 = add(3, 2);
    int result2 = sub(3, 2);
    printf("add result: %d\n", result1);
    printf("sub result: %d\n", result2);
    return 0;
}
🔑 2. 编译链接静态库

使用 gcc 编译器将 main.c 与静态库链接生成可执行文件。假设静态库 libmath.a 位于当前目录,使用以下命令:

gcc -o main main.c -L. -lmath
  • -o main:指定生成的可执行文件名为 main
  • main.c:要编译的源文件。
  • -L.-L 选项用于指定库文件的搜索路径,. 表示当前目录。如果静态库位于其他目录,需将其路径替换 .
  • -lmath-l 选项用于指定要链接的库名,这里去掉了 libmath.alib 前缀和 .a 后缀。
🔑 3. 运行可执行文件

链接成功后,在命令行执行生成的可执行文件:

./main

将会输出:

add result: 5
sub result: 1

在这里插入图片描述

三 🎈​动态库的创建和使用

🚀动态库的制作

编写Makefile构建动态库并使用

# 定义编译器和编译选项
CC = gcc
CFLAGS = -Wall -g -fPIC  # -fPIC用于生成位置无关代码,是创建动态库必需的
LDFLAGS = -shared  # 用于链接生成动态库

# 定义源文件和目标文件
SRCS_LIB = add.c sub.c
OBJS_LIB = $(SRCS_LIB:.c=.o)
LIB_NAME = libmath.so

SRCS_MAIN = main.c
OBJS_MAIN = $(SRCS_MAIN:.c=.o)
EXEC = main

# 默认目标
all: $(LIB_NAME) $(EXEC)

# 生成动态库
$(LIB_NAME): $(OBJS_LIB)
    $(CC) $(LDFLAGS) -o $@ $^

# 生成可执行文件
$(EXEC): $(OBJS_MAIN)
    $(CC) $(CFLAGS) -o $@ $^ -L. -lmath

# 编译源文件为目标文件
%.o: %.c
    $(CC) $(CFLAGS) -c $< -o $@

# 清理生成的文件
clean:
    rm -f $(OBJS_LIB) $(OBJS_MAIN) $(LIB_NAME) $(EXEC)

在Linux系统中,动态库(也称为共享库)在程序运行时才被加载到内存,多个程序可以共享同一份动态库代码,从而节省内存。以下详细介绍动态库的创建和使用步骤。

🚀1. 编写源文件

假设我们要创建一个包含加法和减法函数的动态库,编写 add.csub.c 两个源文件:

// add.c
int add(int a, int b) {
    return a + b;
}
// sub.c
int sub(int a, int b) {
    return a - b;
}
🚀2. 生成目标文件

使用 gcc 编译器的 -fPIC 选项编译源文件,生成位置无关代码(Position Independent Code)的目标文件。-fPIC 选项确保生成的代码可以被加载到内存的任意位置,适用于动态库的特性。执行以下命令:

gcc -fPIC -c add.c sub.c

这将生成 add.osub.o 两个目标文件。

🚀3. 创建动态库

使用 gcc 编译器的 -shared 选项将目标文件链接成动态库。动态库文件通常以 lib 为前缀,以 .so 为扩展名。执行以下命令创建名为 libmath.so 的动态库:

gcc -shared -o libmath.so add.o sub.o

🔱 动态库的使用

🔱 1. 编写调用动态库的源文件,和提供声明的头文件

制作math.h头文件,它包含 addsub 函数的声明。

// math.h
#ifndef MATH_H
#define MATH_H

int add(int a, int b);
int sub(int a, int b);

#endif

使用以上制作出的动态库 libmath.so ,它包含 addsub 函数的实现。现在编写一个 main.c 文件来调用这些函数:

#include <stdio.h>
#include "math.h"
// 声明要调用的函数
int add(int a, int b);
int sub(int a, int b);

int main() {
    int result1 = add(3, 2);
    int result2 = sub(3, 2);
    printf("add result: %d\n", result1);
    printf("sub result: %d\n", result2);
    return 0;
}
🔱 2. 编译链接动态库

使用 gcc 编译器将 main.c 与动态库链接生成可执行文件。假设动态库 libmath.so 位于当前目录,执行以下命令:

gcc -o main main.c -L. -lmath

其中,-L. 表示在当前目录查找库文件,-lmath 表示链接名为 libmath.so 的库(去掉 lib 前缀和 .so 后缀)。

🔱 3. 运行可执行文件

unfound
执行main.c时发现找不到共享库。

ldd main //显示可执行文件依赖的动态链接库

unfound
原因:
执行main文件时未告诉加载器动态库在哪 ,上述生成可执行文件main时只告诉了编译器动态库的位置.

由于动态库在运行时才被加载,系统需要知道动态库的位置。如果动态库不在系统默认的搜索路径中,可以通过以下几种方式解决:

  1. 直接安装到系统lib64目录或者/lib/x86_64-linux-gnu/下
  2. 在lib64目录或者/lib/x86_64-linux-gnu/下建立软连接指向动态库
  3. 导入环境变量将自己的库所在路径,添加到系统环境变量LD_LIBRARY_PATH中
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/shiyue/liba
  1. 在/etc/ld.so.conf.d 建立一个以.conf结尾的文件,将库所在目录添入文件中去 让后执行ldconfig即可

使用以上第三种方案
ldd
成功执行!!!
在这里插入图片描述


http://www.kler.cn/a/517084.html

相关文章:

  • C#编程:List.ForEach与foreach循环的深度对比
  • vim在命令模式下的查找功能
  • Redis内部数据结构--跳表详解
  • 【2024年华为OD机试】 (A卷,100分)- 微服务的集成测试(JavaScriptJava PythonC/C++)
  • 【算法篇】从汉明重量的基础理解到高效位运算优化详解
  • AI如何帮助解决生活中的琐碎难题?
  • 智能风控 数据分析 groupby、apply、reset_index组合拳
  • Cosmos学习记录
  • Databend x 沉浸式翻译 | 基于 Databend Cloud 构建高效低成本的业务数据分析体系
  • C++/CLI(Common Language Runtime)关键点详解
  • JDK14特性Java 原生代码编译工具jpackage
  • SpringBoot自定义实现触发器模型的starter
  • 【期末速成】软件设计模式与体系结构
  • 把网站程序数据上传到服务器的方法和注意事项
  • 针对业务系统的开发,如何做需求分析和设计?
  • 【数据结构】_基于顺序表实现通讯录
  • 在Docker 容器中安装 Oracle 19c
  • 编译Android平台使用的FFmpeg库
  • 【玩转全栈】----YOLO8训练自己的模型并应用
  • 6. 马科维茨资产组合模型+政策意图AI金融智能体(DeepSeek-V3)增强方案(理论+Python实战)