个人根据正点原子文档原创学习笔记,如有侵权,联系删除,转载请标明出处;
本文包括但不限于:易读性引入、编写与使用、语法、变量、模式、伪目标、条件判断、函数;
何为Makefile
Makefile是一种用于构建和管理项目的自动化构建工具的配置文件;
它使用一套特定的语法来定义目标、依赖关系和构建规则。
多终端输入 GCC 命令不现实,可编写一个描述“编译哪些源码文件、如何编译”的文件;
make: 工程编译的工具
Makefile: 描述哪些文件需要编译、哪些需要重新编译的文件
事实上 IDE 都有Makefile,只不过这些 IDE对其进行了封装,提供的是已封装后的图形界面。
Makefile 的引入☆☆☆
典例
C 文件:main.c、input.c 、calcu.c
头文件: input.h、calcu.h
gcc main.c calcu.c input.c -o main
-
工程仅三个文件!若文件很多或有文件被修改,使用上面的命令编译的时候所有的文件都会重新编译;
-
改进编译方法:第一次编译工程,先将工程中的文件都编译一遍,后面修改了哪个文件就编译哪个文件。
- 分别是将 main.c、input.c 和 calcu.c 编译成对应的.o 文件
- 将所有的.o 文件链接成可执行文件
gcc -c main.c gcc -c input.c gcc -c calcu.c gcc main.o input.o calcu.o -o main
Makefile编写与使用
如果修改的文件一多,可能都不记得哪个文件修改过了,然后忘记编译,为此我们需要这样一个工具:
-
如果工程没有编译过,那么工程中的所有.c 文件都要被编译并且链接成可执行程序;
-
如果工程中只有个别 C 文件被修改了,那么只编译这些被修改的 C 文件即可;
-
如果工程的头文件被修改了,那么我们需要编译所有引用这个头文件的 C 文件,并且链接成可执行文件;
能够完成这个功能的就是 Makefile!
vim编写makefile
- 行首需要空出来的地方一定要使用“TAB”键!
make编译工程
-
直接在命令行中输入 make 命令来编译工程;
-
make 命令会在当前目录下查找是否存在“Makefile”这个文件;
-
存在则按照Makefile 中定义的编译方式进行编译
-
文件改动后make,会对改动的自动编译
Makefile 语法
个人理解:指定目标及其所需资源,执行(创建一个 Shell 进程)完成目标的命令即为makefile
makefile(规则) = Linux基本命令+shell进程+gcc编译器
Makefile 规则格式
Makefile 里面是由一系列的规则组成
#/* 目标…... : 依赖文件集合……
# 命令 1
# 命令 2
# ……
#例: */
main : main.o input.o calcu.o
gcc -o main main.o input.o calcu.o
-
上述规则的目标是 main,main.o、input.o 和 calcu.o 是生成 main 的依赖文件,
如果要更新目标 main,就必须先更新它的所有依赖文件(刚刚更改input.c时已体现);
-
命令列表中的每条命令必须以 TAB 键开始,不能使用空格!
make 命令会为 Makefile 中的每个以 TAB 开始的命令创建一个 Shell 进程去执行。
clean
-
功能:完成工程的清理
-
执行以后就会删除当前目录下所有的.o 文件以及 main
-
无依赖文件,默认为依赖文件都是最新,命令行下其对应的命令不会执行,命令行可用make clean
make clean
make print
功能:类似clean,不过功能是打印;
@echo
原样输出,类似c语言print;
”$(变量)“
引用变量,变量需提前赋值;
Make 的执行过程
make
顺序问题
-
Makefile 的“终极目标”所在的规则以外,其它规则的顺序在 Makefile 中是没有意义的;
-
“终极目标”就是指在使用 make 命令的时候没有指定具体的目标时,make 默认的那个目标,它是 Makefile 文件中第一个规则的目标;
-
如果 Makefile 中的第一个规则有多个目标,那么这些目标中的第一个目标就是 make 的“终极目标”。
Makefile 变量
典例
-
跟 C 语言一样 Makefile 也支持变量
-
Makefile 中的变量都是字符串!类似 C 语言中的宏
1 #Makefile 变量的使用
2 objects = main.o input.o calcu.o
3 main: $(objects)
4 gcc -o main $(objects)
-
注释开头要用符号“#”
-
定义了一个变量 objects,并且进行赋值,其值为字符串“main.o input.o calcu.o”,引用方法是“$(变量名)”;
#示例代码 3.4.2.1 赋值符"="":=""?=""+="使用
name = zzk
curname = $(name)
name = zuozhongkai
name1 = zzk
curname1 := $(name1)
name1 = zuozhongkai
name2 = zzk
curname2 ?= $(name2)
name2 = zuozhongkai
name3 = zzk
curname3 ?= $(name3)
name3 = zuozhongkai
print:
@echo curname: $(curname)
@echo curname1: $(curname1)
@echo curname2: $(curname2)
@echo curname3: $(curname3)
-
要输出一串字符的话使用“echo”,就和 C 语言中的“printf”一样;
-
“echo”前加“@”符号,因Make执行中会自动输出命令执行过程,在命令前加上“@”则不输出命令执行过程
赋值符“=”
- 变量的真实值取决于它所引用的变量的最后一次有效值;
赋值符”:=“
- 不会使用后面定义的变量,只能使用前面已经定义好的;
赋值符“?=”
-
如果变量 curname 前面没有被赋值,那么此变量就是“zuozhongkai”,
-
如果前面已经赋过值了,那么就使用前面赋的值。
变量追加“+=“
objects = main.o inpiut.o
objects += calcu.o
-
一开始变量 objects 的值为“main.o input.o”,后面我们给他追加了一个“calcu.o”;
-
因此变量 objects 变成了“main.o input.o calcu.o”,这个就是变量的追加;
Makefile 模式规则
%.o : %.c
#命令
-
以前将对应.c 源文件编译为.o 文件,每个 C 文件都写一对应规则,若工程中 C 文件很多的话则很麻烦;
-
可使用 Makefile 中的模式规则,通过模式规则可使用一条规则将所有的.c 文件编译为对应的.o 文件
模式规则中,至少在规则的目标定定义中要包涵“%”,否则就是一般规则;
目标中的“%”表示对文件名的匹配,“%”表示长度任意的非空字符串;
比如“%.c”就是所有的以.c 结尾的文件,类似与通配符,a.%.c 就表示以 a.开头,以.c 结束的所有文件;
- (通配符)“%”表示对文件名的匹配,“%”表示长度任意的非空字符串
第 5、6 这两行代码替代了“示例代码 3.4.3.1”中的 3~8 行代码
借助另外一种强大的变量—自动化变量,保障 .o .c 文件编译链接;
Makefile 自动化变量
-
自动化变量:变量会把模式中所定义的一系列的文件自动的挨个取出,直至所有的符合模式的文件都取完;
-
自动化变量只应出现在规则的命令中;
常用的三种: @ 、 @、 @、<和$^
Makefile 伪目标
作用
-
执行 make 命令的时候通过指定这个伪目标来执行其所在规则的定义的命令;
-
伪目标是为避免 Makefile 中定义的执行命令的目标和工作目录下的实际文件出现名字冲突;
#例
clean:
rm *.o
rm main
#规则中并没有创建文件 clean 的命令,因此工作目录下永远都不会存在文件 clean;
#输入“make clean”以后,后面的“rm *.o”和“rm main”总是会执行;
在工作目录下创建一个名为“clean”的文件,那就不一样;
执行“make clean”的时候,规则因为没有依赖文件,所以目标被认为是最新的;
后面的 rm 命令也就不会执行,预先设想的清理工程的功能也就无法完成;
我们可以将 clean 声明为伪目标,声明方式:
.PHONY : clean
#示例代码 3.4.5.1 伪目标
#工作目录下有一个名为“clean”的文件!
objects = main.o input.o calcu.o
main: $(objects)
gcc -o main $(objects)
.PHONY : clean
%.o : %.c
gcc -c $<
clean:
rm *.o
rm main
- 声明 clean 为伪目标以后不管当前目录下是否存在名为“clean”的文件,输入“make clean”的话规则后面的 rm 命令都会执行
Makefile 条件判断
通过条件判断语句来根据不同的情况来执行不同的分支;
两种条件判断方法
四个调关键字
ifeq、ifneq、ifdef 、 ifndef
ifeq 与ifneq
- 用法
- ifeq 用来判断是否相等,ifneq 就是判断是否不相等
用来比较“参数 1”和“参数 2”是否相同,如果相同则为真,“参数 1”和“参数 2”可以为函数返回值;
ifneq 的用法类似,ifneq 是用来比较“参数 1”和“参数 2”是否不相等,如果不相等的话就为真;
ifdef 与 ifndef
- 用法
- 功能
如果“变量名”的值非空,那么表示表达式为真,否则表达式为假,“变量名”同样可以是一个函数的返回值;
ifndef 用法类似,但是含义用户 ifdef 相反;
Makefile 函数使用
-
不支持自定义函数
-
Makefile 中的函数已定义好
用法
函数的调用以“$”开头,调用函数和调用普通变量一样;
参数集合是函数的多个参数,参数之间以逗号“,”隔开,函数名和参数之间以“空格”分隔开;