Makefile中的函数介绍

@echo 用法

如果规则的命令行以字符@开始,则make在执行这个命令时就不会回显这个将要被执行的命令。
例如:
@echo '开始编译XXX模块'执行时,将会得到“开始编译XXX模块”这条输出信息。
如果在命令行之前没有字符@,那么,make 的输出将是:“echo '开始编译XXX模块'

eval 函数

$(eval text)
作用:是Makefile的一个内建函数,用于在Makefile中动态创建新的make规则。会将参数文本解析为Makefile语法,然后执行。
参数:text是你想要创建的make规则或者定义的变量
返回:文件所在目录。

ln 命令

ln [选项]... [-T] 目标 链接名 # 创建一个到目标的链接,名称为链接名
ln [选项]... 目标         # 在当前目录中创建一个到目标的链接
ln [选项]... 目标... 目录   # 在目录中创建指向每个目标的链接
选项:
  --backup[=CONTROL] : 为每个已存在的目标文件创建备份文件
  -b: 类似–backup,但不接受任何参数
  -d, -F, --directory : 创建指向目录的硬链接(只适用于超级用户)
  -f, --force: 强行删除任何已存在的目标文件
  -i, --interactive: 提示是否删除目的地
  -L, --logical: 解引用的目标是符号链接
  -n, --no-dereference: 将链接名视为普通文件,它是指向目录的符号链接
  -P, --physical: 将硬链接直接设置为符号链接
  -r, --relative: 创建相对于链接位置的符号链接
  -s, --symbolic: 用符号链接代替硬链接
  -S, --suffix=SUFFIX : 覆盖通常的备份后缀
  -t, --target-directory=DIRECTORY : 指定在其中创建链接的DIRECTORY
  -T, --no-target-directory: 始终将LINK_NAME视为普通文件
  -v, --verbose: 打印每个链接文件的名称
  --help: 显示此帮助信息并退出
  --version: 显示版本信息并退出

cc-option 函数

$(call cc-option,-fno-stack-protector)
第一个参数赋给$ (1)(这里是指-fno-stack-protector),
第二个参数给$(2)(这里为空)。

变量cc-option的值是函数try-run的执行结果,函数try-run又是$(shell ....)输出的结果;也就是if …else…的结果。在函数try-run中:

  1. $(1) : $(CC) -Werror $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -x c /dev/null -o "
  2. $(2) : 函数cc-option的 $(1) (这里是指-fno-stack-protector)
  3. $(3) : 函数cc-option的 $(2) (这里为空)

如果函数try-run的$(1)能执行,那么echo $(2),否则echo $(3);echo 的值正是cc-option的值 。


综上:
如果交叉编译工具$(CC)支持cc-optionl函数参数1表示的选项(也就是指-fno-stack-protector),那么cc-option函数的返回就是该选项(指-fno-stack-protector),否则返回的是call函数的参数2表示的选项。

cc-option:检测$(CC) 是否支持给定的选项

cc-disable-warning 函数

cc-disable-warning 检查 gcc 是否支持给定的警告,并返回命令行开关以禁用它。此特殊函数是必需的,因为 gcc 4.4 及更高版本接受任何未知的-Wno-*选项,并且仅在源文件中有其他警告时才发出警告。

KBUILD_CFLAGS += $(call cc-disable-warning, stringop-truncation)

在上面的示例中,只有当 gcc 真正接受 -Wno-stringop-truncation变量时,才会将其添加到KBUILD_CFLAGS

dir 函数

$(dir <names...>)
作用:获取文件所在目录,本质是获取最后一个反斜杠 ‘/’ 以前的内容。如果没有反斜杠 ‘/’ ,返回 ./
参数:不同文件名之间以空格隔开。
返回:文件所在目录。

basename 函数

$(basename <names...>)
作用:从文件名序列 <names> 中取出各个文件名的前缀部分。
参数:文件名序列
返回:返回文件名序列 <names> 的前缀序列,如果文件没有前缀,则返回空字串。
例如:

$(basename  src/main.c  src/hello.c) 
返回值为:src/main src/hello

notdir 函数

$(notdir <names...>)
作用:获取一个文件路径的非目录部分,也可以理解为获取文件名(含后缀),本质是获取最后一个反斜杠 ‘/’ 之后的内容。如果没有反斜杠,直接返回本身。
参数:不同文件名之间以空格隔开。
返回:文件名(含后缀)。

