嵌入式Linux学习---Day3

368 阅读5分钟

今天我们来浅浅的讲一下Makefile

一. Makefile是什么

我们在Linux中通常会使用make命令来编译,但是make命令它所依赖的就是名为Makefile的文件,make命令编译的也就是根据Makefile里面的东西来编译的.

二. Makefile的规则

我们在Makefile里面写各种各样的东西不能乱写,要遵循一定的规则。

目标(target) : 依赖(prerequiries)

tab 命令(command)

命令执行条件:依赖文件比目标文件,或者目标文件没有生成

image.png

我就利用这个来讲解一下Makefile的规则吧

objection : a.o b.o c.o的意思就是objection这个目标依赖于a.o b.o c.o三个文件,然后下面就是gcc -o object a.o b.o c.o就是命令,下面三个亦是如此。

image.png

执行make objection的时候,我们的目标文件(objection)还没有生成,这个时候,就会执行对应的命令gcc -o object a.o b.o c.o,然后呢,又发现a.o b.o c.o也没有生成,那么继续往后面找,发现a.o b.o c.o都依赖于对应的.c文件,那么他们又会执行对应的命令,来生成对应的.o文件,最后所有的.o文件都有了,就可以执行gcc -o object a.o b.o c.o这条命令了

三. Makefile的变量以及常用函数

1. Makefile变量

:= 即时变量(使用的时候才会赋值,其余的时候是空)

= 延时变量

?= 延时变量(只有第一次定义才起效,如果前面已经定义,可以忽略这个命令)

+= 这个是即时还是延时变量取决于前面的定义是即时变量还是延时变量

image.png

image.png

echo是打印出值,类似于C语言中的printf,@是不让我们看到命令,$在这里是对变量取值。我们可以看到,A是没有值的,因为A是即时变量,使用的时候才赋值,但是C在all目标的后面了,所以A就没有值了

2. Makefile的函数
2.1 foreach函数

$(foreach var, list, text) 简单的说就是for each var in list, change it to text,对list里面的每一个元素,取出来赋值给var,然后把var改成text

image.png

image.png

看到这个,我们把name这个变量里面的每一个值都给到了f,然后用$(f).o来替换f,说白了就是t用t.o来替换,里面每一个都应.o来替换

2.2 filter or filter-out函数

$(filter pattern, text) 把text中符合pattern的内容过滤出来,然后留下来

$(filter-out pattern, text) 把text中符合pattern的内容过滤出来,扔掉

image.png

image.png

%是通配符的意思,然后direction1就是把符合%/的东西留下来,也就是d/,direction2恰恰相反,就是把符合%/的东西找到,扔掉,我们可以看到其实这两个函数是互补的

2.3 wildcard函数

$(wildcard pattern) pattern所列出的文件,把存在的文件都列出来

image.png

image.png

这里涉及到了一个patsubst函数,我们先不管,先看wildcard函数,我们看到files,这个就是使用了wildcard函数,*在这里是通配符的意思,所有后缀是.c的并且都存在的文件列出来

2.4 patsubst函数

$(patsubst patternn, replacement, text) 寻找text中符合pattern的东西,用replacement替换

image.png

image.png

这是刚才讲解wildcard函数用到的,我们重点看一下replace_file这个,在file1中寻找,把所有的.c文件都改成.h文件

四. Makefile常用技巧

文件

$@ : 目标文件

$^ : 所有依赖文件

$< : 第一个依赖文件

image.png

重点看我框出来的,我们在使用gcc命令可能需要使用到很多个依赖文件,我直接使用就可以指代所有,我们就不需要一个一个的写什么a.o b.o啥的了。

image.png

这里也看我框出来的部分,根据Makefile规则,这里意思就是所有的.o文件依赖于.c文件,然后只要.o文件没有生成或者.c文件比.o文件新,那么就会执行命令。这个命令就不需要我们直接去写什么a.o a.c之类的玩意了

假想目标 : .PHONY

image.png

在这里我们想要使用make clean是可以的,但是万一我们有一个文件恰巧名字就是clean呢,那么会发生冲突,所以我们可以使用.PHONY假想目标来解决这个问题。这样就算有clean这个文件我们也不会有太大的问题了。

依赖头文件

Makefile有很多好用的地方,但是也有其缺点,那就是我们不设定一般不会包含头文件,需要我们自己在命令中去写

gcc -M c.c 查看c.c所依赖的头文件

gcc -M -MF c.d c.c 生成一个c.d的文件,将c.c依赖的头文件放入c.d里面去

gcc -c -o c.o c.c -MD -MF c.d 这个就是会编译c.c然后生成一个c.d的文件,将c.c依赖的头文件放入c.d里面去

image.png

我们使用make命令之后,然后会直接找到第一个目标test,test依赖objs里面的.o文件,然后.o文件依赖.c文件,就会执行命令生成.o文件,并且生成它对应的依赖文件,然后dep_files里面的文件是函数将objs里面的.o文件变成的,我们使用wildcard发现dep_files里面的文件确实存在,所有就包含了头文件。

这样做的一个最大好处就是我们修改头文件里面的东西,不会影响我们编译后应用程序的正常使用。如果我们不这么做,我们修改了头文件里面的东西,那么我们重新编译的应用程序里面依赖的头文件不会实时更新。

CFLAGS

image.png

大家主要看框出来的部分,CFLAGS中-Werror是如果有警告信息,直接当成错误信息打印出来,这样子是为了有的警告大家不当回事,后续容易引发事故,所以这样子能有效防范大家出错。而这个-I呢就是头文件,我这里其实把所有需要用到的头文件都放到了一个名字叫做include的文件夹里面去了,而这个include文件夹呢和我们的Makefile同级,我这里呢,是为了方便管理,所有头文件都放到一个文件夹中,然后这里使用了这个都去指定的文件夹寻找头文件