[RTOS 学习记录] 工程管理工具make及makefile

[RTOS 学习记录] 工程管理工具make及makefile

image-20240421150217202

这篇文章是我阅读《嵌入式实时操作系统μCOS-II原理及应用》后的读书笔记,记录目的是为了个人后续回顾复习使用。
前置内容:

开发工具 Borland C/C++ 3.1 精简版

文章目录

  • 1 make 工具
  • 2 makefile 的内容结构
  • 3 程序段标号的作用
    • 3.1 makefile 示例代码
    • 3.2 代码说明
    • 3.3 第一次运行
    • 3.4 第二次运行
    • 3.5 第三次运行
    • 3.6 结论
  • 4 makefile 实现编译、链接工作
    • 4.1 示例代码
    • 4.2 makefile 代码说明
    • 4.3 makefile 的执行
  • 5 程序段标号的目标作用
    • 5.1 makefile 示例代码
    • 5.2 伪目标
      • 5.2.1 第一次运行
  • 6 makefile 文件的命名
  • 7 makefile 中的变量

1 make 工具

一个开发平台提供给我们,用于管理工程或项目的实用程序,它可以按照我们用户编写的makefile脚本文件对工程项目进行管理。

2 makefile 的内容结构

makefile是一个脚本文件,文件内容中有许多我们在命令行中常常用到的各种命令。

makefile程序段的格式如下:

程序段的标号(target): 关联程序段1的标号 关联程序段2的标号 ...
	命令集
关联程序段1的标号:
	命令集
关联程序段2的标号:
	命令集
...

注意:命令集中的所有命令行必须缩进一个tab键。

一个makefile文件有若干个程序段,程序段的开头必须有一个target进行标注,区分各个程序段。不同的程序段之间可以进行关联,此时在target后面以空格为界罗列相关联程序段的target。每个程序段有一组实现工程项目管理的命令集。

3 程序段标号的作用

标号可以看作是对应程序段的名称,我们可以在make命令的后面使用标号来指定需要执行的程序段。

3.1 makefile 示例代码

按照makefile的内容格式编写一个makefile脚本文件,命名为makefile(makefile的默认名称):

mkdir1:
    md dir1
mkdir2:
    md dir2
rmdir:
    rd dir1
    rd dir2

3.2 代码说明

上面编写的makefile文件中一共有3个程序段:mkdir1、mkdir2 和 rmdir。作用分别是:

  1. mkdir1——在当前目录下创建一个名为dir1的文件夹
  2. mkdir2——在当前目录下创建一个名为dir2的文件夹
  3. rmdir——删除前面两个步骤创建的两个文件夹dir1和dir2

3.3 第一次运行

在命令行窗口中使用 cd EXP2_3 进入此次示例makefile文件所在的目录中,输入 make 命令并且回车执行。可以看到,执行完成后在当前目录新建了一个名为dir1的文件夹,如下图所示:

image-20240421154600345

根据执行结果,我们知道了make执行了makefile中的第一个程序段mkdir1,其余两个程序段mkdir2rmdir都没有被执行。

3.4 第二次运行

输入命令 make mkdir2 并且回车执行,可以看到,执行完毕后当前目录下又新建了一个名为dir2的文件夹,如下图所示:

image-20240421155052461

3.5 第三次运行

输入命令 make rmdir 并且回车执行,可以看到,执行后dir1和dir2这两个文件夹都被删除了,如下图所示:

image-20240421155302943

3.6 结论

当使用 make 命令时,makefile的第一个程序段会被执行,即makefile的首段程序段是make.exe的默认执行程序段,makefile的其他程序段需要执行时必须在make命令后面显式地指定标号。

4 makefile 实现编译、链接工作

由于makefile的程序段中的命令集中可以使用一切命令行命令,所以我们可以把源文件的编译和链接工作步骤编写到makefile中,然后通过执行makefile脚本文件“自动的”完成编译、链接工作。

4.1 示例代码

一个具有3个源文件应用程序的示例如下:

头文件 printA.h

#ifndef _PRINTA_H_
#define _PRINTA_H_

extern const char *msgA;

#endif

源文件 printA.c

#include "printA.h"

const char *msgA = "AAAAA";

头文件 printB.h

#ifndef _PRINTB_H_
#define _PRINTB_H_

extern const char *msgB;

#endif

源文件 printB.c

#include "printB.h"

const char *msgB = "BBBBB";

源文件 test.c

#include <stdio.h>
#include "printA.h"
#include "printB.h"

int main(void)
{
    unsigned char i = 0;
    
    for (i=0; i<5; i++)
    {
        printf("%s\n", msgA);
        printf("   %s\n", msgB);
    }
    
    return 0;
}

