关于 kernel Makefile 中的技巧
MAKECMDGOALS 变量
MAKECMDGOALS 是 make 内置变量, 表示用户输入的目标合集, 例如
default:
@echo $(MAKECMDGOALS)
demo:
@echo ok
执行
$ make default demo
default demo
ok
MAKEFLAGS 变量
MAKEFLAGS 是 make 本身的参数设置项, 通过make --help 可以看到所有可用选项, 当用户执行 make -(options), options 便会传给 MAKEFLAGS, 例如
# 也可以在文件内直接设置
MAKEFLAGS += -r
all:
@echo $(MAKEFLAGS)
执行
$ make all -s
sr
MAKEFLAGS 值为 sr, s 是命令行给出, r 是在文件中给出
伪目标
伪目标指不产生实际文件的目标, .PHONY
可用来指明哪些目标是伪目标.
作用1:
作用2: PHONY可以确保源文件(*.c *.h)修改后,对应的目标文件会被重建。倘若缺少了PHONY,可以看到情况会很糟。
PHONY += all
all:
echo all
PHONY += clean
clean:
echo clean
.PHONY: $(PHONY)
变量展开
定义一个变量 cmd = xxx, 然后使用 $(cmd) 进行引用, 变量展开后变成字符串再对外层引用进行展开, 直到展开所有引用, 然后执行, 例如:
cmd = echo hello
all:
$(cmd)
很显然上面会输出 hello, 因为引用 cmd 后, cmd 被展开 --> echo hello, 实际上就相当于执行一次 echo hello, 所以结果是 hello
cmd = echo hello
mycmd = $(shell echo $(cmd))
all:
$(mycmd)
- 先展开内部
$(cmd)
-->$(shell echo echo hello)
- 再展开
shell
函数部分 -->mycmd = echo hello
- 最后展开
$(mycmd)
-->echo hello
所以最后输出是 hello
call 函数
call 函数可以在引用变量时传入参数
cmd = echo $(1)
all
$(call cmd,hello)
执行 call 后, cmd 被引用, 而 $(1)
是对第一个参数的引用, 展开有变成 hello, 所以最后展开后变成 echo hello, 输出 hello
- 组合变量
利用 call 函数的引用传参特性可以实现对变量的灵活引用
调用 call 函数后, cmd 变量被展开成 -->cmd = $(cmd_$(1)) cmd_hello = echo hello all: $(call cmd,hello)
$(cmd_hello)
--> 再展开后变成 echo hello, 于是输出 hello - 显示调用命令
编译时有时需要显示调用的命令详情, 但有时又需要简洁模式. 这就需要能在每一行命令调用时自定义显示内容. 下面的echo-cmd
正是用于此目的.-
echo-cmd
会将当前执行的命令按用户自定义的方式进行回显 - 用户需要定义两个版本命令, 一个是实际命令, 一个是该命令调用时的自定义显示
- 当 quiet 变量不为空时表示回显的是自定义显示的内容, 当 quiet 为空时, 则回显当前执行的命令详情;
quiet = quiet_ echo-cmd = echo ' $($(quiet)cmd_$(1))' cmd = @$(echo-cmd); $(cmd_$(1)) # 定义两个命令, 一个是实际命令, 一个是该命令调用时的自定义显示 cmd_hello = echo hello quiet_cmd_hello = command runing all: $(call cmd,hello)
cmd = @$(echo-cmd); $(cmd_$(1))
一行其实是包含了两部分, 前面部分负责回显, 用来给用户提示, 后面部分则是命令执行本身, @ 符号有效的屏蔽了 make 对命令展开后的显示, 最后显示的内容就只要自定义的echo-cmd
了. 执行后- 如果
quiet = quiet_
则回显提示command runing
, 而后台在默默执行cmd_hello
即输出hello
- 如果
quiet
未定义或为空, 则回显提示echo hello
即命令本身, 并且命令在后台正确执行, 输出hello
-
完整版
# Beautify output
# ---------------------------------------------------------------------------
#
# Normally, we echo the whole command before executing it. By making
# that echo $($(quiet)$(cmd)), we now have the possibility to set
# $(quiet) to choose other forms of output instead, e.g.
#
# quiet_cmd_cc_o_c = Compiling $(RELDIR)/$@
# cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<
#
# If $(quiet) is empty, the whole command will be printed.
# If it is set to "quiet_", only the short version will be printed.
# If it is set to "silent_", nothing will be printed at all, since
# the variable $(silent_cmd_cc_o_c) doesn't exist.
#
# A simple variant is to prefix commands with $(Q) - that's useful
# for commands that shall be hidden in non-verbose mode.
#
# $(Q)ln $@ :<
#
# If KBUILD_VERBOSE equals 0 then the above command will be hidden.
# If KBUILD_VERBOSE equals 1 then the above command is displayed.
# If KBUILD_VERBOSE equals 2 then give the reason why each target is rebuilt.
#
# To put more focus on warnings, be less verbose as default
# Use 'make V=1' to see the full commands
ifeq ("$(origin V)", "command line")
KBUILD_VERBOSE = $(V)
endif
ifndef KBUILD_VERBOSE
KBUILD_VERBOSE = 0
endif
ifeq ($(KBUILD_VERBOSE),1)
quiet =
Q =
else
quiet=quiet_
Q = @
endif
# If the user is running make -s (silent mode), suppress echoing of
# commands
ifneq ($(findstring s,$(filter-out --%,$(MAKEFLAGS))),)
quiet=silent_
KBUILD_VERBOSE = 0
endif
export quiet Q KBUILD_VERBOSE
# -----------------------------------------------------
# include 部分
squote := '
# 转义单引号以在 echo 语句中使用
escsq = $(subst $(squote),'\$(squote)',$1)
# 命令执行时回显
# 如果有自定义回显内容 $(quiet)cmd_$(1), 则执行回显
echo-cmd = $(if $($(quiet)cmd_$(1)),\
echo ' $(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';)
# sink stdout for 'make -s'
redirect :=
quiet_redirect :=
silent_redirect := exec >/dev/null;
# 执行一个命令
# 通过 $(call cmd, name) 来执行, 它会根据需要将命令回显,同时执行实际命令 cmd_name
cmd = @set -e; $(echo-cmd) $($(quiet)redirect) $(cmd_$(1))
# why - 告诉 User 为何该目标需要进行构建
# 当 V=2 时才显示
ifeq ($(KBUILD_VERBOSE),2)
why = $(if $(0), \
- 'due to something' \
)
endif
echo-why = $(call escsq, $(strip $(why)))
# -----------------------------------------------------
# 定义两个命令, 一个是实际命令, 一个是该命令调用时的自定义显示
quiet_cmd_hello = GEN $@
cmd_hello = echo hello
all: tar1
$(call cmd,hello)
tar1:
$(Q)echo "tar1"
网友评论