静态链接库和动态链接库的创建



简介

  本项目实在 Ubuntu 20.04 环境下进行,目的是实现简单的矩阵生成和矩阵间运算,本质上是为了熟练掌握静态和动态链接库的生成与调用。项目中将矩阵的生成和运算功能分别生成两个链接库(分为静态和动态两种,共4个),在主程序(用于测试链接库功能)进行编译时,将链接库写进主程序的编译代码中即可。
  本博文为项目实现过程的记录,用于本人以后复习或者给有需要完成类似任务的人提供些许帮助。由于实现过程中会走一些弯路,若想要复现最好先通读一遍之后再进行尝试,避免被带进坑。


项目功能代码与使用流程

1、预处理

(1)调整各个文件的相对位置

原本所有文件处于同一目录下,按照如下结构进行整理(Makefile文件可以先不用管)
在这里插入图片描述
项目的部分代码位于附录中

(2)在两个库文件夹下分别使用 gcc -c 命令来得到 .o 文件
gcc -o Matrix_calculate.o -c Matrix_calculate.c # ./lib-Matrix_calculate文件夹下运行
gcc -o Matrix_generate.o -c Matrix_generate.c # ./lib-Matrix_generate文件夹下运行

出现如下报错
在这里插入图片描述

  由于之前 .h 文件与 main.c 文件放在同一个目录下,调整项目文件结构时忘记修改代码。因此出现相对路径有误找不到 .h 文件位置的情况。(原代码如下)
在这里插入图片描述

更改后如下(修改为正确的相对路径)
在这里插入图片描述

重新运行代码,编译成功
在这里插入图片描述

在另外一个库文件进行同样操作
在这里插入图片描述

(3)编写 Makefile 来得到动态链接库和静态链接库

  用 ar -r 命令来得到静态链接库,用 gcc 命令来得到动态链接库,然后通过 cp 命令将得到的链接库安装(即复制)到系统库(/usr/lib64/)。
  具体实现如下(以 Matrix_calculate 库为例,创建 Makefile 文件于 ./lib-Matrix_calculate 下)

LIB=Matrix_calculate
LIB_STATIC=lib$(LIB).a
LIB_DYNAMIC=lib$(LIB).so

library:$(LIB_STATIC) $(LIB_DYNAMIC)

$(LIB_STATIC):$(LIB).o
	ar -r lib$(LIB).a $^

$(LIB_DYNAMIC):$(LIB).c
	gcc -fPIC -shared -o $@ $^

install-static:$(LIB_STATIC)
	cp $^ /usr/lib64

install-dynamic:$(LIB_DYNAMIC)
	cp $^ /usr/lib64

.PHONY:clean
clean:
	rm *.o *.a *.so

而 Matrix_generate 库的 Makefile 文件只需将上面文件中第一行的 LIB 变量修改为 Matrix_generate 即可,其余不变。

(4)调用 Makefile 文件

输入 make 命令运行 Makefile 文件,得到静态(.a)和动态链接库(.so)。
在这里插入图片描述

另外一个库进行同样的操作,得到如下的目录。
在这里插入图片描述

2、静态编译

(1)调用本地的库

  先编译,为了编译时能够找到本地库的位置,需要用 -L 选项加上各个库的路径,具体命令如下。

gcc -o binary-static main.c -static -L../lib-Matrix_generate -lMatrix_generate -L../lib-Matrix_calculate -lMatrix_calculate

提示:原本 main.c 文件中 .h 文件的调用路径同样是错误的,需要同之前的操作一样修改其相对路径。

  编译成功,运行得到的可执行文件 ./binary-static,可以得到相应的输出,如下(输出内容看不清楚没关系,只要知道运行正常即可)
在这里插入图片描述

(2)安装到系统的库中

  分别在两个库文件下调用 Makefile 文件中的 install-static 命令。由于需要将库拷贝到系统库中,需要添加 sudo 指令,如下操作,完成安装。

sudo make install-static

在这里插入图片描述

(3)调用复制到系统的库

  上一步安装完库之后,即不需要 -L 选项明确库的具体位置,直接引入库的名称即可进行编译。

