首页 > 其他分享 >make 的执行过程与条件判断

make 的执行过程与条件判断

时间:2022-10-06 17:37:18浏览次数:42  
标签:判断 make makefile mk ifeq 执行 vari

知识点

  • ​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​​ 命令,观察输出结果。

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​​ 命令观察输出结果。

make 的执行过程与条件判断_绝对路径_02

可以发现 ​​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 的输出结果如图:

make 的执行过程与条件判断_条件判断_03

说明三条命令是在三个不同的 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​​进行测试:

make 的执行过程与条件判断_条件判断_04

可以看出两条命令输出的进程 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 的输出结果如图所示:

make 的执行过程与条件判断_未定义_05

说明这三条命令是在同一个进程中被执行的。


使用反斜线\分割命令

在同一行中书写多条指令是一件比较麻烦的事情,尤其是指令较长时,非常不方便阅读和修改。 ​​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 的输出结果如图:

make 的执行过程与条件判断_未定义_06

可以看出执行效果与修改后的 ​​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 输出结果如图:

make 的执行过程与条件判断_绝对路径_07


​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 输出结果如图:

make 的执行过程与条件判断_绝对路径_08

​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 的执行过程与条件判断_绝对路径_09

可见对 ​​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 的执行过程与条件判断_未定义_10


本章学习了 ​​make​​ 执行的两个阶段,目标指令的执行细节以及 makefile 中条件执行语句的编写。

标签:判断,make,makefile,mk,ifeq,执行,vari
From: https://blog.51cto.com/u_15773567/5733921

相关文章