Makefile教程(附通用模板)

工程目录

工程目录如图,build文件夹是编译出来的

.
├── app
│   ├── imx6ul.lds
│   ├── main.c
│   ├── makefile
│   └── start.S
├── bsp
│   ├── clk
│   │   ├── bsp_clk.c
│   │   └── bsp_clk.h
│   ├── delay
│   │   ├── bsp_delay.c
│   │   └── bsp_delay.h
│   └── led
│       ├── bsp_led.c
│       └── bsp_led.h
├── build
│   ├── bsp_clk.o
│   ├── bsp_delay.o
│   ├── bsp_led.o
│   ├── led_bsp.bin
│   ├── led_bsp.elf
│   ├── led_bsp.lst
│   ├── main.o
│   └── start.o
└── imx6ul├── cc.h├── fsl_common.h├── fsl_iomuxc.h├── imx6ul.h└── MCIMX6Y2.h



Makefile源码

#   $@  表示目标文件;
#   $^  表示所有的依赖文件;
#   $<  表示第一个依赖文件;#   =   延时赋值,该变量只有在调用的时候,才会被赋值;
#   :=   直接赋值,与延时赋值相反,使用直接赋值的话,变量的值定义时就已经确定了;
#   ?=  若变量的值为空,则进行赋值,通常用于设置默认值;
#   +=  追加赋值,可以往变量后面增加新的内容。# 定义交叉编译器变量
CROSS_COMPILER ?= arm-linux-gnueabihf-# 定义编译选项
CFLAGS = -Wall -Wextra -std=c11 -O2# 定义目标文件
TARGET = led_bsp# 定义连接脚本文件路径
LD_SCRIPT = -T./imx6ul.lds# 定义目标文件夹
BUILD_DIR := ../buildSRC_DIRS := ./
INC_DIRS := ../imx6ul
LIB_DIRS := ../lib# 扩展源文件夹列表
SUBDIRS := clk led delay
SRC_DIRS += $(addprefix ../bsp/, $(SUBDIRS))
VPATH := $(SRC_DIRS)# 扩展头文件夹列表
INC_DIRS := $(addprefix -I, $(INC_DIRS))
INC_DIRS += $(addprefix -I, $(SRC_DIRS))# 扩展库文件夹列表
LIB_DIRS := $(addprefix -L, $(LIB_DIRS))# 定义需要链接的库
#LIBS = -lm -lpthread# 查找所有的源文件
SRCS_S := $(shell find $(SRC_DIRS) -name '*.S')
SRCS_C := $(shell find $(SRC_DIRS) -name '*.c')
# 去掉路径 只保存文件名
NOT_DIR_SRCS_S := $(notdir  $(SRCS_S))
NOT_DIR_SRCS_C := $(notdir  $(SRCS_C))
# 将.c .S替换成.o
OBJS_S := $(patsubst %.S, $(BUILD_DIR)/%.o, $(NOT_DIR_SRCS_S))
OBJS_C := $(patsubst %.c, $(BUILD_DIR)/%.o, $(NOT_DIR_SRCS_C))
OBJS := $(OBJS_S) $(OBJS_C)# 默认目标 链接所有.o
$(BUILD_DIR)/$(TARGET): $(OBJS)$(CROSS_COMPILER)ld $(LD_SCRIPT) $(LIB_DIRS) $(LIBS)  -o $@.elf $^ # 编译成.o
$(OBJS_C) : $(BUILD_DIR)/%.o : %.c$(CROSS_COMPILER)gcc $(CFLAGS) $(INC_DIRS) -c -o $@ $<$(OBJS_S) : $(BUILD_DIR)/%.o: %.S$(CROSS_COMPILER)gcc $(CFLAGS) $(INC_DIRS) -c -o $@ $<# 生成bin文件
bin: $(BUILD_DIR)/$(TARGET)$(CROSS_COMPILER)objcopy -O binary $<.elf $<.bin# 生成反汇编文件
disassemble: $(BUILD_DIR)/$(TARGET)$(CROSS_COMPILER)objdump --source --all-headers --demangle --line-numbers --wide $<.elf > $<.lst# 生成空间信息
size: $(BUILD_DIR)/$(TARGET)$(CROSS_COMPILER)size --format=berkeley $<.elf # all目标生成目标文件、bin文件和反汇编文件
all: $(BUILD_DIR)/$(TARGET) bin disassemble size# 清理规则,用于清除生成的目标文件、可执行文件、二进制文件和反汇编文件
clean:rm -rf $(BUILD_DIR)# 确保编译目标文件夹存在
$(BUILD_DIR):mkdir -p $(BUILD_DIR)# 编译之前先创建目标文件夹
$(OBJS): | $(BUILD_DIR).PHONY: bin disassemble size all clean



