makefile基本语法(已完成)
makefile基本语法
一.makefile规则
一个简单的 Makefile 文件包含一系列的“规则”,其样式如下:
目标(target)…: 依赖(prerequiries)…
<tab>命令(command)
目标(target)通常是要生成的文件的名称,可以是可执行文件或OBJ文件, 也可以是一个执行的动作名称,诸如`clean’。 依赖是用来产生目标的材料(比如源文件),一个目标经常有几个依赖。
命令是生成目标时执行的动作,一个规则可以含有几个命令,每个命令占一 行。 注意:每个命令行前面必须是一个 Tab 字符,即命令行第一个字符是 Tab(有的时候执行makefile在命令出可能会出现空行以及一些莫名其妙的错误,要注意是不是makefile中是不是存在空行且该空行首个为Tab,makefile会把这样的空行当作命令执行)。
通常,如果一个依赖发生了变化,就需要规则调用命令以更新或创建目标。 但是并非所有的目标都有依赖,例如,目标“clean”的作用是清除文件,它没有依赖。 规则一般是用于解释怎样和何时重建目标。
make 首先调用命令处理依赖, 进而才能创建或更新目标。当然,一个规则也可以是用于解释怎样和何时执行一 个动作,即打印提示信息。 一个 Makefile 文件可以包含规则以外的其他文本,但一个简单的 Makefile 文件仅仅需要包含规则。虽然真正的规则比这里展示的例子复杂,但格式是完全 一样的。
对于上面的 Makefile,执行“make”命令时,仅当 hello.c 文件比 hello 文件新,才会执行命令“arm-linux-gcc –o hello hello.c”生成可执行文件 hello; 160 / 566 如果还没有 hello 文件,这个命令也会执行。 运行“make clean”时,由于目标 clean 没有依赖,它的命令“rm -f hello” 将被强制执行。
二.makefile常见符号
- "@" 隐藏命令
这个符串通常用在“规则”行中,表示不显示命令本身,而只显示它的结果,例如以下例子:
a = 5
all:
@echo a = $(a)
a = 5
all:
echo a = $(a)
可以看到在第三行添加了"@"后,make执行的结果中本条命令就不可见了,去掉"@"后就会显示本条命令。
- "#"注释
在makefile中,“#”表示注释,和我们平时写代码不一样,请注意,例子如上方代码所示。
- "$"
美元符号$,主要扩展打开makefile中定义的变量,即对指定的变量会按照要求从中取出值,例子如下:
1)$@ --代表目标文件(target)
2)$^ --代表所有的依赖文件(components)
3)$< --代表第一个依赖文件(components中最左边的那个)。
4)$? --代表示比目标还要新的依赖文件列表。以空格分隔。
5)$(%) --表示从括号中的变量取值("%"表示为通配符)
- "%"通配符
在makefile中,"%"表示通配符,即所有符合条件的符号,例如"%.c"就表示为所有文件中包含".c"的文件
三.变量的定义
在makefile中,定义变量大致可以分为4种,如下所示:
a := $(c) #即使变量,也叫简单变量,立马赋值
b = $(c) #延时变量,用到再赋值
c = abc
d = hello
d ?= No #延时变量,如果是第一次定义才起效,如果已经定义过了就忽略这个指令
#"+=" 附加,它是延时变量还是即时变量取决于前面的值,不太好演示就不举例了
all:
@echo a = $(a)
@echo b = $(b)
@echo d = $(d)
四.假想目标
在编写makefile时,很可能遇到这种情况:想要执行make clean,但是目录中已经有clean这个文件存在,此时怎么办?makefile提供了一个办法--假想目标".PHONY",可以理解成总是会执行。它的用法和平时我们编译我们类似,如以下所示:
test : a.c
gcc -o test a.c
clean:
rm -f test
可以看到使用make clean时,如果有同名的文件,就会提示已存在文件,无法执行make clean命令,这是就需要用到们的".PHONY"了
此时就可以正确删除了。当然,".PHONY"不仅仅可以用于多次执行make clean命令,也可以帮助我们重复编译文件,我们知道makefile编译形成可执行文件,一般是比较修改信息的,如果你的目标文件比原来的文件新,他就不会再编译,加上".PHONY"就可以重复编译文件,如下所示:
.PHONY:test
test : a.c
gcc -o test a.c
.PHONY:clean
clean:
rm -f test
五.常见函数
在makefile中,有很多函数可以帮助我们实现功能,接下来我们介绍几个常见的函数(以下介绍的都是简单常用的函数,其余的函数感兴趣的可以看看官方文档)。
1.makefile函数调用的基本格式:
$(function arguments)
这里"function"是函数名,"arguments"是该函数的参数。参数和函数名之 间是用空格或 Tab 隔开,如果有多个参数,它们之间用逗号隔开。这些空格和逗号不是参数值的一部分。内核的 Makefile 中用到大量的函数,现在介绍一些常 用的。
2.$(patsubst pattern,replacement,text)
用"replacement"替换"text"变量中符合格式"pattern’的字符。 "pattern"和"replacement"中可以使用通配符。例子如下:
a = x.o obj.o
b = $(patsubst %.o,%.c, $(a))
c = $(patsubst %.c,%.o,x.c.c bar.c)
all:
@echo a = $(a)
@echo b = $(b)
@echo c = $(c)
3.$(findstring find,in)
在字符串"in"中寻找"find",如果找到,则返回值是"find",否则返回值 为空,例子如下:
makefilea = hello vscode
b = $(findstring hello, $(a))
c = $(findstring enen, $(a))
all:
@echo a = $(a)
@echo b = $(b)
@echo c = $(c)
4.$(filter pattern...,text)
返回在"text"中由空格隔开且符合参数"pattern"的字符串,去除不符合的字符串,例子如下:
a = hello.c vscode.o a.c b.s
b = $(filter %.c, $(a))
all:
@echo a = $(b)
5.$(filter-out pattern...,text)
返回在"text"中由空格隔开且不符合参数"pattern"的字符串,去除符合的字符串,例子如下:
a = hello.c vscode.o a.c b.s
b = $(filter %.c, $(a))
c = $(filter-out %.c, $(a))
all:
@echo a = $(b)
@echo c = $(c)
6.$(wildcard text)
从变量test中找到真实存在的文件,如下:
a = hello.c vscode.o a.c b.s
b = $(wildcard $(a))
all:
@echo b = $(b)
7.$(sort list)
将‘list’中的字按字母顺序排序,并去掉重复的字。输出由单个空格隔开 的字的列表,如下:
a = hello.c vscode.o a.c b.s
b = $(sort $(a))
all:
@echo b = $(b)
六.编写makefile
前文我们已经介绍了makefile常见的语法了,接下来让我们自己编写几个makefile看看把。
1.单文件编译形成单个可执行程序
#include<stdio.h>
int main()
{
printf("hello, can you see me?\n");
return 0;
}
test : test.c #想要生成test,test依赖于test.c
gcc -o test test.c #指令
.PHONY:clean
clean:
rm -f test
#以上就是我们编写makefile的基本格式
目标:源文件 #注意下方首个是tab键,不然不能执行指令
指令
知道以上基本格式以后,我们再来编写几个复杂点的makefile
2.多文件编译形成多个可执行程序
编写一个文件的时候我们可以不用告诉makefile,它会默认执行,但是要一次性形成多个可执行程序时,就要说明。
all : test test2 //告诉makefile要生成哪几个程序
test : test.c
gcc -o test test.c
test2 : test2.c
gcc -o test2 test2.c
.PHONY:clean
clean:
rm -f test
rm -f test2
3.通用makefile模板
makefile对于我们而言,只是一个工具,针对大型项目的时候,没必要每次都自己造轮子,只要知道怎么用就行了,接下来介绍一个通用的makefile模板。
target=main //想要生成的可执行文件名称可自定义,此处为main
src=$(wildcard *.c)
deps=$(wildcard *.h)
obj=$(patsubst %.c,%.o,$(src))
$(target):$(obj)
gcc $^ -o $@ -Wall
%.o:%.c $(deps)
gcc -c $< -o $@ -Wall
.PHONY:clean
clean:
-rm -rf $(target) $(obj)
对于生成多个目标文件的,只需要在上面修改一下即可
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库