前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >实战Makefile前,该知道那些知识?

实战Makefile前,该知道那些知识?

作者头像
Rice加饭
发布2022-05-10 08:42:13
4620
发布2022-05-10 08:42:13
举报
文章被收录于专栏:Rice嵌入式

在前一篇文章讲解了Makefile的一些概念和原理,接下来说说Makefile的一些知识点。

make与make clean

生成目标文件规则(make命令):

执行make命令则会根据当前目录的Makefile文件定义的规则生成对应的目标文件。

如果Makefile为其他名字,比如makefile.linux,则需要使用make的参数(-f or --file)执行对应的Makefile文件,例如:

代码语言:javascript
复制
make -f makefile.linux

清空目标文件的规则(make clean命令):

每个Makefile中都应该写一个清空目标文件( .o 和目标文件等)的规则,这不仅便于重编译,也很 利于保持文件的清洁。也许在写Makefile的时候,都要养成这样一个习惯,一般的风格都是:

代码语言:javascript
复制
clean:
    rm $(obj) *.o

更为稳健的做法是(原因:如果当前目录存在clean文件,该命令会执行失败),解决办法:增加伪目标:.PHONY:clean:

代码语言:javascript
复制
.PHONY:clean
clean:
    rm $(obj) *.o

注意:

  • clean的规则不要放在文件 的开头,不然,会变成make的默认目标,一般:clean从来都是放 在文件的最后。

书写规则

显示规则(@字符):

当用@字符在命令前面时,那么执行这条命令的时候,这条命令不会显示出来。对比: 命令前加@字符例子:

代码语言:javascript
复制
rice@rice:~/rice_file/mkfile$ cat Makefile 
exec:
  @echo "rice makefile"
rice@rice:~/rice_file/mkfile$ make
rice makefile

命令前不加@字符例子:

代码语言:javascript
复制
rice@rice:~/rice_file/mkfile$ cat Makefile 
exec:
  echo "rice makefile"
rice@rice:~/rice_file/mkfile$ make
echo "rice makefile"
rice makefile

注意:

make命令参数 -s--silent--quiet 则是全面禁止命令的显示

命令执行规则:

当依赖目标新于目标时,make会一条一条的执行其后的命令。其中,加入要让上一条命令的结果应用在下一条命令时,应使用分号分隔这两条命令,并且不能将两条命令写在同一行。

例子1:

Makefile:

代码语言:javascript
复制
exec:
    @cd /home/rice
    @pwd

结果:

代码语言:javascript
复制
/home/rice/rice_file/mkfile

例子2:

Makefile:

代码语言:javascript
复制
exec:
    @cd /home/rice;pwd

结果:

代码语言:javascript
复制
/home/rice

从上面两个例子可以证明命令依赖的规则。

命令出错规则(-符号):

当命令运行完,make会检测每个命令的返回码,如果返回成功,那make会执行下一条命令,当规所有的命令成功返回后,make执行完成。如果一个规则中的某个命令出错了(命令退出码 非零),那么make就会终止执行当前规则,这将有可能终止所有规则的执行。

有时命令的出错并不表示错误。例如mkdir命令,建立一个目录,如果目录不存 在,则mkdir不会出现错误。如果目录已存在,那么将产生错误。从例子说明,mkdir的出错并没有对其他命令产生影响,因为我只要目录存,所以mkdir出错不应该终止命令规则的运行。

为了解决上述问题,只需要在Makefile的命令行前加一个符号-,即使命令执行出错,也依然继续执行后续的命令。

代码语言:javascript
复制
.PHONY:clean
clean:
    -rm $(obj) *.o

变量

变量的定义

Makefile也支持变量定义,变量的定义也让的我们的Makefile更加简化,可复用。

变量的定义:一般采用大写字母,赋值方式像C语言的赋值方式一样。

代码语言:javascript
复制
DIR = ./src/

变量取值:使用括号将变量括起来再加美元符。

代码语言:javascript
复制
FOO = $(DIR)

Makefile除了使用'='进行赋值,还有其他赋值方式,比如':='和'?=',接下来我们来对比一下这几种的区别:

赋值符'=':

代码语言:javascript
复制
PARA = RICE
CURPARA = $(PARA)
PARA = rice