基本编译规则

编译过程

在GCC中,每个编译阶段都有对应的指令来执行。以下是每个阶段对应的GCC指令:

  1. 预处理(Preprocessing)gcc -E 这个指令告诉GCC只进行预处理,生成预处理后的代码,而不执行后续的编译、汇编和链接步骤。生成的预处理文件通常以.i为扩展名

  2. 编译(Compiling)gcc -S 这个指令告诉GCC只进行编译,将源代码转换为汇编代码,而不执行汇编和链接步骤。生成的汇编语言文件通常以.s为扩展名

  3. 汇编(Assembling)gcc -c 这个指令告诉GCC只进行汇编,将汇编语言代码转换为目标文件,而不执行链接步骤。生成的目标文件通常以.o为扩展名

  4. 链接(Linking)ld 这个指令执行完整的编译链接过程,将多个目标文件以及可能的库文件链接在一起,生成最终的可执行文件。可通过指定输入的目标文件和库文件来完成链接过程,并使用 -o 选项来指定输出文件名



Makefile基本规则

规则定义了如何根据源文件生成目标文件,规则通常由三个部分组成:目标(target)、依赖关系(dependencies)和命令(commands)

以下是规则的一般格式:

codetarget: dependenciescommand
  • 依赖全部存在时,才会执行command
  • 程序会从默认规则开始执行,也是为了生成第一个目标(一般都是可执行文件)
  • 当依赖不存在时,就会自动去别的规则中的目标中去寻找,以此类推
  • .PHONY声明了伪目标,例如make all,这样做的好处是,可以避免与同名的文件或目录发生冲突,同时确保这些目标能够被正确地执行


常用函数和语句

sheel

result := $(shell command)

会创建一个shell进程执行command,并将结果返回到result

需要注意执行效率,此函数可能会被多次调用到



wildcard(匹配文件名并返回列表)

$(wildcard pattern)