链接文件 TESTLINK

C:\BC\LIB\C0L.OBJ +
PRINTA.OBJ +
PRINTB.OBJ +
TEST.OBJ
TEST
TEST
C:\BC\LIB\CL.LIB

接下来就编写一个具有4个程序段的makefile脚本文件,实现源文件的编译、中间目标文件的链接,最终生成可执行文件TEST.EXE。

make脚本文件 makefile

##############################################
#             创建可执行文件(exe)
TEST.EXE:
    TLINK   @TESTLINK
    
##############################################
#           创建各个目标文件(obj)
PRINTA.OBJ:
    BCC -c -ml -IC:\BC\INCLUDE -LC:\BC\LIB PRINTA.C
PRINTB.OBJ:
    BCC -c -ml -IC:\BC\INCLUDE -LC:\BC\LIB PRINTB.C
TEST.OBJ:
    BCC -c -ml -IC:\BC\INCLUDE -LC:\BC\LIB TEST.C

4.2 makefile 代码说明

为了增强可读性,此次示例的makefile代码中使用了文件名称作为程序段的标号,而且该文件正是对应程序段的命令集中的命令所要实现的目标结果。

第2~4个程序段分别完成对3个源文件printA.c、printB.c和test.c的编译,然后得到3个中间目标文件printA.obj、printB.obj和test.obj。第1个程序段即首段程序段完成各个中间目标文件的链接,最终得到可执行文件TEST.EXE。

4.3 makefile 的执行

分别依次使用 make PRINTA.OBJmake PRINTB.OBJmake TEST.OBJmake 完成示例应用程序的编译、链接,如下图所示:

image-20240421165535513

image-20240421165621705

image-20240421165657126

image-20240421165732331

运行可执行程序 TEST.EXE,可以看到屏幕上重复5次打印了字符串,如下图所示:

image-20240421165907435

5 程序段标号的目标作用

前面的示例makefile文件中,我们使用了文件名:PRINTA.OBJPRINTB.OBJTEST.OBJ 作为它们各自程序段的标号,而该文件名对应的文件正是它的程序段命令集所要生成的文件,因此我们把满足这种关系的程序段标号又称作程序段的目标,例如:PRINTA.OBJ 是它对应程序段的目标,PRINTB.OBJ 是它对应程序段的目标,TEST.OBJ 是它对应程序段的目标等等。