wildcard 函数

$(wildcard PATTERN...)
作用:在Makefile中用于获取匹配指定模式的所有文件名列表。
参数:指定模式。
返回:返回与模式相匹配的所有文件名列表,如果没有任何匹配,那么返回空字符串。

addprefix 函数

$(addprefix PREFIX,NAMES…)
作用:文件名添加前缀的函数,为“NAMES…”中的每一个文件名添加前缀“PREFIX”
参数:“NAMES…”是空格分割的文件名序列;“PREFIX”是给文件名添加的前缀。
返回:以单空格分割的添加了前缀“PREFIX”的文件名序列。

foreach函数

$(foreach VAR,LIST,TEXT)
作用:执行时把"LIST"中使用空格分隔的字符串依次取出赋值给变量"VAR",然后执行"TEXT"表达式。重复直到"LIST"的最后一个字符串。"TEXT"中的变量或函数引用在执行时才被展开,因此,如果在"TEXT"中存在对"VAR"的引用,那么"VAR"的值在每一次展开式将会是不同的值。如果存在变量或函数的引用,首先需要展开变量"VAR"和"LIST"的引用
参数:"VAR"是一个局部的临时变量,它只在"foreach"函数的上下文有效,它的定义不影响其他部分定义的同名"VAR"变量的值。
返回:无。

filter函数

$(filter PATTERN…,TEXT)
作用:过滤掉字串“TEXT”中所有不符合模式“PATTERN”的单词,保留所有符合此模式的单词。可以使用多个模式。模式中一般需要包含模式字符“%”。存在多个模式时,模式表达式之间使用空格分割。
参数:
返回:空格分割的“TEXT”字串中所有符合模式“PATTERN”的字串。

filter-out函数

$(filter-out PATTERN…,TEXT)
作用:过滤掉字串“TEXT”中所有符合模式“PATTERN”的单词,保留所有不符合此模式的单词。可以有多个模式。存在多个模式时,模式表达式之间使用空格分割。
参数:
返回:空格分割的“TEXT”字串中所有不符合模式“PATTERN”的字串。

patsubst函数

$(patsubst pattern,replacement,text)
作用:过查找text中的单词(单词以“空格”、“Tab”或“回车”“换行”分隔)是否符合模式pattern,如果匹配的话,则以replacement替换。这里,pattern可以包括通配符“%”,表示任意长度的字串。如果replacement中也包含“%”,那么,replacement中的这个“%”将是pattern中的那个“%”所代表的字串。(可以用“\”来转义,以“%”来表示真实含义的“%”字符)
参数:
返回:返回被替换过后的字符串。

sort函数

$(sort list)
作用:是Makefile的一个内建函数,它用于将列表中的词进行排序,并删除重复的词。
参数:
返回:

call函数

$(call 函数名 参数1, 参数2, ...)
作用:给自定义函数传递参数,并展开。一般而言,call 本身并不具备编译功能,call 只是将自定义函数在当前位置展开,遇到Makefile内置函数​​​​​​​会自动执行(比如 info,warning等),调用函数的时候要使用字符“$”,后面可以跟小括号也可以使用花括号。
参数:参数之间要用逗号分隔开,参数和函数名之间使用空格分开。
返回:函数名对应的函数返回值就是 call 函数的返回值。
注意: make 执行这个函数的时候,函数名对应的函数参数中的变量$(1)、$(2)、$(3)等,会被参数1,参数2,参数3依次取代。

subst函数

$(subst <from>,<to>,<text>)
作用:字符串处理函数,把字符串<text>中的<from>字符串替换成<to>。
参数:
返回:返回被替换过后的字符串。

strip函数

$(strip STR)
作用:去掉字符串中多余的空格符(若干单词,使用若干空字符分割) “STR”开头和结尾的空字符,并将其中多个连续空字符合并为一个空字符。
参数:
返回:无前导和结尾空字符、使用单一空格分割的多单词字符串。

firstword函数

$(firstword <text>)
作用:取字符串 中的第一个单词。
参数:
返回:返回字符串 的第一个单词。

@F

@F表示"$@“的文件部分,如果”$@“值是"dir/foo.o”,那么"$(@F)“是"foo.o”,“$(@F)“相当于函数”$(notdir $@)”