其中 pattern 是一个文件名模式,可以包含通配符(例如 *?

wildcard 函数会返回匹配 pattern 的文件列表,如果没有匹配的文件,则返回空字符串。

以下是一个示例:

SRCS := $(wildcard src/*.c)

在这个示例中,$(wildcard src/*.c) 将匹配 src 目录下所有以 .c 结尾的文件,并返回这些文件的列表给 SRCS 变量



foreach (遍历执行)

用于在每个元素上执行操作,它的语法如下:

$(foreach var, list, text)
  • var 是一个变量名,用于保存列表中的每个元素
  • list 是一个空格分隔的元素列表
  • text 是要执行的文本

foreach 函数会遍历列表中的每个元素,并将当前元素依次赋值给 var,然后执行 text 中的命令。在每次迭代中,text 中可以使用 var 来引用当前元素

在这个示例中, 会遍历 FILES 列表中的每个文件名,并将其打印出来

FILES := file1.txt file2.txt file3.txt
$(foreach file, $(FILES), $(info File: $(file)))



addprefix(给列表加前缀)

用于在每个元素前添加一个前缀,它的语法如下:

makefileCopy code
$(addprefix prefix,names...)
  • prefix 是要添加的前缀
  • names 是一个空格分隔的元素列表

addprefix 函数会将 prefix 添加到 names 列表中的每个元素前面,并返回修改后的列表以下是一个示例:

makefileCopy codeFILES := file1.txt file2.txt file3.txt
$(addprefix prefix_, $(FILES))

在这个示例中,$(addprefix prefix_, $(FILES)) 会将 FILES 列表中的每个文件名前面都添加 prefix_ 前缀,得到一个新的列表。结果将是 prefix_file1.txt prefix_file2.txt prefix_file3.txt



查找所有源文件

第一步先是通过addprefix生成所有包含源文件的目录,将其存在SRC_DIRS 中,并借助info 将其打印出来

SUBDIRS := clk led delay
SRC_DIRS += $(addprefix ../bsp/, $(SUBDIRS))$(info SRC_DIRS : $(SRC_DIRS))#结果如下
SRC_DIRS : ./ ../bsp/clk ../bsp/led ../bsp/delay



使用 find

​ 通过如下命令即可找出SRC_DIRS 中的所有.c文件

SRCS_C := $(shell find $(SRC_DIRS) -name '*.c')$(info SRCS_C : $(SRCS_C))#结果如下
SRCS_C : ./main.c ../bsp/clk/bsp_clk.c ../bsp/led/bsp_led.c ../bsp/delay/bsp_delay.c

附上find的常见用法:

  1. 在当前目录及其子目录中搜索所有文件:

    find
    
  2. 在指定目录中搜索所有文件:

    find /path/to/directory
    
  3. 在当前目录及其子目录中搜索所有 .txt 文件:

    find -name "*.txt"
    
  4. 在当前目录及其子目录中搜索所有大于 1MB 的文件:

    find -size +1M
    
  5. 在当前目录及其子目录中搜索所有修改时间在一天之内的文件:

    find -mtime -1
    
  6. 在当前目录及其子目录中搜索所有空文件:

    find -type f -empty
    

find 命令非常强大,它支持多种匹配条件和动作,可以根据实际需求来进行灵活的文件搜索和操作



使用wildcard和foreach

通过如下命令即可找出SRC_DIRS 中的所有.c文件

SRCS_C := $(foreach dir, $(SRC_DIRS), $(wildcard $(dir)/*.c))$(info SRCS_C : $(SRCS_C))#结果如下
SRCS_C : ./main.c ../bsp/clk/bsp_clk.c ../bsp/led/bsp_led.c ../bsp/delay/bsp_delay.c



notdir

用于从文件路径中提取文件名部分,去除路径。它的语法如下:

$(notdir names...)

其中 names 是一个空格分隔的文件路径列表

notdir 函数会返回 names 中每个文件路径的文件名部分,去除路径信息

以下是一个示例:

SRCS := src/main.c src/foo.c src/bar.c
FILE_NAMES := $(notdir $(SRCS))

在这个示例中,$(notdir $(SRCS)) 将提取 SRCS 中每个文件路径的文件名部分,结果将是 main.c foo.c bar.c



patsubst

用于在字符串中执行模式替换操作。它的语法如下:

$(patsubst pattern, replacement, text)

其中:

  • pattern 是要匹配的模式
  • replacement 是用于替换匹配模式的文本
  • text 是要进行模式替换的原始文本

patsubst 函数会查找 text 中与 pattern 匹配的部分,并将它们替换为 replacement

以下是一个示例:

SRCS := file1.c file2.c file3.c
OBJS := $(patsubst %.c, %.o, $(SRCS))

在这个示例中,$(patsubst %.c,%.o,$(SRCS)) 将把 SRCS 中的 .c 文件名替换为 .o 文件名,生成的 OBJS 变量会包含 file1.o file2.o file3.o


调用其他 Makefile

在 Makefile 中,可以通过 include 指令来引入其他的 Makefile。这样做的主要目的是为了将大型项目拆分成更小的模块,每个模块对应一个独立的 Makefile,方便管理和维护。同时,通过模块化的方式,可以提高代码的重用性和可维护性。

在 Makefile 中使用 include 指令的语法如下:

include other_makefile.mk

其中 other_makefile.mk 是要包含的其他 Makefile 的文件名。

通过引入其他的 Makefile,可以将项目拆分成多个模块,每个模块负责特定的功能或任务。这样做有以下几个优点:

  1. 模块化管理:将项目拆分成多个模块后,每个模块可以独立管理,减少了代码的耦合度,方便团队协作和代码维护
  2. 代码重用:通过将通用的功能和规则封装在单独的模块中,可以提高代码的重用性,避免重复编写相同的代码
  3. 可维护性:将项目拆分成多个模块后,每个模块的功能更加清晰明确,易于理解和维护。同时,可以针对每个模块进行单独的测试和调试

总之,通过引入其他的 Makefile,可以将大型项目拆分成更小的模块,提高了代码的组织性、可维护性和重用性,是一种良好的编程实践。

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

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

相关文章

软考 系统架构设计师系列知识点之SOME/IP与DDS(1)

本文内容参考&#xff1a; 车载以太网 - SOME/IP简介_someip-CSDN博客 https://zhuanlan.zhihu.com/p/369422441 什么是SOME/IP?_someip-CSDN博客 SOME/IP 详解系列&#xff08;1&#xff09;—— 概述_some ip-CSDN博客 深入浅出SOME/IP协议&#xff1a;基本概念和原理-…

天童教育:停止内耗放松身心

如果一个人经常从自己身上找原因&#xff0c;经常揽下他人的过错的责任&#xff0c;总是自我怀疑自我否定&#xff0c;认为自己不值得被爱。当被人误解时会在心里悄悄附和&#xff0c;责怪自己。缺乏自信&#xff0c;没办法和他人有正常的交往&#xff0c;长期处于身心疲惫的状…

Python与Python3的区别:深度剖析与全面解读

Python与Python3的区别&#xff1a;深度剖析与全面解读 在编程领域&#xff0c;Python和Python3是两个常被提及的版本&#xff0c;它们之间既存在相似之处&#xff0c;又有着显著的区别。本文将从四个方面、五个方面、六个方面和七个方面&#xff0c;深入剖析Python与Python3之…

OJ3376无尽的石头问题

答案&#xff1a; #include<bits/stdc.h> using namespace std; const int N10e7; int fx(int n) {int sum0;while(n){sum(n%10);n/10;}return sum; } int main() {int t,n,x;cin>>t;while(t--){cin>>n;int count0;for(int i1;i<N;){if(in){cout<<…

在github上创建(上传、关联)自已的项目

目录 创建一个github项目并进行开发。 1.github创建空项目 2. git clone 项目 3. 将项目关联 创建一个github项目并进行开发。 1.github创建空项目 右边的New 然后按步创建就行 2. git clone 项目 复制这个连接 然后在终端&#xff1a;git clone [刚才复制的连接] 3. 将…

解读 Explainable Image Similarity Integrating Siamese Networks and Grad-CAM

给出论文&#xff08;Explainable Image Similarity Integrating Siamese Networks and Grad-CAM&#xff09;的内容解读、代码运行说明 论文链接&#xff1a;J. Imaging | Free Full-Text | Explainable Image Similarity: Integrating Siamese Networks and Grad-CAM (mdpi.c…

纯网络的系统能否定级备案?

很多单位想把网络基础设施进行定级备案和测评&#xff0c;但是不知道这样可否&#xff1f; 目前湖北省是可以的。因为根据《定级指南》的术语解释3.2对等级保护对象的定义是包括通信基础设施的&#xff0c;也就是网络基础设施。其他地区目前有的地方可以有的地方不行&#xff…

2024年武汉东湖高新中级职称报名时间是什么时候?

2024年武汉市东湖高新中级职称上半年批次报名已经截止了&#xff0c;下半年东湖高新至少还有一次报名机会&#xff0c;所以各位东湖高新区评职称的朋友们&#xff0c;不要错过这次了。 2024年武汉东湖高新区中级职称报名条件&#xff1a; 1.东湖高新区社保满足1年&#xff0c;近…

进口不锈钢气动输送泵-美国品牌

进口不锈钢气动输送泵是一种利用压缩空气为动力&#xff0c;通过气阀控制进行往复运动&#xff0c;将能量转换为泵的动能&#xff0c;从而实现对液体或固体物料输送的设备。以下是关于进口不锈钢气动输送泵的详细介绍&#xff1a; 一、产品特点 材质优良&#xff1a;主体部分…

seata源码分析(03)_创建代理的过程

seata提供了ProxyUtil工具类为事务组件创建代理对象&#xff0c;在spring环境中&#xff0c;seata提供了GlobalTransactionScanner类和SeataAutoDataSourceProxyCreator为组件创建AOP代理&#xff0c;本文重点分析这两个类。 ProxyUtil io.seata.integration.tx.api.util.Pro…

【中年危机】程序猿自救指南

中年危机&#xff0c;一个听起来就充满挑战的词汇&#xff0c;它不仅仅是一个年龄的标记&#xff0c;更是一个个人成长和职业发展的转折点。 构架个人品牌&#xff1a; 学会打造IP个人品牌是职业生涯中的重要资产。在中年时期&#xff0c;你已经积累了丰富的经验和知识&#x…

golang的http客户端封装

简介 net/http 是 Go 语言标准库的一部分&#xff0c;它提供了创建 HTTP 客户端和服务器的能力。这个包通过简化与 HTTP 协议的交互&#xff0c;让开发者能够方便地构建 HTTP 请求和响应&#xff0c;以及处理路由等任务。 本文以 net/http 包作为底层&#xff0c;封装一个包含…

HTCC电路板是什么,有哪些主要应用领域

HTCC英文名称是High-Temperature Co-Fired Ceramic&#xff0c;又称高温共烧多层陶瓷基板。因其具有导热系数高、耐热性好、热膨胀系数小、机械强度高、绝缘性好、耐腐蚀等优势&#xff0c;是保持高速增加的PCB线路板之一。 SPEA作为专业电路板测试设备方案服务商&#xff0c;公…

FY-SA-20237·8-WhyWeSpin

Translated from the Scientific American, July/August 2023 issue. Why We Spin (我们为什么旋转) Primates may play with reality by twirling around 翻译&#xff1a;灵长类动物有能力通过旋转或旋转运动来操纵或扭曲他们对现实的感知。 解释&#xff1a; “Primates”…

Java生成指定长度验证码

生成指定长度验证码的简单思路在Java中通常涉及以下几个步骤&#xff1a; 1、定义字符池&#xff1a; 首先&#xff0c;需要定义一个包含所有可能字符的字符串&#xff0c;这个字符池通常包括数字(0-9)、大写字母(A-Z)、小写字母(a-z)。 例如&#xff1a; String chars "…

【开发心得】三步本地化部署llama3大模型

目录 第一步&#xff1a;启动ollama 第二步&#xff1a;启动dify 第三步&#xff1a;配置模型&#xff08;截图&#xff09; 最近llama3很火&#xff0c;本文追击热点&#xff0c;做一个本地化部署的尝试&#xff0c;结果还成功了&#xff01; 当然也是站在别人的肩膀上&…

【运维项目经历|027】PXE自动化部署与管理平台

&#x1f341;博主简介&#xff1a; &#x1f3c5;云计算领域优质创作者 &#x1f3c5;2022年CSDN新星计划python赛道第一名 &#x1f3c5;2022年CSDN原力计划优质作者 &#x1f3c5;阿里云ACE认证高级工程师 &#x1f3c5;阿里云开发者社区专…

Nginx企业级负载均衡:技术详解系列(18)—— 作为上传服务器

你好&#xff0c;我是赵兴晨&#xff0c;97年文科程序员。 在上一期的技术分享中&#xff0c;我们探讨了如何高效搭建Nginx下载服务器&#xff0c;并讨论了长连接优化策略。那么今天&#xff0c;咱们进一步了解Nginx的另一面——作为上传服务器的配置技巧。 作为上传服务器&a…

怎么做好企业短信服务呢?(文字短信XML接口示例)

企业短信服务已经成为各行各业都信赖的行业推广方式之一&#xff0c;并且短信行业也与时俱进的发展着&#xff0c;随之而来的就是市场上短信平台的数量也随之增多。那么怎么在鱼龙混杂的短信行业中选择适合自己的企业短信服务平台呢&#xff1f;企业短信服务平台又适用于哪些应…

Django的PATH路径转换器

本书1-7章样章及配套资源下载链接: https://pan.baidu.com/s/1OGmhHxEMf2ZdozkUnDkAkA?pwdnanc 源码、PPT课件、教学视频等&#xff0c;可以从前言给出的下载信息下载&#xff0c;大家可以评估一下。 在Django框架中&#xff0c;默认内置了一组PATH路径转换器&#xff0c;具…