我们前面已经提到了[makefile允许关联程序段](#makefile 的内容结构),即makefile允许我们把程序段编写成如下形式:

目标(标号): 生成目标所需的文件名(依赖文件,简称“依赖”)
	命令集

为了强调程序段目标与其所需文件之间的关系,我们把生成目标所需的文件称作依赖文件,简称依赖

因此,我们可以把一个工程的编译、链接工作所需的多个程序段关联起来,从而仅需要执行一次 make 命令即可完成所有的编译和链接工作。

对于上述示例的makefile来说,如果要把生成TEST.EXE文件的程序段和生成其依赖文件的程序段关联起来,那么按照上述格式,makefile的第一个程序段就为:

TEST.EXE: PRINTA.OBJ PRINTB.OBJ TEST.OBJ
	TLINK @TESTLINK

该程序段的含义是:本程序段的目标(标号)为 TEST.EXE,该目标(标号)需要由 PRINTA.OBJPRINTB.OBJTEST.OBJ 三个文件来生成,其命令则为 TLINK @TESTLINK

如果目标所依赖的文件都存在,满足生成目标所需要的条件,则连接命令 TLINK 被执行,否则程序会以 PRINTA.OBJPRINTB.OBJTEST.OBJ 为转移目标转向以它们为标号的程序段。也就是说,目标:依赖文件名 的这种格式是一种多分支条件转移语句。当生成目标的条件不满足(依赖文件不存在)时,程序的执行将要发生转移,其转移目标就是以依赖文件名为标号或目标的程序段。

实际上,make工具在执行makefile的各个程序段时,首先会检查目标(target)文件是否已经存在,如果存在,则会进一步检查该目标所依赖文件的时间戳(文件属性中的“创建时间”、“修改时间”等时间信息),只有当依赖文件比现有目标新时,其命令集才会被执行。其目的就是:尽量不做不必要的重复编译工作。

5.1 makefile 示例代码

为了格式上的整齐,凡是以目标为标号的程序段都要写上目标的依赖。

make 文件 makefile

##############################################
#             创建可执行文件(exe)
TEST.EXE: PRINTA.OBJ PRINTB.OBJ TEST.OBJ
    TLINK   @TESTLINK
##############################################
#           创建各个目标文件(obj)
PRINTA.OBJ: PRINTA.C PRINTA.H
    BCC -c -ml -IC:\BC\INCLUDE -LC:\BC\LIB PRINTA.C
PRINTB.OBJ: PRINTB.C PRINTB.H
    BCC -c -ml -IC:\BC\INCLUDE -LC:\BC\LIB PRINTB.C
TEST.OBJ: TEST.C PRINTA.H PRINTB.H
    BCC -c -ml -IC:\BC\INCLUDE -LC:\BC\LIB TEST.C

5.2 伪目标

由上可知,makefile的target有目标和标号两种作用:当它是文件名时,它既是标号也是目标;而当它只是一个标识时,它就是标号。听起来很混乱,所以为了明确起见,人们把makefile中的target全部叫做目标,把那种仅起标号作用的目标则叫做“伪目标”。
在makefile中,伪目标所对应的程序段是一个不与其他程序段相关联的程序段,所以在需要执行它们时,必须在make命令中显式地使用其标号,除非它是makefile的第一个程序段(几乎没人这样做)。它们通常被用来完成一些创建目录、删除目录、复制文件、移动文件及删除文件等项目管理任务。

例如,可以为示例makefile添加一个标号为 CLEAN 的伪目标代码段,该段的任务就是为了用户目录的整洁,在已生成了最终可执行文件后,删除那些中间目标文件 PRINTA.OBJPRINTB.OBJTEST.OBJ
修改后的makefile如下:

##############################################
#             创建可执行文件(exe)
TEST.EXE: PRINTA.OBJ PRINTB.OBJ TEST.OBJ
    TLINK   @TESTLINK
##############################################
#           创建各个目标文件(obj)
PRINTA.OBJ: PRINTA.C PRINTA.H
    BCC -c -ml -IC:\BC\INCLUDE -LC:\BC\LIB PRINTA.C
PRINTB.OBJ: PRINTB.C PRINTB.H
    BCC -c -ml -IC:\BC\INCLUDE -LC:\BC\LIB PRINTB.C
TEST.OBJ: TEST.C PRINTA.H PRINTB.H
    BCC -c -ml -IC:\BC\INCLUDE -LC:\BC\LIB TEST.C
CLEAN:
    DEL PRINTA.OBJ
    DEL PRINTB.OBJ
    DEL TEST.OBJ

5.2.1 第一次运行

使用 make 命令执行 makefile 的第一个程序段,生成最终可执行文件 TEST.EXE,如下图所示:

image-20240422091935127

image-20240422092035300

执行 make clean 表示显示地使用 CLEAN 参数执行 makefile 文件中的 CLEAN 程序段,将中间目标文件删除,如下图所示:

image-20240422092319854

image-20240422092334231

6 makefile 文件的命名

makefile是make文件的默认名称,如果用户不喜欢该名称,则完全可以自行对其进行命名(包括扩展名),但在make命令中要使用参数f,即:

make -f 文件名

7 makefile 中的变量

通常,在一个makefile中会有很多经常要重复使用的元素,例如示例makefile中的编译命令 BCC、编译命令中的参数 -c -ml -IC:\BC\INCLUDE -LC:\BC\LIB 等等。显然,用一些比较简洁且语义清楚的符号变量来表示它们更好,因此makefile允许人们定义变量。

变量格式:

变量名 = 变量的值

引用变量格式:

$(变量名)

使用变量改写示例makefile后,代码如下:

其中,前面带有符号“#”的为注释行;如果依赖文件表示行过长,也可以反斜杠“\”为换行符分行书写。

##############################################
#             makefile
##############################################
#        用变量来表示所使用的开发工具
BORLAND = C:\BC
CC = $(BORLAND)\BIN\BCC
LINK = $(BORLAND)\BIN\TLINK
##############################################
#               编译选项说明
#
# -l    生成80286实模式代码
# -c    编译为.obj文件
# -I    指示包含头文件所在路径
# -k    采用标准栈帧
# -L    指示库文件所在路径
# -ml   Large memory内存模式
# -n    指示生成目标文件的位置
##############################################
#             C编译选项变量
C_FLAGS = -c -ml -l -n.\ -k -I$(BORLAND)\INCLUDE -L$(BORLAND)\LIB
##############################################
#             链接选项变量
LINK_FLAGS = 
##############################################
#             创建可执行文件(exe)
TEST.EXE:       \
    PRINTA.OBJ      \
    PRINTB.OBJ      \
    TEST.OBJ
    $(LINK) $(LINK_FLAGS) @TESTLINK
##############################################
#           创建各个目标文件(obj)
PRINTA.OBJ:         \
    PRINTA.c        \
    PRINTA.h
    $(CC) $(C_FLAGS) PRINTA.c
PRINTB.OBJ:         \
    PRINTB.C        \
    PRINTB.H
    $(CC) $(C_FLAGS) PRINTB.C
TEST.OBJ:       \
    TEST.C      \
    PRINTA.H        \
    PRINTB.H
    $(CC) $(C_FLAGS) TEST.C
# 以下为伪目标代码段
CLEAN:
    DEL PRINTA.OBJ
    DEL PRINTB.OBJ
    DEL TEST.OBJ

运行结果如下图:

make

image-20240422094447941

image-20240422094550617

make clean

image-20240422094621696

image-20240422094647703

可以看到,使用变量后,make执行时会自动将makefile中引用的变量替换成变量的值。

参考资料:

《嵌入式实时操作系统μCOS-II原理及应用》

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【学习笔记二十四】EWM补货策略和自动补货配置

一、EWM补货策略概述 1.计划补货 ①以联机或批处理模式启动 ②根据最大和最小数量计算补货 ③仅当库存量低于最低数量时才开始 ④四舍五入至最小补货数量的倍数 2.自动补货 ①在WT确认期间启动 ②根据最大和最小数量计算补货 ③只有当库存量低于最低数量时才开始 ④四舍…

Linux thermal框架介绍

RK3568温控 cat /sys/class/thermal/thermal_zone0/temp cat /sys/class/thermal/thermal_zone1/temp cat /sys/class/thermal/cooling_device0/cur_state cat /sys/class/thermal/cooling_device1/cur_state cat /sys/class/thermal/cooling_device2/cur_state thermal_zone…

翻页电子图书制作小技巧分享给你

当今社会&#xff0c;二维码已经成为了信息传递的重要方式之一&#xff0c;其在电子商务、广告营销、活动推广等领域广泛应用。而如何将二维码巧妙地融入电子画册中&#xff0c;制作出高端、具有吸引力的作品&#xff0c;成为了许多设计师和营销人员关注的焦点 但是很多人却不知…

ABeam×StartUp丨蓝因机器人访问ABeam旗下德硕管理咨询(深圳)新创部门,展开合作交流

近日&#xff0c;深圳蓝因机器人科技有限公司&#xff08;以下简称“蓝因机器人”&#xff09;创始人陈卜铭先生来访ABeam旗下德硕管理咨询&#xff08;深圳&#xff09;有限公司&#xff08;以下简称“ABeam-SZ”&#xff09;&#xff0c;与新创部门展开合作交流。 交流中&am…

六西格玛管理培训:我的转变与成长之旅

4月初&#xff0c;我参与了天行健咨询的六西格玛管理培训&#xff0c;这次经历不仅极大地提升了我的工作效率&#xff0c;还帮助我在工作中实现了卓越。现在&#xff0c;我想分享一些我在这次培训中的学习心得和实践经验&#xff0c;希望能对正在寻求提升绩效和卓越之路的大家有…

【无线通信】OQPSK

调制 sps 8; RolloffFactor 0.2; FilterSpanInSymbols 10;bits randi([0, 1], 224*8, 1); % 1792symbols bits*2 - 1; % 1792 re -symbols(2:2:end); % 896 im -symbols(1:2:end); % 896pFilterTx comm.RaisedCosineTransmitFilter(...Shape, Square root, ...Rollo…

MySQL主从结构搭建

说明&#xff1a;本文介绍如何搭建MySQL主从结构&#xff1b; 原理 主从复制原理如下&#xff1a; &#xff08;1&#xff09;master数据写入&#xff0c;更新binlog&#xff1b; &#xff08;2&#xff09;master创建一个dump线程向slave推送binlog&#xff1b; &#xff…

GoJudge环境部署本地调用云服务器部署go-judge判题机详细部署教程go-judge多语言支持

前言 本文基于go-judge项目搭建&#xff0c;由于go-judge官网项目GitHub - criyle/go-judge: Sandbox Server in REST / gRPC API. Based on Linux container technologies.&#xff0c;资料太少&#xff0c;而且只给了C语言的调用样例&#xff0c;无法知道其他常见语言比如&am…

Python基础06-日期和时间的操作方法

在Python中处理日期和时间是编程中常见的需求&#xff0c;无论是安排任务、记录日志还是分析数据。本文将介绍如何在Python中获取当前日期和时间、创建特定日期和时间、格式化日期和时间、解析字符串中的日期和时间、使用时间差、比较日期和时间、从日期/时间中提取组件、处理时…

uni-app开发canvas绘图画画,如何实现后退功能

在uni-app中使用canvas进行绘图时&#xff0c;实现后退功能通常意味着你需要保存用户的每一步操作&#xff0c;然后提供一个机制来撤销最近的步骤。下面是一个基本的实现思路&#xff1a; 保存绘图步骤&#xff1a; 每当用户在canvas上绘制时&#xff08;比如通过touchMove事件…

出海不出局 | 小游戏引爆高线市场,新竞争态势下的应用出海攻略

出海小游戏&#xff0c;出息了&#xff01; 根据 Sensor Tower 近期发布的“2024 年 3 月中国手游收入 TOP30”榜单&#xff0c;出海小游戏在榜单中成了亮眼的存在。 其中&#xff0c;《菇勇者传说》3 月海外收入环比增长 63%&#xff0c;斩获出海手游收入增长冠军&#xff0c…

学习经验分享【33】YOLOv5 / YOLOv7 / YOLOv8 / YOLOv9 / RTDETR 基于 Pyside6 的图形化界面

大论文可以写两章关于算法创新模型&#xff0c;最后一章可以写对前两章提出方法进行封装&#xff0c;利用PyQT5搭建YOLOv5可视化界面&#xff0c;并打包成exe程序&#xff0c;构建检测平台实现简单的应用。用来凑大论文的字数和工作量&#xff0c;是简单又快速的方法&#xff0…

《龙之谷》游戏(客户端+服务端+视频架设教程+工具),本人收集的8个版本,云盘下载

龙之谷这个游戏本人觉得挺好玩的。你们可以下载研究一下看看&#xff0c;有能力的话&#xff0c;可以提取服务端文件出来&#xff0c;做成外网&#xff0c;让大家一起玩。。。。 《龙之谷》游戏&#xff08;客户端服务端视频架设教程工具&#xff09;&#xff0c;本人收集的8个…

WEB前端-笔记(三)

目录 一、事件 1.1类型 1.2对象 1.3页面加载事件 1.4滚动事件 1.5尺寸事件 1.6捕获&冒泡事件 1.7阻止表单提交 1.8全选案例 1.9事件委托 ​编辑 1.10client&offset 1.11换取元素的位置 1.12创建节点 1.13克隆节点 1.14删除节点 1.15setTimeout 1.16s…

【后端】PyCharm的安装指引与基础配置

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、PyCharm是什么二、PyCharm安装指引安装PyCharm社区版安装PyCharm专业版 三、配置PyCharm&#xff1a;四、总结 前言 随着开发语言及人工智能工具的普及&am…

MS1000TA超声波测量模拟前端

产品简述 MS1000TA 是一款超声波测量模拟前端芯片&#xff0c;广 泛应用于汽车工业和消费类电子。该芯片具有高度 的灵活性&#xff0c;发射脉冲个数、频率、增益及信号阈值 均可配置。同时&#xff0c;接收通道参数也可以灵活配置&#xff0c; 从而适用于不同尺寸容器、不…

Java——继承与组合

和继承类似, 组合也是一种表达类之间关系的方式, 也是能够达到代码重用的效果。组合并没有涉及到特殊的语法 (诸如 extends 这样的关键字), 仅仅是将一个类的实例作为另外一个类的字段。 继承表示对象之间是is-a的关系&#xff0c;比如&#xff1a;狗是动物&#xff0c;猫是动…

ROM修改进阶教程------安卓7_____安卓13去除签名验证操作步骤解析

同类博文: 安卓玩机搞机技巧综合资源-----修改rom 制作rom 解包rom的一些问题解析【二十一】_qcn改区域锁-CSDN博客 安卓系列机型rom修改。如果你删减了系统相关的app。那么严重会导致开机系统卡米 定屏等问题。这类一般都是系统签名验证导致的。而破解签名验证一般都是修改…

计算机java项目|springboot校园一卡通

作者主页&#xff1a;编程指南针 作者简介&#xff1a;Java领域优质创作者、CSDN博客专家 、CSDN内容合伙人、掘金特邀作者、阿里云博客专家、51CTO特邀作者、多年架构师设计经验、腾讯课堂常驻讲师 主要内容&#xff1a;Java项目、Python项目、前端项目、人工智能与大数据、简…

【Linux】文件系统——那就浅聊一下吧

前言 在上一篇文件描述符详解中谈论的都是打开的文件&#xff0c;但是在我们的系统中不仅有打开的文件还有许多未打开的文件&#xff0c;那么这些未打开的文件又该如何理解呢?阅读完本篇文章相信你会得到答案。 如果觉得文章内容对你有所帮助的话&#xff0c;可以给博主一键三…