gcc -o binary-static main.c -static -lMatrix_generate -lMatrix_calculate

  编译时,再次显示没有找到文件。
在这里插入图片描述
  由于调用的是复制到系统的链接库,则应该摆脱对本地文件(.h)的依赖。为此,可以将两个 .h 文件拷贝到 /usr/include/ 目录下,操作如下(同样需要sudo指令)

sudo cp ../lib-Matrix_calculate/Matrix_calculate.h /usr/include/
sudo cp ../lib-Matrix_generate/Matrix_generate.h /usr/include/

在这里插入图片描述

编译成功并尝试运行,输出如下。
在这里插入图片描述

3、动态编译

(1)调用本地的库

相比于静态编译的命令,动态编译只需删去 -static 选项即可,如下。

gcc -o binary-dynamic main.c -L../lib-Matrix_generate -lMatrix_generate -L../lib-Matrix_calculate -lMatrix_calculate

在这里插入图片描述

运行动态编译得到的可执行文件出现报错,提示不能打开共享的目标文件。
在这里插入图片描述

为实现本地调用,可以通过设置临时的环境变量(重启会被删除),使得库的位置可以被找到,设置操作如下。

export LD_LIBRARY_PATH=../lib-Matrix_generate:$LD_LIBRARY_PATH
export LD_LIBRARY_PATH=../lib-Matrix_calculate:$LD_LIBRARY_PATH

再次执行./binary-dynamic,运行成功。
在这里插入图片描述

(2)安装到系统的库中并调用复制到系统的库(可重启使得之前设置的环境变量失效)

分别在两个库文件中将动态链接库复制到 /usr/lib64/ 目录下。

sudo make install-dymatic

在这里插入图片描述

发现该可执行文件无法运行
在这里插入图片描述

尝试将两个库文件拷贝到 /usr/lib 目录下(具体原因不清楚)
在这里插入图片描述
再次执行,成功
在这里插入图片描述

4、简化项目

  之前的操作均在终端下进行,为了方便运行和代码复用,可通过编写 Makefile 文件来实现。

(1)文件结构

在这里插入图片描述
  需要先根据之前的操作得到静态链接库和动态链接库。

(2)Makefile 文件编写

  若看完之前在终端下的操作则会发现,其实 Makefile 文件就是之前代码的结合,只是使用了一些 Makefile 的语法使得代码更加简洁且方便复用。

MG=Matrix_generate
MC=Matrix_calculate
OBJ_S=binary_static
OBJ_D=binary_dynamic
ST=static
MA=main.c

# 调用本地库
localtest:
	# 静态编译
	gcc -o $(OBJ_S) ./test/$(MA) -$(ST) -L./lib-$(MG)/ -l$(MG) -L./lib-$(MC)/ -l$(MC)
	# 动态编译
	gcc -o $(OBJ_D) ./test/$(MA) -L./lib-$(MG)/ -l$(MG) -L./lib-$(MC)/ -l$(MC)
	
# 安装到系统
install:
	# 安装静态编译库
	cp lib-$(MG)/lib$(MG).a /usr/lib64
	cp lib-$(MC)/lib$(MC).a /usr/lib64
	# 安装动态编译库
	cp lib-$(MG)/lib$(MG).so /usr/lib
	cp lib-$(MC)/lib$(MC).so /usr/lib

# 调用复制到系统的库
installtest:
	# 将.h文件复制到/usr/include目录下
	cp lib-$(MG)/$(MG).h /usr/include
	cp lib-$(MC)/$(MC).h /usr/include
	# 调用静态编译库
	gcc -o $(OBJ_S) ./test-install/$(MA) -$(ST) -l$(MG) -l$(MC)
	# 调用动态编译库
	gcc -o $(OBJ_D) ./test-install/$(MA) -$(ST) -l$(MG) -l$(MC)

  测试过程会发现原先编写的 Makefile 文件有错误,在后面的测试过程会不断进行更改。上述代码是最终测试无误的 Makefile 文件的内容。

(3)调用本地的库

多次调用,发现一直出现如下的提示
在这里插入图片描述

经过观察发现当前目录下存在 test 目录,这可能导致命令的运行出现歧义
在这里插入图片描述