cmp 命令

cmp 命令是 Linux 系统中用于比较两个文件是否有差异的命令。它能够比较两个文件的内容,并在发现差异时显示差异的位置。如果两个文件完全相同,cmp 命令不会输出任何信息。
使用 cmp 命令时,可以指定两个文件名作为参数,也可以使用 - 作为参数来从标准输入读取数据。此外,cmp 命令支持多种选项来控制其行为,例如:
-l 或 --verbose:显示所有不同之处。
-s 或 --quiet--silent:不显示错误信息。
-c 或 --print-chars:除了标明差异处的十进制字码之外,一并显示该字符所对应字符。
-i <字符数目> 或 --ignore-initial=<字符数目>:指定一个数目,忽略每个文件开头的指定数量的字符后再进行比较。
-v 或 --version:显示版本信息。
–help:显示帮助信息。

touch 命令

touch [选项] [文件名]
作用:用来创建新的空文件或者修改已有文件的访问时间和修改时间。如果文件不存在,则会创建出一个空内容的文本文件;如果文件已经存在,则会对文件的Atime(访问时间)和Ctime(修改时间)进行修改操作,管理员可以完成此项工作,而普通用户只能管理主机的文件。
参数1:[选项]
      -a:只修改访问时间
      -c:仅在文件不存在的情况下创建文件
      -m:只修改修改时间
      -d:使用指定的时间,而非当前时间作为文件的时间
参数2:[文件名] 创建或修改的文件。

示例:

  1. 创建新文件:touch newfile.txt
    在当前目录下创建一个名为newfile.txt的空文件
  2. 批量创建文件:touch file{1..5}.txt
    创建file1.txt、file2.txt、file3.txt、file4.txt、file5.txt这五个文件
  3. 更新文件时间戳:touch -m file.txt
    将file.txt的修改时间更新为当前时间
  4. 指定时间戳:touch -d "2022-01-01" file.txt
    将file.txt的时间属性修改为指定的日期
  5. 创建带有目录结构的文件:mkdir dir && touch dir/file.txt
    先创建一个名为dir的目录,然后在该目录下创建一个名为file.txt的文件
  6. 更新多个文件的时间戳:touch file*.txt
    更新所有以file开头且以.txt结尾的文件的时间戳
  7. 修改访问时间而不新建文件:touch -a file.txt
    将file.txt的访问时间更新为当前时间
  8. 禁止创建新文件:touch -c newfile.txt
    如果newfile.txt文件已经存在,则不会有任何变化;如果文件不存在,则不会创建新文件

fixdep工具

fixdep <depfile> <target> <cmdline>
作用:查找实现目标所用的命令、源码、头文件等全部信息。
参数1:<depfile>编译产生的依赖文件*.d
参数2:<target>编译生成的目标
参数3:<cmdline>编译使用的命令
返回:实现目标所用的命令、源码、头文件等全部信息

escsq函数(uboot)

作用:将参数1(字符串)中的'替换成\'
返回:返回被替换过后的字符串。
分析:此函数在 scripts/Kbuild.include 第32行定义:

7 squote  := '
32 escsq = $(subst $(squote),'\$(squote)',$1)

make-cmd函数(uboot)

作用:将$(cmd_$(1)) 中的\$替换成$$,然后将替换后的字符串中的#替换成$(pound)[即 \#],再次将替换后的字符串中'替换成\'
返回:返回$(cmd_$(1)) 被替换过后的字符串。
分析:此函数在 scripts/Kbuild.include 第32行定义:

11  pound := \#
252 make-cmd = $(call escsq,$(subst $(pound),$$(pound),$(subst $$,$$$$,$(cmd_$(1)))))

echo-why函数(uboot)

作用:条件不成立,函数为空
分析:此函数在 scripts/Kbuild.include 第299-318行定义:

299	ifeq ($(KBUILD_VERBOSE),2)
300	why =                                                                        \
301		$(if $(filter $@, $(PHONY)),- due to target is PHONY,                    \
302			$(if $(wildcard $@),                                                 \
303				$(if $(strip $(any-prereq)),- due to: $(any-prereq),             \
304					$(if $(arg-check),                                           \
305						$(if $(cmd_$@),- due to command line change,             \
306							$(if $(filter $@, $(targets)),                       \
307								- due to missing .cmd file,                      \
308								- due to $(notdir $@) not in $$(targets)         \
309							 )                                                   \
310						 )                                                       \
311					 )                                                           \
312				 ),                                                              \
313				 - due to target missing                                         \
314			 )                                                                   \
315		 )
316
317	echo-why = $(call escsq, $(strip $(why)))
318	endif

