千家信息网

怎么进行Makefile分析

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,怎么进行Makefile分析,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。什么是MakefileMakefile是一个名
千家信息网最后更新 2026年11月03日怎么进行Makefile分析

怎么进行Makefile分析,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。

什么是Makefile

Makefile是一个名为GNU-Make软件所需要的脚本文件,该脚本文件可以指导Make软件控制arm-gcc等工具链去编译工程文件最终得到可执行文件,几乎所有的Linux发行版都内置了GNU-Make软件,VScode等多种IED也内置了Make程序。

你见到的xxx.mk文件或者Makefile都统称为Makefile脚本文件。

Makefile的规则

Makefile的规则如下,这里的[TAB]指键盘上的TAB按键,不是空格,如果在命令前输入了空格则会造成错误,并且在Makefile中TAB键不能随意使用:

目标 : 依赖

[TAB]命令

例如:

Hello :

@echo "Hello"

这时执行make命令就会输出一条语句"Hello",Hello是目标,依赖为空,为了生成目标,需要执行echo "Hello"语句,从而导致输出Hello。

例如:假设我们有一个Hello.c C语言源文件,需要将其编译不链接为Hello.o文件,最后在进行连接,Makefile内容如下:

Hello.out : Hello.o

gcc -o Hello.out Hello.o

Hello.o : Hello.c

gcc -c -o Hello.o Hello.c

这时执行make命令,make解释器发现目标为"Hello.out",但是生成Hello.out需要Hello.o,发现目录下找不到"Hello.o",就向下查找是否有生成Hello.o的规则,找到了,发现"Hello.o"依赖于"Hello.c",在目录下也找到了Hello.c,就执行语句"gcc -c -o Hello.o Hello.c"生成"Hello.o",只要编译过程不出错,即可得到"Hello.o",这时可以执行"gcc -o Hello.out Hello.o"生成"Hello.out"

从哪里开始分析?

这里可以用分析一个C语言或Java语言程序来类比,一般都是根据程序是执行流来进行分析,也就是先找到main函数,因为main函数是程序的执行入口,Makefile也有执行入口,在执行make命令时,make解释器默认搜索当前目录下名为"Makefile"的文件,找到后,执行生成第一个目标的命令及生成其依赖所需的命令。

这里选择在SDK/Targets目录中STM32L431_BearPi工程中的GCC目录下的Makefile开始分析。

第1行到第140行都是设置一些变量和导入一些makefile文件(其中也没有任何规则,都是进行一些变量的设置),第143行是第一条规则

当我们执行make或make all时,就开始生成all目标,其依赖于BUILD_DIR(GCC/build)目录中的TARGET(Huawei_LiteOS).elf文件,BUILD_DIR和TARGET为两个变量,一开始就被赋值,如下图所示,实际使用时$(变量)会被替换为变量的值,例如$(TARGET).elf最终会被替换为Huawei_LiteOS.elf。

可是Huawei_LiteOS.elf还不存在,make只好继续向下查找是否有生成Huawei_LiteOS.elf的规则,好在第147行的目标为Huawei_LiteOS.elf,这就是生成Huawei_LiteOS.elf的规则,该规则依赖为$(OBJ_DIRS) $(C_OBJ) $(S_OBJ)分别对应三个目录,这三个目录都不存在,所以make只好继续向下查找,它发现第152行正好为目标是该目录的规则,就创建了该目录,解决了$(OBJ_DIRS)这个依赖,接着该处理$(C_OBJ)这个依赖

Make向下查找依赖发现位于第156行出现生成这个以来的规则,这里的$(C_OBJ):$(BUILD_DIR)/%.o:%.c对应makefile中的静态模式,我这里简单的说一下,大家如果想深入了解可以自行百度。

静态模型的格式如下:

目标列表: 与目标列表相匹配的模型: 与依赖相匹配的模型

[TAB]命令

来看一个例子,

目标列表中有foo.o、bar.o和test.s三个值,首先将匹配%.o的模型找出来,test.s不匹配就被遗弃了,将匹配的foo.o和bar.o替换为foo.c和bar.c,最终这一条规则等于执行了下列这两条规则,为什么要这样做呢?你可以试想以下,假设目标列表中有几千个文件,这样做的话是不是就可以少写很多规则:

回到LiteOS_Lab的Makefile上来,156行将C_OBJ变量中的符合build/xxx.o格式的文件作为xxx.c格式的依赖,C_OBJ变量的赋值如下图所示:

$(patsubst PATTERN, REPLACEMENT, TEXT)函数的作用是模式替换,将TEXT中以空格隔开的每个单词(文件名),符合PATTERN格式的替换为REPLACEMENT格式,例如第124行,将所有的C_SOURCE变量中的文件名,凡是只要在SDK/ iot_link目录下的都替换为.o后缀,SDK/ iotlink目录中有一个符合该模型的文件,link_main.c,在执行该规则对应的命令时,目标文件为link_main.o,第125和126行同上。

这里以link_main.c为例向大家讲解指令,经过模式替换后规则如下:

link_main.o: link_main.c