更改 Makefile 文件,将 test 命令改成 localtest ,再次调用。如下(运行成功)

make localtest

在这里插入图片描述

查看得到的目标文件
在这里插入图片描述

尝试运行得到的可执行文件(由于输出较长,只截取部分)
在这里插入图片描述
在这里插入图片描述

(4)安装库至系统

执行 make install,由于命令会更改系统文件,需要使用sudo命令执行。

sudo make install

在这里插入图片描述

(5)调用复制到系统的库

执行 make installtest 命令,也需要使用 sudo 指令。

sudo make installtest

在这里插入图片描述
得到目标文件
在这里插入图片描述
运行目标文件(由于输出较长,只截取部分)
在这里插入图片描述
在这里插入图片描述

附录

  本附录提供Matrix_generate.h、Matrix_calculate.h、./test/main.c 与 ./test-install/main.c 文件的实现,目的是让需要的人了解本项目的基本功能。没有提供 .c 文件的实现是因为代码实现难度并不大,且本人编程修为较低,写的代码实在丑陋怕惹人笑话。而本项目主要记录的是与链接库有关的知识,读者应该也有自己的项目,所以所有代码放上来作用不大反而占空间。仅作参考。

Matrix_generate.h

#ifndef MATRIX_GENERATE_H
#define MATRIX_GENERATE_H

#include<stdio.h>

int** generate_matrix(int m,int n,int range); // 生成 m*n 矩阵并在 range 范围内随机初始化
void set_value(int** M,int m,int n,int i,int j,int value); // 将 m*n 矩阵 M 的第 i 行第 j 列设置为 value
void print_Matrix(int** M,int m,int n); // 打印矩阵的值

#endif

Matrix_calculate.h

#ifndef MATRIX_CALCULATE_H
#define MATRIX_CALCULATE_H

int** matrix_add(int** M1,int **M2,int m,int n); //矩阵相加
int** matrix_multiply(int** M1,int m1,int n1,int** M2,int m2,int n2); //矩阵相乘
int** matrix_merge(int** M1,int m1,int n1,int** M2,int m2,int n2,int K); //矩阵合并
int** matrix_subsetting(int** M,int m,int n,int i,int j); //取子集

#endif

./test/main.c

#include<stdio.h>
#include<unistd.h>
#include "../lib-Matrix_calculate/Matrix_calculate.h"
#include "../lib-Matrix_generate/Matrix_generate.h"
int main(){
	//矩阵相加
	int** M1 = generate_matrix(1,3,10);
	printf("M1:\n");
	print_Matrix(M1,1,3);
	sleep(1);
	int** M2 = generate_matrix(1,3,10);
	printf("M2:\n");
	print_Matrix(M2,1,3);
	int** M_add = matrix_add(M1,M2,1,3);
	printf("M1 + M2 = M_add\n");
	printf("M_add:\n");
	print_Matrix(M_add,1,3);
	printf("\n\n");
	

	//矩阵相乘
	sleep(1);
	int** M3 = generate_matrix(3,1,10);
	printf("M3:\n");
	print_Matrix(M3,3,1);
	int** M_multi = matrix_multiply(M1,1,3,M3,3,1);
	printf("M1 * M3 = M_multi\n");
	printf("M_multi:\n");
	print_Matrix(M_multi,1,1);
	printf("\n\n");

	//矩阵上下合并
	int** M_merge = matrix_merge(M1,1,3,M2,1,3,1);
	printf("M1 merge M2 up and down is M_merge\n");
	printf("M_merge:");
	print_Matrix(M_merge,2,3);
	printf("\n\n");

	//取子集
	int** M_sub = matrix_subsetting(M_merge,2,3,1,2);
	printf("M_merge 's subsetting is M_sub\n");
	printf("M_sub:\n");
	print_Matrix(M_sub,1,2);
	printf("\n\n");

	return 0;
}

./test-install/main.c
安装到系统之后不需要使用相对路径

// 对./test/main.c文件的3、4行进行如下修改即可

// #include "../lib-Matrix_calculate/Matrix_calculate.h"
// #include "../lib-Matrix_generate/Matrix_generate.h"
#include "Matrix_calculate.h"
#include "Matrix_generate.h"
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值