知识点
-
make
读取 makefile 文件并执行更新和重建操作 - makefile 反斜线的使用
- makefile 中条件语句的基本格式
- makefile 关键字
ifeq
,ifneq
,ifdef
,ifndef
的使用
代码获取
通过在 Terminal 中输入以下命令可以将本课程所涉及到的所有源代码下载到linux环境中,作为参照对比进行学习。
wget http://labfile.oss.aliyuncs.com/courses/849/make_example-master.zip && unzip make_example-master.zip && rm make_example-master.zip
命令执行后 WebIDE 的工作区中将会出现一个名为 make_example-master 的文件夹
本章节的源代码位于 /home/project/make_example-master/chapter3
目录下,请在 Terminal 中通过 cd 命令切换至该目录后再进行实验学习。
1️⃣ make 的两个执行阶段
编写 makefile 文件内容如下:
# this is a makefile example
vari_a = "vari a from makefile"
vari_b = "vari b from makefile"
.PHONY:all
all:
@echo $(vari_a)
@echo $(vari_b)
在 makefile 文件中我们定义了两个变量 vari_a
与 vari_b
,同时我们在执行规则 all
时将他们的值打印输出,现在执行 make
命令,观察输出结果。
新增一个文件 inc_a
,在文件中声明一个变量 vari_b
值为 「vari b from inc_a」。 提供的源代码中已有此文件,内容如下:
# this is a include file for make
vari_b = "vari b from inc_a"
复制代码
修改 makefile 文件,在文件的最后一行通过 include
将 inc_a
包含到 makefile 中。
include inc_a
复制代码
执行 make
命令观察输出结果。
可以发现 vari_b
的值被修改了。
我们知道 make
是按照顺序一行行读入 makefile。 前面介绍make
的第一阶段是读入所有 makefile 文件,include
导入的文件以及环境变量指定的文件。所以解析新修改的 makefile 时,inc_a
应该在第一阶段被解析完毕,所以 vari_b
变量就被 inc_a
修改掉了。
由此说明文件的处理顺序与
include
指示符在 makefile 中的位置无关。
2️⃣ make 目标指令的执行细节
到目前为止,我们已经知道 makefile 中的指令都是 shell 指令,那么 make
是怎样执行目标对应指令呢? 答案还是 shell。make
会调用 shell 去执行每一条指令。需要注意的是,即便在同一个目标下,每一条指令都是相互独立的。 也就是说 make
会分别调用 shell 去执行每一条指令,而非使用一个 shell 进程按顺序执行所有的命令。
测试命令pwd
和cd
的执行效果。
使用 cd
命令和 pwd
命令查看两条相邻的命令能否相互产生影响,由此来验证说法的正确性。 在提供的源文件代码中已经有 cd_test.mk
文件,内容如下:
# this is a makefile to test cd and pwd cmd
.PHONY:all
all:
@pwd
cd ..
@pwd
复制代码
从内容中我们可以知道 all
规则是由三条命令构成的,其中 @pwd
表示打印当前绝对路径,但不要显示 pwd
命令,cd ..
表示回到上一层目录。 因此,若三条指令是在一个 shell 进程中顺序执行,那么命令的执行顺序是先打印当前目录的绝对路径,再返回上一层目录并打印上一层目录的绝对路径。若是三条指令是在三个不同的 shell 中执行的,则两次 @pwd
命令的执行结果将会是相同的。
现在执行下面的命令并观察输出结果。
make -f cd_test.mk
复制代码
Terminal 的输出结果如图:
说明三条命令是在三个不同的 shell 中执行的。
打印进程id
确认指令会被不同的进程执行。
现在我们用另外一种方法来进行证明,打印执行当前命令的进程 id,通过观察进程 id 是否相同来判断不同行的命令是否是在同一个 shell 中执行的。提供的源代码中已有用来测试的代码文件 cmd_test.mk
, 内容如下:
#this is a command test makefile
.PHONY:all
all:
@echo "cmd1 process id is :" $$$$
@echo "cmd2 process id is :" $$$$
其中“$$$$”
代表的是当前进程id
。 所以cmd_test.mk
的命令执行过程就是分别打印all
目标下两条命令的进程id
。 执行make -f cmd_test.mk
进行测试:
可以看出两条命令输出的进程 id 是不同的
目标下的每一条命令都是通过不同的shell执行的。
在同一行中使用多条命令
有些状况下,用户希望能够使用 cd
命令来控制命令执行时所在的路径,比如 cd
到某个目录下,编译其中的源代码,要实现该操作就必须在一行中写入多条指令。
先修改cd_test.mk
文件,将三条指令都放在一行,并用“;”
隔开。 请注意第三条“@pwd”
的指令中,“@”
符号要删掉,此符号只用于每一行的开头。 修改后的cd_test.mk
内容如下:
# this is a makefile to test cd and pwd cmd
.PHONY:all
all:
@pwd; cd .. ; pwd
执行以下命令:
make -f cd_test.mk
Terminal 的输出结果如图所示:
说明这三条命令是在同一个进程中被执行的。
使用反斜线\分割命令
在同一行中书写多条指令是一件比较麻烦的事情,尤其是指令较长时,非常不方便阅读和修改。 makefile
中可以使用反斜线“\”
来将一行的内容分割成多行。 源文件中有一个multi_test.mk
脚本,用于测试反斜线的作用,内容如下:
#this is a command test makefile
.PHONY:all
all:
@echo "cmd1 process \
id is :" $$$$; \
echo "cmd2 process id is :" $$$$
复制代码
此文件将一条指令分割成 3 行,其中第 1 行和第 2 行组成一条完整的指令,内容与第 3 行指令相似。两条指令的作用也是打印当前执行进程的 id 号。 使用 make -f multi_test.mk
命令执行此文件。
Terminal 的输出结果如图:
可以看出执行效果与修改后的 cmd_test.mk
文件执行效果一致,说明反斜杠的确能起到连接多行指令的作用。
3️⃣ makefile 中的条件判断语句
条件判断语句的基本格式
makefile 中没有 else
分支的条件判断语句的格式如下:
CONDITIONAL-DIRECTIVE
TEXT-IF-TRUE
endif
复制代码
其中 TEXT-IF-TRUE
可以为若干任何文本行,当条件为真时它被 make
作为需要执行的一部分。
makefile 中有 else
分支的条件判断语句格式如下:
CONDITIONAL-DIRECTIVE
TEXT-IF-TRUE
else
TEXT-IF-FALSE
endif
复制代码
其中 make
在条件为真时执行 TEXT-IF-TRUE
,否则执行TEXT-IF-FALSE
。
条件判断语句中的关键字
关键字 | 描述 |
ifeq | 判断参数是否相等 |
ifneq | 判断参数是否不相等 |
ifdef | 判断变量是否有值 |
ifndef | 判断变量是否无值 |
ifeq 语句
ifeq 用于判断条件是否相等,可以支持以下几种格式:
ifeq (ARG1, ARG2)
ifeq 'ARG1' 'ARG2'
ifeq "ARG1" "ARG2"
ifeq "ARG1" 'ARG2'
ifeq 'ARG1' "ARG2"
复制代码
❗ 注意:ifeq/ifneq
等关键字后面一定要接一个空格,否则 make
会因为无法识别关键字而报错!
提供的代码文件中已有 eq.mk
文件,内容如下:
#this is a makefile to test ifeq
.PHONY:all
b="ifeq default"
ifeq ($(a),1)
b="ifeq a 1"
endif
ifeq '$(a)' '2'
b="ifeq a 2"
endif
ifeq "$(a)" "3"
b="ifeq a 3"
endif
ifeq "$(a)" '4'
b="ifeq a 4"
endif
ifeq '$(a)' "5"
b="ifeq a 5"
endif
all:
@echo $(b)
复制代码
依次执行下面的命令:
make -f eq.mk
make -f eq.mk a=1
make -f eq.mk a="1"
make -f eq.mk a=2
make -f eq.mk a=3
make -f eq.mk a=4
make -f eq.mk a=5
make -f eq.mk a=6
复制代码
Terminal 输出结果如图:
ifneq
语句
ifneq
支持的格式与 ifeq
相同,同样提供的代码文件中已有 neq.mk
文件,内容如下:
#this is a mekfile to test ifneq
.PHONY:all
ifneq ($(a),)
b=$(a)
else
b="null"
endif
all:
@echo "value b is:" $(b)
neq.mk
中的条件判断语句使用了 ifneq ... else ... endif
结构。 当 a
不为空时,b
的值与 a
相同,否则 b
为默认值 null
。
依次执行下面的 make
命令,打印输出 b
在各种情况下的值:
make -f neq.mk
make -f neq.mk a=1
make -f neq.mk a=2
make -f neq.mk a="hello"
Terminal 输出结果如图:
ifdef
语句
ifdef
语句的语法格式如下:
ifdef VARIABLE-NAME
它只会判断变量是否有值,而不关心其值是否为空。
现在我们测试 ifdef
的用法,以及要怎样理解变量值为空和变量未定义的差别。 提供的源代码文件中已有测试需要的代码文件def.mk
,内容如下:
#this is a makefile to test ifdef
.PHONY:all
a=
b=$(a)
ifdef a
c="a is defined"
else
c="a is not defined"
endif
ifdef b
d="b is defined"
else
d="b is not defined"
endif
all:
@echo "vari a is:" $(a)
@echo "vari b is:" $(b)
@echo "vari c is:" $(c)
@echo "vari d is:" $(d)
def.mk
文件中先声明了一个变量 a
,但并未给其赋值,即变量 a
未定义。 变量 a
又被赋给了变量 b
,由于 a
是未定义变量,因此 b
为空值。 make
执行此文件时分别打印变量 a
、b
、c
、d
的值。
现在执行下面的 make
命令,观察输出结果。
make -f def.mk
Terminal 的输出结果如图:
可见对 make
来说,它认为 a
属于未定义变量,b
则属于已定义变量。
ifndef
语句
ifneq
格式与 ifeq
相同,逻辑上与 ifneq
相反。 提供的源代码中包含了测试需要用到的代码文件 ndef.mk
文件,它的内容与 def.mk
相似:
#this is a makefile to test ifndef
.PHONY:all
a=
b=$(a)
ifndef a
c="a is not defined"
else
c="a is defined"
endif
ifndef b
d="b is not defined"
else
d="b is defined"
endif
all:
@echo "vari a is:" $(a)
@echo "vari b is:" $(b)
@echo "vari c is:" $(c)
@echo "vari d is:" $(d)
现在执行下面的 make
命令并查看输出结果。
make -f ndef.mk
Terminal 中的输出结果如图所示:
标签:判断,make,makefile,mk,ifeq,执行,vari From: https://blog.51cto.com/u_15773567/5733921本章学习了
make
执行的两个阶段,目标指令的执行细节以及 makefile 中条件执行语句的编写。