$(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(@:%.o=%.lst) $< -o $@

这里的CC是指arm-none-eabi-gcc,CFLAGS是指各类编译参数,例如-MMD -MP -Wno-missing-braces,$(@:%.o=%.lst)函数的作用是将$@目标符合%.o模型的值替换为%. lst,这里就将link_main.o替换link_main. lst,$<是指第一个依赖,$@是指目标,组合的命令后如下:

arm-none-eabi-gcc -c -MMD -MP -Wno-missing-braces -Wa,-a,-ad,-alms=link_main. lst link_main.c -o link_main.o。一句话来说就是将所有的.c源文件编译不链接生成.o文件和.lst文件,等待后续进一步操作。

第160和161行的操作类似于上面的操作,将所有的汇编文件都编译不链接生成.o文件等待后续进一步操作。

第147到149行规则所需的依赖全部都生成好了,可以开始执行该规则的命令,将所有依赖通过LDFLAGS变量中的值链接生成Huawei_LiteOS.elf文件并列出程序文件中各段的大小。

LDFLAGS变量中通过MCU变量定义了内核相关参数,例如ARM架构的版本以及是否支持硬件浮点数运算等参数,如下图所示,如果你需要将工程移植到不是STM32L431系类的MCU上,就需要修改MCU变量的值。

LDFLAGS变量中通过LDSCRIPT变量读取os.ld链接脚本来控制程序该如何链接,每个段应该存放在程序中的何处,在os.ld链接脚本中还指明了MCU的RAM和FLASH大小及起始位置,我们在进行移植时也需要修改。

Huawei_LiteOS.elf文件是第143至145行规则的依赖,将该elf文件转换为Huawei_LiteOS.hex和Huawei_LiteOS.bin文件,即可烧录。

现在大家应该明白make控制下的整个程序编译过程了吧,以及Makefile文件起到的作用,我们再来看看前面的include导入的文件,如下图所示:

首先导入了.config文件,这由Kconfig软件读取用户通过图形化配置的各项参数信息生成的,其中包含了对SDK中各组件参数的配置信息,如下图所示:

以AT组件为例,CONFIG_AT_ENABLE=y代表使能AT组件;CONFIG_AT_DEVNAME="atdev"将AT组件用到的串口以"atdev"注册到driver层中;CONFIG_AT_OOBTABLEN=6 OOB表的长度配置为6个,这时用于接收异步数据的结构体,意味着我们最多能配置6个特定字符串,当这时字符串出现时调用相应处理函数进行处理;CONFIG_AT_RECVMAXLEN=1024将AT框架中的接收缓存区大小配置为1024字节,如果你的MCU资源受限可以减少这里的大小;CONFIG_AT_TASKPRIOR=10将AT任务的优先级配置为10,注意:这里只有第35行这条语句会影响Make的编译,其余语句是为了记录用户做了哪些配置和生成iot_config.h所用。

.config文件中所有的组件配置都和上面分析的一致,如果组件没有被使能如下图所示:

相信大家看到这里又有新的疑问了,这些配置是如何影响到程序的编译呢?回到前面的第70行include $(SDK_DIR)/iot_link/iot.mk,来看看这个SDK/iot_link目录下的iot.mk文件中有什么你就有答案了,如下图所示:



该Makefile将每个组件所属文件夹下的Makefile也导入进来了,我们还是以AT框架为例,第31行,导入at目录下的at.mk文件,该Makefile内容如下图所示:

看到了吧,第7行与前面的CONFIG_AT_ENABLE=y变量相对应,ifeq ($(CONFIG_AT_ENABLE),y)语句的意思是如果CONFIG_AT_ENABLE变量的值为y,则将ifeq到endif之间的语句全部执行。

第8至9行将at目录下所有.c文件添加到C_SOURCES变量中,注意这里用的是+=是追加上去。

第11至12行将at目录下所有.h文件所在路径(注意是路径,通过-I参数指定头文件所在的路径,这样编译器才能找到头文件,否则会因为找不到头文件导致编译失败)添加到C_INCLUDES变量中,注意这里用的是+=是追加上去。

第14至14行将-D CONFIG_AT_ENABLE=1文本追加到C_DEFS变量中。

这三个变量大家都很眼熟吧,这就是工程目录/GCC目录中Makefile中的那三个变量,如下图所示:

这样AT组件中的所有源文件和头文件就参与了编译。

回到第三个include,include $(MAKEFILE_DIR)/project.mk,这是用于包含(引入)工程目录/GCC目录下的project.mk,该Makefile部分内容如下图所示:

主要用于包含Hal库中的文件以及用户自己添加进去的文件,这也是移植时需要进行修改的文件之一,大家可以仿照我前面分析的方法自己分析一下。最终所有被添加进入的.c源文件会被追加到C_SOURCES变量中,所有.h头文件所在的路径会被追加到C_INCLUDES变量中。

SDK中所有的Makefile文件都不需要也不能进行修改,只需要修改工程中的三个Makefile,.config(这个不用手动修改,可以通过图形化配置进行修改),Makefile(根据目标MCU修改MCU相关的参数即可,也就是MCU这个变量的值),project.mk(根据目标MCU修改、添加或删除库文件以及用户文件以及最后的C_DEFS变量即可)。

看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注行业资讯频道,感谢您对的支持。

文件 变量 目录 规则 目标 生成 编译 命令 配置 程序 分析 组件 三个 参数 语句 链接 工程 模型 函数 格式 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 百单网互联网科技有限公司 智能科技公司是互联网公司吗 关于新基建和互联网科技 腾讯科技 互联网女皇 苏州大垚互联网科技 广州紫鲸互联网科技 互联网高科技股票 互联网科技类展会 深圳市运趣互联网科技有限公司 互联网科技公司需要的职位 玖二柒互联网科技公司待遇 米聚互联网科技南京有限公司排面 伊宁互联网科技做什么的 信承诺互联网科技有限公司 抖集互联网科技技术咨询 北京军民互联网科技公司 科技互联网专业工作会议发言稿 亚光科技低轨卫星互联网 数字科技和互联网金融哪个好 银川新华互联网科技学校招聘 广州百单互联网科技有限公司 科技和互联网公司 互联网科技保险 互联网科技公司电话 云创客互联网科技公司 广州慧亚互联网科技怎么样 晋城互联网科技 华中科技大学互联网的牛人 普陀区互联网教育科技管理办法 广州三三互联网科技有限公司
0