由于输入make V=1,所以$(KBUILD_VERBOSE)=1,这里条件不成立,echo-why 为空

echo-cmd函数(uboot)

作用:$($(quiet)cmd_$(1)))中的'替换成\'后打印
返回:$($(quiet)cmd_$(1)))中的'替换成\'后打印
分析:此函数在 scripts/Kbuild.include 第220行定义:

220 echo-cmd = $(if $($(quiet)cmd_$(1)),\
221 	echo '  $(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';)

判断$($(quiet)cmd_$(1)))是否存在,不存在echo-cmd=空,否则将$($(quiet)cmd_$(1)))中的'替换成\'后打印

set -e

set -e 是 Linux shell 中的一个选项,它的作用是在脚本执行过程中,一旦出现任何命令执行失败(返回非零的退出状态码),脚本就会立即退出。

cmd函数(uboot)

作用: 执行cmd_$(1)内容,打印其内容。
分析:由于在顶层Makefile的第386行中引用include scripts/Kbuild.include, cmd函数在此文件224行中定义:

7   squote  := '
32  escsq = $(subst $(squote),'\$(squote)',$1)
......
299 ifeq ($(KBUILD_VERBOSE),2)
300 why =                                                                        \
301     $(if $(filter $@, $(PHONY)),- due to target is PHONY,                    \
302         $(if $(wildcard $@),                                                 \
303             $(if $(strip $(any-prereq)),- due to: $(any-prereq),             \
304                 $(if $(arg-check),                                           \
305                     $(if $(cmd_$@),- due to command line change,             \
306                         $(if $(filter $@, $(targets)),                       \
307                             - due to missing .cmd file,                      \
308                             - due to $(notdir $@) not in $$(targets)         \
309                          )                                                   \
310                      )                                                       \
311                  )                                                           \
312              ),                                                              \
313              - due to target missing                                         \
314          )                                                                   \
315      )
316 
317 echo-why = $(call escsq, $(strip $(why)))
318 endif
......
220 echo-cmd = $(if $($(quiet)cmd_$(1)),\
221 	echo '  $(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';)
222
223
224 cmd = @$(echo-cmd) $(cmd_$(1))

