【Linux】实验二 Makefile 的编写及应用

news2025/3/1 3:36:32

静态和动态库的转换可以参考这篇文章哦!!

文章目录

  • 实验二 Makefile 的编写及应用
    • 实验目的
    • 实验内容
    • 具体步骤:
      • 一、进入文件夹
      • 二、生成各个.c .h文件
        • 1. exam.h
        • 2. exam.c
        • 3. mat.h
        • 4. mat.c
        • 5. main.c
      • 三、编译建立的文件
        • 1. 只编译不链接 main.o
        • 2. 使用 file 查看 main.o 的格式,并尝试执行 main.o
        • 3. 对 main.o 进行链接,并尝试执行
      • 四、将 mat.o exam.o 做成`静态库`,并静态链接执行
        • 1. 重新编译 mat.c 和 exam.c 生成静态库文件
          • 1.1 重新编译 mat.c 和 exam.c 文件
          • 1.2 将 mat.o 和 exam.o 打包到静态库中
        • 3. 链接 main.o 和静态库文件并执行
        • 4. 执行
      • 五、将 mat.o exam.o 做成`动态库`,动静态链接执行
        • 1. 生成对应的目标文件, 适用于动态库编译
        • 2. 将 mat.o 和 exam.o 打包到动态库中
        • 3. 链接 main.o 和动态库文件并执行
        • 4. 执行
  • 每天进步一点点 笔记仅供自学,用来回看复习,不一定适合你,如有错误请指出。

实验二 Makefile 的编写及应用

实验目的

  1. 掌握 GCC 编译与链接的基本使用方式、测试编译流程
  2. 了解 Makefile 的基本概念和基本结构.
  3. 初步掌握编写简单 Makefile 的方法.
  4. 了解递归 Make 的编译过程
  5. 初步掌握利用 GNU Make 编译应用程序的方法

实验内容

1、完成一个在字符界面下的小学数学教学软件。该软件主要实现计算机自动出题,使用者回答
问题,计算机判断对错,测试结束后给出成绩。程序的整体流程如图 3-1 所示。
2、首先用 vi 编写基本程序,
3、对代码进行编译,链接,并执行查看效果
4、编写 Makefile 实现自动化编译
在这里插入图片描述

具体步骤:

一、进入文件夹

切换到桌面(个人习惯)

cd ./Desktop/

生成单个文件夹

mkdir MathExam

切换到生成的文件中

cd ./MathExam/

二、生成各个.c .h文件

1. exam.h

vi exam.h
#ifndef EXAM_H
#define EXAM_H
#include "mat.h"
int GetExamNum(); //获取一次练习的题目数
void SetExamNum(int num); //设置一次练习的题目数
void PrintFormula(Formula *formula, int IsPrintAns); //显示算式
int ExamFormula(Formula *formula); //出题,并自动检查每题算式的答案是否正确
void ExamPaper(); //根据设置的题目数,调用 ExamFormula()并完成整份练习的得分统计
#endif

2. exam.c

vi exam.h
#include "exam.h"

int ExamPaNum = 5; //设置出题数 

//获取一次练习的题目数
int GetExamNum() 
{
	return ExamPaNum;
}

//设置一次练习的题目数
void SetExamNum(int num)
{
	 ExamPaNum= num;
}

//显示算式
void PrintFormula(Formula *formula, int IsPrintAns)
{
	int op1,op2,Optype;
	op1 = formula->Op1;
	op2 = formula->Op2;
	Optype = formula->OpType;
	printf("%d%c%d=%d\n",op1,Optype,op2,IsPrintAns);
}

int CorrectCnt=0;
//出题,并自动检查每题算式的答案是否正确
int ExamFormula(Formula *formula)
{
	int youAnswer,correctAnswer;
	correctAnswer = formula->Answer;
	scanf("%d",&youAnswer);
	if(correctAnswer== youAnswer)
	{
		CorrectCnt++;
		printf("回答正确!!\n");
	}
	else
	{
		printf("回答错误!!\n");
		printf("正确答案如下:");
		PrintFormula(formula,correctAnswer);
	}
}