print:
  @echo $(CURPATA)

结果为:

代码语言:javascript
复制
rice

变量CURPARA的值并不是“RICE”。其值为PARA最后一次赋值的值。说明,赋值符“=”,可以借助另外一个变量,可以将变量的真实值推到后面去定义。也就是变量的真实值取决于它所引用的变量的最后一次有效值。

赋值符':=':

代码语言:javascript
复制
PARA = RICE
CURPARA := $(PARA)
PARA = rice

print:
  @echo $(CURPATA)

结果为:

代码语言:javascript
复制
RICE

变量CURPARA的值为“RICE”。“=”和“:=”的区别就在这里,“:=”只取第一次被赋值的值。

赋值符'?=':

代码语言:javascript
复制
PARA = RICE
PARA ?= rice

print:
  @echo $(PATA)

结果为:

代码语言:javascript
复制
RICE

如果上面例子第一行去掉,结果为:

代码语言:javascript
复制
rice

说明,如果变量PARA 前面没有被赋值,那么此变量就是“rice”,如果前面已经赋值过,那么就使用前面赋的值。

赋值符'+=':

Makefile中的变量是字符串,有时候我们需要给前面已经定义好的变量添加一些字符串进去,此时就要使用到符号"+=":

代码语言:javascript
复制
OBJ = main1.o main2.o
OBJ += main3.o

OBJ的值为:”main1.o,main2.o,main3.o“。说明“+=”用作与变量的追加。

系统自带变量:

系统自定义了一些变量,通常都是大学,比如CC,PWD,CLFAG等等,有些有默认值,有些没有,比如以下几种,如下

  • CPPFLAGS:预处理器需要的选项,如:-l
  • CFLAGS:编译的时候使用的参数-Wall -g -c
  • LDFLAGS:链接库使用的选项-L -l

其中:默认值可以被修改,比如CC默认值是cc,但可以修改为gcc:CC=gcc

自动变量:

Makefile的语法提供一些自动变量,这些变量可以让我们更加快速的完成Makefile的编写,其中自动变量只能在规则中的命令使用,常用的自动变量如下:

  • $@:规则中的目标
  • $<:规则中的第一个依赖文件
  • $^:规则中的所有依赖文件
代码语言:javascript
复制
CC = gcc
OBJ = main.o add.o
output: $(OBJ)
  $(CC) -o $@ $^
main.o: main.c
  $(CC) -c $<
add.o: add.c
  $(CC) -c $<

.PHONY:clean
clean:
  @rm $(OBJ) output

模式规则

模式规则实在目标及依赖中使用%来匹配对应的文件,我们依旧使用上面的例子,采用模式规则格式,如下:

代码语言:javascript
复制
CC = gcc
OBJ = main.o add.o
output: $(OBJ)
  $(CC) -o $@ $^
%.o: %.c
  $(CC) -c $<

.PHONY:clean
clean:
  @rm $(OBJ) output

其中:

main.o由main.c生成

add.o 由add.c生成

函数

Makefile提供了大量的函数,其中我们经常使用的函数主要有两个(wildcard,patsubst)。

wildcard函数:用于查找指定目录下指定类型的文件,函数参数:目录+文件类型,使用方法:

代码语言:javascript
复制
SRC = $(wildcard ./src/*.c)

print:
  @echo $(SRC)

结果:

代码语言:javascript
复制
./src/add.c ./src/main.c

表示:找到目录./src下所有后缀为.c的文件,并赋值给变量SRC。命令执行完,SRC变量的值:./src/add.c ./src/main.c

patsubst函数:用于匹配替换。函数参数:原模式+目标模式+文件列表,使用方法:

代码语言:javascript
复制
SRC = $(wildcard ./src/*.c)
OBJ = $(patsubst %.c, %.o, $(SRC))

print:
  @echo $(OBJ)

结果:

代码语言:javascript
复制
./src/add.o ./src/main.o

表示:把变量中所有后缀为.c的文件替换为.o。命令执行完,OBJ变量的值:./src/add.o ./src/main.o

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-02-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Rice 嵌入式开发技术分享 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 清空目标文件的规则(make clean命令):
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档