第220行,$(quiet) 在顶层Makefile中定义:
命令行中输入:make V=number其中number不等于1时,quiet=quiet_,否则为空
命令行中输入:make -s时,quiet=silent_,否则为空
由于输入的是make V=1,所以quiet=
第220行,escsq函数定义在第32行,最终 $(call escsq, ( ( ((quiet)cmd_$(1))) 展开后为 cmd_$(1)
第220行,$(echo-why)定义在第317行,由于输入的是make V=1,所以KBUILD_VERBOSE=1,条件不成立,$(echo-why)为空
第220行,最终展开为:即判断cmd_$(1)是否存在,存在则打印其内容

220 echo-cmd = $(if $(cmd_$(1)),echo '  $(cmd_$(1))';)

第224行,最终展开为:即判断cmd_$(1)是否存在,不论是否存在都不回显其内容,最后执行cmd_$(1)内容

224 cmd = @$(if $(cmd_$(1)),echo '  $(cmd_$(1))';)    $(cmd_$(1))

if_changed_dep函数(uboot)

作用: 打印和执行cmd_$(1),并将实现目标$@所用的命令、源码、头文件等信息全部写入到 $(obj)/.$@.cmd 文件中。
分析:由于在顶层Makefile的386行引用scripts/Kbuild.include, if_changed_dep 函数在此文件266行中定义:

5   comma   := ,
14  # Name of target with a '.' as filename prefix. foo/bar.o => foo/.bar.o
15  dot-target = $(dir $@).$(notdir $@)
20  depfile = $(subst $(comma),_,$(dot-target).d)
......
237	ifneq ($(KBUILD_NOCMDDEP),1)
238	# Check if both arguments are the same including their order. Result is empty
239	# string if equal. User may override this check using make KBUILD_NOCMDDEP=1
240	arg-check = $(filter-out $(subst $(space),$(space_escape),$(strip $(cmd_$@))), \
241							 $(subst $(space),$(space_escape),$(strip $(cmd_$1))))
242	else
243	arg-check = $(if $(strip $(cmd_$@)),,1)
244	endif
......
256	any-prereq = $(filter-out $(PHONY),$?) $(filter-out $(PHONY) $(wildcard $^),$^)
......
266	if_changed_dep = $(if $(strip $(any-prereq) $(arg-check) ),                  \
267		@set -e;                                                             \                                                         
268		$(echo-cmd) $(cmd_$(1));                                             \                                  
269		scripts/basic/fixdep $(depfile) $@ '$(make-cmd)' > $(dot-target).tmp;\
270 	rm -f $(depfile);              
271 	mv -f $(dot-target).tmp $(dot-target).cmd, @:)                                      \

第266行中$(any-prereq)在第256行中定义,$?依赖文件列表中被改变过的所有文件,$^表示所有的依赖文件,所以$(filter-out $(PHONY) $(wildcard $^),$^)返回的是空字符串。
最终: any-prereq=$? 【依赖文件列表中被改变过的所有文件】
第266行中$(arg-check)在第237-244行中定义,只有在命令行中输入make KBUILD_NOCMDDEP=1时,执行243行,所以这里执行240行,其中的$(space),$(space_escape) 在8-10行定义。
最终: arg-check = 将 $(cmd_$1) 中所有空格替换成 -SPACE- 后的字符串

8  empty  		:=
9  space   		:= $(empty) $(empty)
10 space_escape := _-_SPACE_-_

所以第266行条件成立,最终展开为:

if_changed = @set -e; \
			$(echo-cmd) $(cmd_$(1)); \
			scripts/basic/fixdep $(depfile) $@ '$(make-cmd)' > $(dot-target).tmp; \
			rm -f $(depfile); \
			mv -f $(dot-target).tmp $(dot-target).cmd

$(depfile) 在5-20行定义,最终: depfile = $(dir $@).$(notdir $@).d
$(dot-target) 在5-20行定义,最终: dot-target = $(dir $@).$(notdir $@)

最终:

  1. set -e :在脚本执行过程中,出现任何命令执行失败,脚本立即退出;
  2. $(echo-cmd):将$(cmd_$(1))中的'替换成\'后打印;
  3. $(cmd_$(1)):执行里面的命令;
  4. scripts/basic/fixdep $(depfile) $@ '$(make-cmd)' > $(dot-target).tmp:fixdep工具将实现目标$@所用的命令、源码、头文件等信息全部写入到中间文件 $(depfile) 中,并输出到 $(dot-target).tmp 文件中;
  5. rm -f $(depfile):删除中间文件;
  6. mv -f $(dot-target).tmp $(dot-target).cmd:从输出文件重命名为 $(dot-target).cmd。

if_changed函数(uboot)

作用: 打印和执行cmd_$(1),并将cmd_$@ := cmd_$(1)的内容输入到 $(obj)/.$@.cmd 文件中。
分析:由于在顶层Makefile的386行引用scripts/Kbuild.include, if_changed函数在此文件260行中定义:

5   comma   := ,
14  # Name of target with a '.' as filename prefix. foo/bar.o => foo/.bar.o
15  dot-target = $(dir $@).$(notdir $@)
20  depfile = $(subst $(comma),_,$(dot-target).d)
......
14  # Name of target with a '.' as filename prefix. foo/bar.o => foo/.bar.o
15  dot-target = $(dir $@).$(notdir $@)
......
237	ifneq ($(KBUILD_NOCMDDEP),1)
238	# Check if both arguments are the same including their order. Result is empty
239	# string if equal. User may override this check using make KBUILD_NOCMDDEP=1
240	arg-check = $(filter-out $(subst $(space),$(space_escape),$(strip $(cmd_$@))), \
241							 $(subst $(space),$(space_escape),$(strip $(cmd_$1))))
242	else
243	arg-check = $(if $(strip $(cmd_$@)),,1)
244	endif
......
256	any-prereq = $(filter-out $(PHONY),$?) $(filter-out $(PHONY) $(wildcard $^),$^)
......
260	if_changed = $(if $(strip $(any-prereq) $(arg-check)),                       \
261		@set -e;                                                             \
262		$(echo-cmd) $(cmd_$(1));                                             \
263		printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd, @:)

第260行中$(any-prereq)在第256行中定义,$?依赖文件列表中被改变过的所有文件,$^表示所有的依赖文件,所以$(filter-out $(PHONY) $(wildcard $^),$^)返回的是空字符串。
最终: any-prereq=$? 【依赖文件列表中被改变过的所有文件】
第260行中$(arg-check)在第237-244行中定义,只有在命令行中输入make KBUILD_NOCMDDEP=1时,执行243行,所以这里执行240行,其中的$(space),$(space_escape) 在8-10行定义。
最终: arg-check = 将 $(cmd_$1) 中所有空格替换成 -SPACE- 后的字符串

8  empty  		:=
9  space   		:= $(empty) $(empty)
10 space_escape := _-_SPACE_-_

所以第260行条件成立,最终展开为:

if_changed = @set -e; \
			$(echo-cmd) $(cmd_$(1)); \
			printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd

$(dot-target) 在5-20行定义,最终: dot-target = $(dir $@).$(notdir $@)

最终:

  1. set -e :在脚本执行过程中,出现任何命令执行失败,脚本立即退出;
  2. $(echo-cmd):将$(cmd_$(1))中的'替换成\'后打印;
  3. $(cmd_$(1)):执行里面的命令;
  4. printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd:将 cmd_$@ := cmd_$(1) 信息输出到 $(dot-target).tmp 文件中;

filechk 函数(uboot)

作用: 执行 $(filechk_$(1)) 命令,并将执行后的结果写入 $@ 文件中,最后显示filechk函数内容。
分析:由于在顶层Makefile的386行引用scripts/Kbuild.include, filechk 函数在此文件56行中定义:

36 kecho := :
39 kecho := $($(quiet)kecho)
......
56 define filechk
57 	$(Q)set -e;				\
58 	mkdir -p $(dir $@);			\
59 	$(filechk_$(1)) < $< > $@.tmp;		\
60 	if [ -r $@ ] && cmp -s $@ $@.tmp; then	\
61 		rm -f $@.tmp;			\
62 	else					\
63 		$(kecho) '  UPD     $@';	\
64 		mv -f $@.tmp $@;		\
65	fi
66 endef

57行:set -e 表示在脚本执行过程中,一旦出现任何命令执行失败(返回非零的退出状态码),脚本立即退出。
58行:创建目标所在的目录。
59行:< 表示输入重定向,即从$<(第一个依赖) 文件中读取输入,然后将结果输出到$@.tmp 文件中(没有自动创建)。
60行:cmp -s 用来比较 $@$@.tmp 两个文件是否有差异,如果两个文件完全相同,不输出任何信息,不显示错误信息。
61行:由于60行中$@文件不存在,条件不成立,所以这里不执行。
63行:由36-39行可知,这里为 : ' UPD $@';
64行:将 $@.tmp 重命名为 $@

deprecated 函数(uboot)

作用: (参数4 != 空) && (参数1中没有y),则输出错误信息,否则什么都不做。
分析:deprecated 函数在顶层Makefile的1066行定义:

# 顶层 Makefile
1046    cfg: u-boot.cfg
1053    got    = $(foreach cfg,$(1),$($(cfg)))
1056    expect = $(foreach cfg,$(1),y)
......
1066	define deprecated
1067		@if [ -n "$(strip $(4))" ]; then 
                if [ "$(got)" != "$(expect)" ]; then \
1068			   echo >&2 "===================== WARNING ======================"; \
1069			   echo >&2 "This board does not use $(firstword $(1)) (Driver Model"; \
1070			   echo >&2 "for $(2)). Please update the board to use"; \
1071			   echo >&2 "$(firstword $(1)) before the $(3) release. Failure to"; \
1072			   echo >&2 "update by the deadline may result in board removal."; \
1073			   echo >&2 "See doc/driver-model/migration.rst for more info."; \
1074			   echo >&2 "===================================================="; \
1075		    fi; 
            fi
1076
1077	endef
  1. if [ -n "$(strip $(4))" ]:当参数4的字符串长度大于0时为真(串非空) ;
  2. if [ "$(got)" != "$(expect)" ]:依次取出参数1中的字符串,当参数1中的字符串中没有y则为真;
  3. >&2:将错误输出到文件描述为2的文件,其实是标准错误。
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值