//根据设置的题目数,调用 ExamFormula()并完成整份练习的得分统计
void ExamPaper()
{
	CorrectCnt = 0;//重新考试则把得分清空 
	int preDiff;
	preDiff = GetMaxNum();
	printf("当前题目数量为%d\n",ExamPaNum);
	printf("当前的题目的难度是%d.\n", preDiff);
	Formula formulator;
	Formula *formula = &formulator;
	int E_cnt;
	for(E_cnt=0; E_cnt < ExamPaNum; E_cnt++)
	{
		printf("第%d题为:",E_cnt+1);
		GetRandFormula(formula);
		SetAnswer(formula);
		ExamFormula(formula);
		printf("------------:\n");
	}
	printf("您的最终得分为:%d\n",CorrectCnt);

}

3. mat.h

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#ifndef MAT_H
#define MAT_H
//定义加/减/乘/除四种运算符
#define MT_ADD 0
#define MT_SUB 1
#define MT_MUL 2
#define MT_DIV 3
 
typedef struct _Formula 
{
	int Op1; //操作数 1
	int Op2; //操作数 2
	char OpType; //运算符:加/减/乘/除
	int Answer; //结果
} Formula;
int GetMaxNum();
void SetMaxNum(int max); //设置计算的最大数
int GetRandOp(); //随机获取 4 种运算符中的一种
char OpTypeToChar(int optype); //整型的运算符转为字符型运算符
void SetAnswer(Formula *formula);//记录算式的正确答案
void GetRandFormula(Formula *formula); //生成随机算式
#endif

4. mat.c

#include "mat.h"
int maxDifficulu=1;//设置初始难度为1 

//获取当前题目难度 
int GetMaxNum()
{
	return maxDifficulu;
}

//设置计算的最大数
void SetMaxNum(int max) //设置计算的最大数
{
	if(max>3)
	{
		printf("难度最大为3,以帮您设置为最大难度\n");
		maxDifficulu = 3;
	}
   maxDifficulu = max;
}

//随机获取 4 种运算符中的一种
int GetRandOp() 
{
	int optype=0;
	srand((unsigned)time(NULL));
	optype=rand()%4;	 //theop就是你要的随机运算符。
	return optype; 
}

//整型的运算符转为字符型运算符
char OpTypeToChar(int optype)
{
	char opType;
	char op[4] = {'+','-','*','/'};
	opType=op[optype];
	return opType;
}


//记录算式的正确答案
void SetAnswer(Formula *formula)
{
	int op1,op2;
	int result;
	char opType;

	op1 = formula->Op1;
	op2 = formula->Op2;
	opType = formula->OpType;
	
	if(opType == '+') 
	{
		result = op1+op2;
	}
	else if(opType == '-') 
	{
		result = op1-op2;
	}	
	else if(opType == '*') 
	{
		result = op1*op2;
	}
	else if(opType == '/') 
	{
		result = op1/op2;
	}
	formula->Answer = result;
}

//生成随机算式
void GetRandFormula(Formula *formula)
{
	char opType;
	int temp_op1,temp_op2;
	Formula temp_formula;
	
	srand((unsigned)time(NULL));
	//按照相应的难度出题 
	if(maxDifficulu == 1)
	{
		temp_op1 = rand()%10;
		temp_op2 = rand()%10+1;
	}
	if(maxDifficulu == 2)
	{
		temp_op1 = rand()%30;
		temp_op2 = rand()%30+1;
	}
	if(maxDifficulu == 3)
	{
		temp_op1 = rand()%50;
		temp_op2 = rand()%50+1;
	}
	
	opType=OpTypeToChar(GetRandOp());
	formula->OpType = opType;
	formula->Op1 = temp_op1;
	formula->Op2 = temp_op2;
	printf("%d%c%d=",formula->Op1,formula->OpType,formula->Op2);
}

5. main.c

#include "mat.h"
#include "exam.h"

int PrintMenu();
void ChangeDifficulty();
void ChangeScale();
int main() 
{
	int choice;
	printf(" * Maths Exam *\n");
	do {
		choice = PrintMenu();
		switch (choice) 
		{
			case 1:
				ExamPaper();
				break;
			case 2:
				ChangeDifficulty();
				break;
			case 3:
				ChangeScale();
				break;
			case 4:
				printf ("Goodbye!\n");
				break;
			default:
				printf("Wrong Choice!\n");
				break;
		}
	} while (choice != 4);
	return 0;
}

