目录
一、Makefile的定义
Linux 环境下的程序员如果不会使用GNU make来构建和管理自己的工程,应该不能算是一个合格的专业程序员,至少不能称得上是 Unix程序员。在 Linux(unix )环境下使用GNU 的make工具能够比较容易的构建一个属于你自己的工程,整个工程的编译只需要一个命令就可以完成编译、连接以至于最后的执行。不过这需要我们投入一些时间去完成一个或者多个称之为Makefile 文件的编写。
一个工程中的源文件不计其数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 makefile就像一个Shell脚本一样,也可以执行操作系统的命令。有点类似于VScode界面左边的工程管理功能。
操作Makefile文件用到了一个工具叫做make,编译整个工程你所要做的事就是在shell 提示符下输入make命令。整个工程完全自动编译,极大提高了效率。make是一个命令工具,它解释Makefile 中的指令。
二、Makefile的使用
1、Makefile的作用和意义
(1)工程项目中c文件太多管理不方便,因此用Makefile来做项目管理,方便编译链接过程。
(2)uboot和linux kernel本质上都是C语言的项目,都由很多个文件组成,因此都需要通过Makefile来管理。所以要分析uboot、必须对Makefile有所了解。
2、目标、依赖、命令
target: prerequisites
command
示例:
led.bin: led.o
arm-linux-ld -Ttext 0x0 -o led.elf $^
arm-linux-objcopy -O binary led.elf led.bin
arm-linux-objdump -D led.elf > led_elf.dis
gcc mkv210_image.c -o mkx210
./mkx210 led.bin 210.bin
%.o : %.S
arm-linux-gcc -o $@ $< -c
%.o : %.c
arm-linux-gcc -o $@ $< -c
clean:
rm *.o *.elf *.bin *.dis mkx210 -f
(1)目标就是我们要去make xxx的那个xxx,就是我们最终要生成的东西。
特别注意 伪目标(.PHONY):
(1)伪目标意思是这个目标本身不代表一个文件,执行这个目标不是为了得到某个文件或东西,
而是单纯为了执行这个目标下面的命令。其与一般的目标有所不同。
(2)伪目标一般都没有依赖,因为执行伪目标就是为了执行目标下面的命令。既然一定要执行
命令了那就不必加依赖,因为不加依赖意思就是无条件执行。
(3)伪目标可以直接写,不影响使用;但是有时候为了明确声明这个目标是伪目标会在伪目标
的前面用.PHONY来明确声明它是伪目标。
对于伪目标,大家可以额外学习了解一下:
关于 Makefile 伪目标的妙用
Makefile中.PHONY伪目标的作用(完整)
(2)依赖是用来生成目录的原材料
(3)命令就是加工方法,所以make xxx的过程其实就是使用命令将依赖加工成目标的过程。
3、通配符%和Makefile自动推导(规则)
(1)%是Makefile中的通配符,代表一个或几个字母。也就是说**%.o就代表所有以.o为结尾的文件。**
Makefile中使用通配符:
(1)* 若干个任意字符
(2)? 1个任意字符
(3)[] 将[]中的字符依次去和[]的部分结合匹配
%,也是通配符,表示任意多个字符,和*很相似,但是%一般只用于规则描述中,
又叫做规则通配符。
(2)所谓自动推导其实就是Makefile的规则。当Makefile需要某一个目标时,他会把这个目标去套规则说明,一旦套上了某个规则说明,则Makefile会试图寻找这个规则中的依赖,如果能找到则会执行这个规则用依赖生成目标。
4、Makefile中 定义 和 使用 变量 及 文件名
(1)Makefile中定义和使用变量,和shell脚本中非常相似。相似是说:都没有变量类型,直接定义使用,引用变量时用$var
(2)Makefile的文件名合法的一般有2个:Makefile或者makefile
5、Makfile中引用其他Makefile(include指令)
有时候Makefile总体比较复杂,因此分成好几个Makefile来写。然后在主Makefile中引用其他的,用include指令来引用。引用的效果也是原地展开,和C语言中的头文件包含非常相似。
6、Makefile中的一些规范
(1)Makefile中注释使用#,和shell一样。
(2)命令前面的@用来静默执行
(1)在makefile的命令行中前面的@表示静默执行。
(2)Makefile中默认情况下在执行一行命令前会先把这行命令给打印出来,然后
再执行这行命令。
(3)如果你不想看到命令本身,只想看到命令执行就静默执行即可。
7、Makefile中几种变量赋值运算符
(1)= 最简单的赋值
(2):= 一般也是赋值
以上这两个大部分情况下效果是一样的,但是有时候不一样。
用=赋值的变量,在被解析时他的值取决于最后一次赋值时的值,所以你看变量
引用的值时不能只往前面看,还要往后面看。
用:=来赋值的,则是就地直接解析,只用往前看即可,看距离最近的一次赋值是多少
(3)?= 如果变量前面并没有赋值过则执行这条赋值,如果前面已经赋值过了则本行
被忽略。(实际上在这里所谓的没有赋值过其实就是这个变量没有被定义过)
(4)+= 用来给一个已经赋值的变量接续赋值,意思就是把这次的值加到原来的值的
后面,有点类似于C语言的strcat函数。(在shell makefile等文件中,可以认为所
有变量都是字符串,+=就相当于给字符串stcat接续内容)(注意一个细节,+=续接的
内容和原来的内容之间会自动加一个空格隔开)
注意:Makefile中并不要求赋值运算符两边一定要有空格或者无空格,这一点比shell的格式要求要松一些。
8、Makefile的环境变量
(1)makefile中用export导出的就是环境变量。一般情况下要求环境变量名用大写,普通变量名用小写。
(2)环境变量和普通变量不同,可以这样理解:环境变量类似于整个工程中所有Makefile之间可以共享的全局变量,而普通变量只是当前本Makefile中使用的局部变量。所以要注意:定义了一个环境变量会影响到工程中别的Makefile文件,因此要小心。
(3)Makefile中可能有一些环境变量可能是makefile本身自己定义的内部的环境变量或者是当前的执行环境提供的环境变量(譬如我们在make执行时给makefile传参。
make CC=arm-linux-gcc(在命令行输入该命令时,'='两端不可以有空格),其实就是给当前Makefile传了一个环境变量CC,值是arm-linux-gcc。我们在make时给makefile传的环境变量值优先级最高的,可以覆盖makefile中对CC的赋值)。
9、Makefile的自动变量
(1)为什么使用自动变量。在有些情况下文件集合中文件非常多,描述的时候很麻烦,所以我们Makefile就用一些特殊的符号来替代符合某种条件的文件集,这就形成了自动变量。
(2)自动变量的含义:预定义的特殊意义的符号。就类似于C语言编译器中预制的那些宏__FILE__一样。
(3)常见自动变量:
$@ 规则的目标文件名
$< 规则的依赖文件名
$^ 依赖的文件集合
三、Makefile深入学习资料
作为一名嵌入式软件工程师,并不一定需要自己 从无到有 手写一个复杂Makefile管理自己的项目,网上有很多成熟的模板可以套用,只要做到能看懂会修改即可。若想深入学习一下相关的知识,我给大家推荐一个资料《跟我一起学makefile》作者:陈皓。
链接:https://pan.baidu.com/s/1_yccwSdM1NsRts8jUBn42g
提取码:m21r
--来自百度网盘超级会员V6的分享
注:本资料大部分由朱老师物联网大讲堂课程笔记整理而来并且引用了部分他人博客以及百度百科的内容,如有侵权,联系删除!水平有限,如有错误,欢迎各位在评论区交流。