静态库/动态库的制作和使用

初始目录如图,文件内容在本文末尾

1.静态库

1.静态库的概念和特点

1. 静态库的概念

静态库(.a文件)在编译时直接嵌入到可执行程序中,包含多个目标文件(.o)的集合。程序运行时无需外部依赖,但会增加可执行文件体积。

2. 静态库的特点

优点:

  • 编译后与程序完全绑定(意味着使用简单)
  • 无需运行时加载库文件(意味着速度更快)

缺点:

  • 库更新需重新编译程序
  • 相同库在多程序中重复占用内存

2.静态库的制作和使用(Linux)

1.生成目标文件

#gcc -c 源文件清单 -I 指定所需的自定义头文件目录
 gcc -c add.c sub.c mult.c div.c -I ../include/

-c​ 表示仅编译,生成目标文件(.o文件)但不进行链接

执行后会生成:add.o sub.o mult.o div.o

2.打包生成静态库

ar rcs cala.a add.o sub.o mult.o div.o

rcs替换旧成员        创建新库        添加索引

3.静态库的使用

gcc main.c cala.a -o app.exe -I ../include
./app

使用 -I 制定静态库的位置

此时可执行文件 app已包含所有库代码

可以将 app 移动到其他位置,依然可以正常运行

2.动态库

1.动态库的概念和特点

1.动态库的概念

动态库(.so文件)在程序​​运行时​​加载,可被多个程序共享。库更新后,程序无需重新编译。

2.动态库的特点

优点:

  • 多个程序共享内存中的同一份库

  • 库更新无需重新编译程序

缺点:

  • 运行时需确保库路径正确(意味着使用麻烦,容易出错)

  • 增加运行时加载开销(意味着速度稍慢)

2.动态库的制作和使用(Linux)

将整个工作区恢复到初始目录的样子

1.生成目标文件(位置无关的目标文件)

# 使用 -fPIC 编译选项制定生成位置无关目标文件
gcc -c add.c sub.c mult.c div.c -fPIC -I ../include/

静态库(.a)在链接时固定地址,无需位置无关性

动态库(.so)需在运行时加载到任意内存地址,必须位置无关

同样生成四个.o目标文件

2.创建动态库

gcc -shared -o libcala.so add.o sub.o mult.o div.o

3.动态库的使用

# 编译链接动态库
gcc main.c -o app.exe -L./ -lcala -I ../include

# 运行时指定库路径
export LD_LIBRARY_PATH=./:$LD_LIBRARY_PATH
./app

-L./ : 指定库搜索路径(为 ./ 即当前目录)

-lcala: 链接名为 libcala.so的库(无需给出前缀lib和后缀.so)

此时如果将app移动至其他位置,无法正确运行:

使用 ldd 查看 app 依赖的库:

可以发现确实找不到库文件
解决办法:

将当前目录加到环境变量 LD_LIBRARY_PATH

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:<动态库所在的目录>

使用 echo 查看是否成功添加

再运行 app,发现没有问题

但是在终端中修改 LD_LIBRARY_PATH  只有在这个终端中才生效,如果重新开一个终端又会运行不了,怎么解决?

前往用户目录,使用 vim 编辑 .bashrc 文件

vim编辑的方法本文不再赘述,网络上教程很多,到文件末尾然后添加:
将下面的 xxxxxxxxxxxxx/Part2/src 改为你自己的动态库的位置即可

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:xxxxxxxxxxxx/Part2/src

然后 ESC ,:wq 保存退出即可

之后只要动态库的位置 .bashrc 文件中关于动态库位置的设置不改变,无论 app 身在何处都可以正常运行。

3.补充

1.静态库动态库选择

静态库与动态库同时存在,编译器优先使用动态库。

静态库和动态库有各自的优缺点,根据实际情况选择较优的即可。

2.头文件与库文件区别

头文件仅仅只是.h 或 .hpp 文件,库文件是 .a 或 .so 文件,头文件没能成为库文件是因为头文件不如库文件通用,如果一个项目中某些模块被频繁使用,并且可以制作为库文件,则可以将其制作为库文件。还有一些代码提供商不愿意将源代码交给乙方,则可以将自己负责的代码制作为库文件打包给乙方,乙方只能使用,无法查看和修改源代码内容。

3.使用Makefile制作库文件

# 编译器设置
CC = gcc
CFLAGS = -Wall -g
INCLUDES = -I../include  # 头文件目录
LIB_DIR = -L.            # 库文件目录(当前目录)

# 库文件
STATIC_LIB = libcala.a   # 使用标准静态库命名
DYNAMIC_LIB = libcala.so # 使用标准动态库命名

# 最终可执行程序
STATIC_APP = app_static
DYNAMIC_APP = app_dynamic

# 源文件和目标文件
SRCS = add.c sub.c mult.c div.c
OBJS = $(SRCS:.c=.o)

# 所有目标
all: $(STATIC_APP) $(DYNAMIC_APP)

# 静态库目标
$(STATIC_LIB): $(OBJS)
	ar rcs $@ $^

# 动态库目标
$(DYNAMIC_LIB): $(OBJS)
	$(CC) -shared -o $@ $^

# 静态可执行程序
$(STATIC_APP): main.o $(STATIC_LIB)
	$(CC) main.o -o $@ $(LIB_DIR) -lcala

# 动态可执行程序
$(DYNAMIC_APP): main.o $(DYNAMIC_LIB)
	$(CC) main.o -o $@ $(LIB_DIR) -lcala

# 目标文件规则
%.o: %.c
	$(CC) $(CFLAGS) $(INCLUDES) -c $< -fPIC

main.o: main.c
	$(CC) $(CFLAGS) $(INCLUDES) -c $<

# 清理
clean:
	rm -f *.o *.a *.so $(STATIC_APP) $(DYNAMIC_APP)

# 测试目标
test: all
	@echo "=== Testing static application ==="
	./$(STATIC_APP)
	@echo "\n=== Testing dynamic application ==="
	LD_LIBRARY_PATH=. ./$(DYNAMIC_APP)

.PHONY: all clean test

Makefile 文件放在 src 目录下

执行 make

分别运行 app_static 和 app_dynamic

本文中使用的源文件如下:
 

// main.c

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

int main() {
    int a = 30, b = 5;
    printf("a=%d, b=%d\n", a, b);
    printf("add: %d\n", add(a, b));
    printf("sub: %d\n", sub(a, b));
    printf("mult: %d\n", mult(a, b));
    printf("div: %d\n", div(a, b));
    return 0;
}
// calculator.h

#ifndef CALCULATOR_H
#define CALCULATOR_H

int add(int x, int y);
int sub(int x, int y);
int mult(int x, int y);
int div(int x, int y);

#endif
// add.c

#include "calculator.h"

int add(int x, int y) {
    return x + y;
}
// sub.c

#include "calculator.h"

int sub(int x, int y) {
    return x - y;
}
// mult.c

#include "calculator.h"

int mult(int x, int y) {
    return x * y;
}
// div.c

#include "calculator.h"

int div(int x, int y) {
    if(y == 0) return 0; // 避免除零错误
    return x / y;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值