int PrintMenu() 
{
	int choice;
	printf("Main Menu:\n");
	printf(" 1) Exam; 2) Set Difficulty; 3) Set Scale; 4) Quit\n");
	printf("Choice: ");
	scanf("%d", &choice);
	return choice;
}

void ChangeDifficulty() 
{
	int preDiff,nexDiff;
	preDiff = GetMaxNum();
	printf("当前的题目的难度是%d.\n", preDiff);
	printf("---------------------\n");
	printf("= 本程序共有以下难度 =\n");
	printf("= 1:10以内的计算题  =\n");
	printf("= 2:30以内的计算题  =\n");
	printf("= 3:50以内的计算题  =\n");
	printf("---------------------\n");
	printf("请选择难度: ");
	scanf("%d", &nexDiff);
	SetMaxNum(nexDiff);
}

void ChangeScale() 
{
	int examnum;
	printf("当前的试题数量为 %d.\n", GetExamNum());
	printf("---------------------\n");
	printf("输入设置新的试题数量: ");
	scanf("%d", &examnum);
	SetExamNum(examnum);
}

三、编译建立的文件

1. 只编译不链接 main.o

gcc -c main.c

可以发现当前文件夹下多了一个 main.o 文件

2. 使用 file 查看 main.o 的格式,并尝试执行 main.o

file main.o

会打印出 log:“main.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped”
表明 main.o 实际上是一个 relocatable 文件。

修改 main.o 的文件属性(权限)为可执行:

chmod 777 main.o

再尝试执行 main.o 文件:

./main.o

此时是执行不了的

在这里插入图片描述

3. 对 main.o 进行链接,并尝试执行

那么怎样才能生成可执行文件呢? 可执行文件需要通过链接来生成。
使用 gcc 将 main.o 链接为 matexam 文件:

gcc –c mat.c exam.c
gcc mat.o exam.o main.o -o matexam

通过 ls 命令查看当前目录下是否生成源代码 mat.c exam.c main.c 所对应的 object 文件 mat.o ;
exam.o main.o 和可执行文件 matexam,运行可执行文件 matexam,并记录运行结果。

./matexam

在这里插入图片描述


四、将 mat.o exam.o 做成静态库,并静态链接执行

这一步可以再生成个文件夹,我生成了个 static

1. 重新编译 mat.c 和 exam.c 生成静态库文件

1.1 重新编译 mat.c 和 exam.c 文件
gcc –c mat.c exam.c main.c

在这里插入图片描述

1.2 将 mat.o 和 exam.o 打包到静态库中
ar rc libexam.a mat.o exam.o

生成 libexam.a 静态库文件

![在这里插入图片描述](https://img-blog.csdnimg.cn/10534d01b78140e19d6ad398030e73d5.png

使用 file 查看 libexam.a:

file libexam.a

在这里插入图片描述

可以看到说明:“libexam.a: current ar archive”
实际上 libxxx.a 只是将指定的.o 文件打包汇集在一起,它的本质上还是 relocatable 文件集合。

3. 链接 main.o 和静态库文件并执行

gcc -o main2 main.o -L./ -lexam 

在这里插入图片描述

说明 1: -L./ 表明库文件位置在当前文件夹
说明 2: -lexam 表示链接 libexam.a 文件,使用“-l”参数时,前缀“lib”和后缀“.a”是需要省略
的。

4. 执行

./main_static

在这里插入图片描述


五、将 mat.o exam.o 做成动态库,动静态链接执行

这一步可以再生成个文件夹,我生成了个 dynamic

1. 生成对应的目标文件, 适用于动态库编译

gcc -fPIC -c exam.c mat.c main.c

必须要加 -fPIC 参数,不然会有下面的报错

在这里插入图片描述

在这里插入图片描述

2. 将 mat.o 和 exam.o 打包到动态库中

gcc -shared -fpic -olibfunc.so mat.o exam.o 

动态库打包,-fPIC: 生成与位置无关的代码

在这里插入图片描述

3. 链接 main.o 和动态库文件并执行

gcc main.o -o test -lfunc -L. 

最终链接 -L 指出动态库路径 -o 指出动态库名称

在这里插入图片描述

4. 执行

./test

可能会遇到的错误:error while loading shared libraries: libxxx.so通用解决方法
在这里插入图片描述


每天进步一点点 笔记仅供自学,用来回看复习,不一定适合你,如有错误请指出。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/9420.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue实现任意内容展开 / 收起功能组件

博主介绍 &#x1f4e2;点击下列内容可跳转对应的界面&#xff0c;查看更多精彩内容&#xff01; &#x1f34e;主页&#xff1a;水香木鱼 &#x1f34d;专栏&#xff1a;后台管理系统 文章目录 简介&#xff1a;这是一篇有关【Vue实现任意内容展开 / 收起功能组件】的文章&am…

1.jdk,数据类型,运算符

Java语言跨平台性的解释 一次编译&#xff0c;到处运行 将.java文件编译成.class文件&#xff0c;然后就可以在linux&#xff0c;windows运行。 java的跨平台的实现是通过在不同的操作系统上的不同的jvm差异来实现跨平台的 jdk jdk jre&#xff08;jvmjavase核心类库&…

MySQL基础操作总结_CRUD

文章目录 1.新增 insert 1.1 单行数据全列插入 1.2 多行数据指定列插入 2.查询 select 2.1 全列查询 2.2 指定列查询 2.3 查询字段包含表达式 2.4 别名 2.5 去重:distinct 2.6 排序:order by 2.7 条件查询 2.7.1 where条件查询 2.7.2 and与or查询 2.7.3 范围查…

Java简介

Java是一门面向对象的编程语言&#xff0c;不仅吸收了C语言的各种优点&#xff0c;还摒弃了C里难以理解的多继承、指针等概念&#xff0c;因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表&#xff0c;极好地实现了面向对象理论&#xff0…

Matplotlib 基础入门知识点总结

目录 1、绘图的一些基本命令展示 2、Matplotlib 绘制网格 3、plt.gca() 对坐标轴的操作 4、 图表的样式参数设计 5、创建图形对象 6、绘制多子图 1.add_axes()&#xff1a;添加区域 2. subplot()函数&#xff0c;可以均等的划分画布 3.subplots()函数详解 7、柱形图的…

踩坑List.addAll抛出UnsupportedOperationException

转载标明出处: 公司内部博客,作者 居xx, 在此表示感谢 1、我自己遇到的问题 try { // 不加try..catch报错 java.lang.UnsupportedOperationException: null ,原因未知list.addAll(a.getResult());list.addAll(b.getResult());list.addAll(c.getResult());list.addAll(d.getResu…

双软认证是指哪两项证书认证

一、双软认证是指哪两项证书认证&#xff1a; “双软认证”&#xff1a;指软件产品等登记和软件企业认定&#xff1b;企业申请双软认证&#xff0c;除了获得软件企业和软件产品的认证资格外&#xff0c;也可以使企业享受国家对软件行业提供的税收优惠政策。 二、认证的好处 1、…

后量子密码学中的模数是多少?

密码学&#xff1a;后量子密码学中的模数是多少&#xff1f; 只要是从事网络安全或安全软件开发的人&#xff0c;就都可能已经了解过公钥加密以及在20世纪70年代末和80年代前后创建的方法。现在我们可能需要学习更多的理论&#xff0c;因为我们所学的方法可能会受到量子计算机的…

网页字体图标用法

目录前言引用流程1、打开网页2、选择自己喜欢的图标加入购物车3、下载图标4、引用引用前言 1、接下来介绍引用图标都是免费的&#xff0c;可以放心食用。 2、标签可以自己设计&#xff0c;用css、svg画图或者引用图片都可以。但我们设计的很难超过专业人员的设计。引用图片的画…

深入理解mvcc机制(详解)

深入理解mvcc机制一&#xff0c;MVCC定义1&#xff0c;undolog日志2&#xff0c;undolog版本控制链3&#xff0c;readView3.1&#xff0c;readview简介3.2&#xff0c;readview和undolog结合使用规则3.3&#xff0c;readview和undolog基本使用4&#xff0c;总结一&#xff0c;M…

Java学习----前端3

今日学习内容如下&#xff1a; JavaScript JavaScript是一种基于对象和事件驱动的客户端脚本语言动态、弱类型、基于原型&#xff0c;内置了支持类 解释器称为 JS 引擎&#xff0c;内置于浏览器中 ECMA 欧洲计算机制造商协会Hello world <input type"button" on…

与git相关错误的究极解决方案

没有科学上网导致的git推送和拉取错误&#xff0c;严重阻碍了搬砖进度&#xff0c;遇到的与git有关的错误&#xff1a; 1. gnutls_handshake() failed: The TLS connection was non-properly terminated. 2. Failed to connect to github.com port 443:connection timed out …

Postman 如何获取请求结果并设置到请求头中

目录1.设置环境变量2.获取token&#xff0c;并赋值给环境变量3.将环境变量添加到请求头Postman&#xff1a; 是一款用于接口调试和测试的开发工具&#xff0c;功能强大&#xff0c;使用简单。 无论是开发人员进行接口调试&#xff0c;还是测试人员做接口测试&#xff0c;Postma…

本地生活小程序有什么功能_本地生活小程序的优势

对于平台运营方 痛点&#xff1a;社区团购毛利偏低 零售行业竞争激烈&#xff0c;单纯依靠社区团购卖货整体毛利率较低 手中大量用户&#xff0c;缺少好的变现模式&#xff0c;迫切需要提升盈利能力。 优势&#xff1a;提升盈利&#xff0c;解决流量变现 本地生活属于轻资产…

8Manage:千万别忽视了供应商绩效管理

供应商绩效管理是采购管理流程中的一部分&#xff0c;现代企业几乎都会对供应商实行绩效考核。绩效管理的主要目的是了解供应商的表现、促进供应商改进&#xff0c;并为工业商奖励、供应商优化提供依据&#xff0c;以此来发现优质的供应商&#xff0c;及时改进不合格的供应商。…

Python控制自己的手机摄像头拍照,并把照片自动发送到邮箱

前言 嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 又到了学Python时刻~ 今天这个案例&#xff0c;就是控制自己的摄像头拍照&#xff0c; 并且把拍下来的照片&#xff0c;通过邮件发到自己的邮箱里。 想完成今天的这个案例&#xff0c;只要记住一个重点&#xff1a;你…

CSDN的MD编辑器【写作技巧】

CSDN的MD编辑器【写作技巧】在线LaTeX公式的编辑器快捷键&#xff0c;结合快捷键提高效率写作技巧在线LaTeX公式的编辑器 推荐去https://www.latexlive.com/在线LaTeX公式编辑器 将写好的公式代码复制过来。 然后复制在CSDN编辑器里面前后加上符合$就行了 前后加两个该符合就会…

Java环境安装即配置

一、java1.8的安装步骤 1 安装目录创建java文件夹 在想要安装java的目录下创建一个java文件夹,不能出现特殊符号和汉字、空格等 2 java文件夹内创建jdk和jre Java安装需要两部分,一个jdk一个jre 所以在java文件夹中创建两个文件夹 3 解压安装包 通过百度网盘分享的文件&#…

【论文精读3】MVSNet系列论文详解-P-MVSNet

P-MVSNet全名为“P-MVSNet: Learning Patch-wise Matching Confidence Aggregation for Multi-View Stereo”&#xff0c;名字当中反映了论文的核心模块即基于学习方法的分块匹配置信聚合模块&#xff0c;乍一看有点难理解&#xff0c;但看完本文肯定很清楚啦。 本文是MVSNet系…

mysql 数据库使用分享(多图解析)

1、大体流程 1.1 一些概念 1.1.1 RDBMS 关系型数据库&#xff0c;是指采用了关系模型来组织数据的数据库&#xff0c;其以行和列的形式存储数据&#xff0c;类似excel 1.1.2 OLAP 和 OLTP OLTP(Online transactionprocessing):在线/联机 事务 处理。主要是对数据库中的数据…