make/Makefile学习之三Makefile文件中各类函数的使用
说明
本小节所有实例主要采用Linux-Kernel-4.13中的首Makefie源码片断,未采用部分,在案例中备注了源码出处
实现中Makefile文件路径为:/opt/linux-kernel/linux-kernel-4.13/linux-4.13
一、文件名操作函数
1.1、dir取目录函数
1、语法:$(dir <'string>)
2、功能:根据字符串(或变量)返回对应的目录名
3、举例:
# $(wildcard <path/*.*>)
# 功能:
匹配路径path下所有的某类文件,如path/*_defconfig,表示匹配所以_defconfig结尾的文件
# $(dir <pathname>)
# 功能:
# 根据函数wildcard返回值,取目录名
board-dirs := $(dir $(wildcard $(srctree)/arch/$(SRCARCH)/configs/*/*_defconfig))
# board-dirs 值为:$(srctree)/arch/$(SRCARCH)/configs/*/ 注:变量srctree和SRCARCH为之前定义好的,*为通配文件夹名
1.2、notdir取文件名函数
1、语法:$(notdir <'string>)
2、功能:根据字符串(或变量)返回文件名
3、举例:
# $(wildcard $(srctree)/arch/$(SRCARCH)/configs/*_defconfig)
# 功能:返回$(srctree)/arch/$(SRCARCH)/configs/目录下所有以_deconfig结尾的文件名及路径
# 并将返回值赋值组boards变量
# $(notdir $(boards))
# 功能:根据boards变量的,得到对应的文件名
# $(sort ...)
# 功能:对获取到的文件名排序,并将排序后的文件名做为值赋值给boards变量
boards := $(wildcard $(srctree)/arch/$(SRCARCH)/configs/*_defconfig)
boards := $(sort $(notdir $(boards)))
1.3、suffix取后缀函数
1、语法:$(suffix<'string>)
2、功能:根据字符串(或变量)返回一个后缀(扩展名)
3、举例:
#因linux kernel 4.13中没有使用到当前函数,故自行举例
# FILEPATH 变量值保存了4个文件名
# $(suffix ...)
# 功能:对FILEPATH变量值取后缀,并返回组变量file_suffix
FILEPATH ?= /usr/src/linux-headers-5.4.0-45/Kconfig drivers/i2c/i2c-core.h Makefile.bak Makefile
file_suffix :=$(suffix $(FILEPATH))
all :
@echo $(file_suffix)
1.4、basename取前缀函数
1、语法:$(basename <'string>)
2、功能:根据字符串(或变量)返回前缀
3、举例:
# 源码位置:arch/powerpc/boot/Makefile
# src-wlib变量和src-plat变量值保存了更多源文件,没有一一列出,可通过源码查看
# $(addprefix argv1 , argv2)
# 功能:为变量argv2增加前缀argv1,即在这里是为:文件名加路径前将值返回给变量src-boot
# $(basename ...)
# 功能:返回变量src-boot值中各元素的前缀
# $(addsuffix argv1, argv2)
# 功能:为变量argv2添加后缀argv1,即:在这里是将$(basename ...)的返回值中各元素加一个后缀,得到的新值,返回给obj-boot变量
#........省略更多....................
src-boot := $(src-wlib) $(src-plat) empty.c
src-boot := $(addprefix $(obj)/, $(src-boot))
obj-boot := $(addsuffix .o, $(basename $(src-boot)))
1.5、addsuffix加后缀函数
1、语法:$(addsuffix <'argv1> , <'string>)
2、功能:为变量string各元素增加后缀argv1,将增加后缀后的值返回
3、举例:
见 1.4举例
1.6、addprefix加后缀函数
1、语法:$(addprefix <'argv1> , <'string>)
2、功能:为变量string各元素增加前缀argv1,将增加前缀后的值返回
3、举例:
见 1.4举例
1.7、join加后缀函数
1、语法:$(join <'argv1> , )
2、功能:为变量string各元素增加前缀argv1,将增加前缀后的值返回
3、举例:
# 因linux kernel 4.13中Makefile文件没有使用到此函数,以下代码为自行编写
# $(join argv1,argv2)
# 功能:将argv1和argv2中各元素一一连接组成新的值并返回
# 注:如argv1和argv2数量不匹配,用空匹配
# Makefile start
FILE_a := pstored.conf pstore sda
PATH_a := /etc/systemd/ /ect/systemd/ /dev/
FILE_b := pstored.conf pstore
PATH_b := /etc/systemd/
FILE_c := pstored.conf pstore
PATH_c := /etc/systemd/ /ect/systemd/ /dev/
all :
@echo $(join $(PATH_a),$(FILE_a))
@echo $(join $(PATH_b),$(FILE_b))
@echo $(join $(PATH_c),$(FILE_c))
# Makefile end
#执行结果如下:
$ make
/etc/systemd/pstored.conf /ect/systemd/pstore /dev/sda
/etc/systemd/pstored.conf pstore
/etc/systemd/pstored.conf /ect/systemd/pstore /dev/
二、foreach遍历函数
1、语法:$(foreach <'tmp_var> , <'list> , <'text>)
参数说明:
tmp_var :临时变量,生命周期仅到foreach函数运行结束,
主要用于存储每次遍历list变量的得到的值。
list : 一个变量的列表
text : 一个用于保存tmp_var值的列表
2、功能:遍历列表list中的每一个值,一一存入tmp_var临时变量中,
text变量保存对tmp_var变量的操作方法
3、举例:
见 三、if函数举例
三、if条件判断函数
1、语法:$(if <条件> , <执行语句1>) 或
$(if <条件> , <执行语句1> , <执行语句2>)
2、功能:如果条件成立,执行条件1,否则执行条件2
3、举例:
# $(if $(boards) ... , ...)
# 判断变量boards是否有值,如果有值执行$(foreach ... , ...)语句
# 如果没有值,执行: echo ''
# $(foreach ... , ...)
# 当board变量有值是,foreach函数依次遍历board变量中的元素,并保存于临时变量b中,
# printf()函数格式化变量b后,进行打印
# printf()函数 :
# %-24s < --- > $(b) 将临时变量b左对齐,24字符输出
# %s < --- > $(subst _defconfig,,$(b) 将变量b中的_defconfig替换为空,并返回,格式化为字符串输出
@$(if $(boards), \
$(foreach b, $(boards), \
printf " %-24s - Build for %s\\n" $(b) $(subst _defconfig,,$(b));) \
echo '')
四、call自定义函数
1、语法:$(call <用户自定义表达式> , , , …)
2、功能 : 用户事先定义一个表达,当调用call函数时,会自动执行用户自定义的表达式,
并将参数argv1 … … 传递给用户自定义的表达式。
3、举例:
# $(call cmd,rmdirs)函数分析
# cmd
# cmd自定义表达式的定义在源文件scripts/Kbuild.include ,源码通过include导入
# cmd = @$(echo-cmd) $(cmd_$(1))
# 变量echo-cmd在scripts/Kbuild.include有定义,详见下源码。
# 变量cmd_$(1) 展开后为:cmd_rmdirs
# 通过以下分析,自定义表达式$(call cmd,rmdirs)函数等同于:
# cmd_rmdirs = rm -rf $(rm-dirs)
# $(if $($(quiet)cmd_$(1)),\ #这里展开应为:if(cmd_rmdir , 或if( quiet_cmd_rmdir,
# echo ' $(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';)
#
include scripts/Kbuild.include
#..........省略更多...............
#以下为变量相关的定义源码
ifeq ($(KBUILD_VERBOSE),1)
quiet =
Q =
else
quiet=quiet_
Q = @
endif
quiet_cmd_rmdirs = $(if $(wildcard $(rm-dirs)),CLEAN $(wildcard $(rm-dirs)))
cmd_rmdirs = rm -rf $(rm-dirs)
quiet_cmd_rmfiles = $(if $(wildcard $(rm-files)),CLEAN $(wildcard $(rm-files)))
cmd_rmfiles = rm -f $(rm-files)
#.........省略更多,以下为call函数使用的源码.......................
clean: $(clean-dirs) #
$(call cmd,rmdirs)
$(call cmd,rmfiles)
#源码位置 :scripts/Kbuild.include
echo-cmd = $(if $($(quiet)cmd_$(1)),\
echo ' $(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';)
cmd = @$(echo-cmd) $(cmd_$(1))
五、origin变量定义信息函数
1、语法:$(origin )
2、功能 : 返回变量的状态
undefined : 如果变量var没有定义,origini函数返回 undefined;
default : 如果变量var的值是一个make工具默认的值,返回default
environment : 如果变量var的值是一个环境变量,返回environment
file: 如果变量var的值定义在makefile文件中,返回file
command line : 如果变量var的值在命令行中定义,返回command line
override : 如果变量var的值被override指示符重新定义,则返回override
automatic : 如果变量var的值是一个命令运行中的自动化变量,则返回automatic
3、举例:
# $(origin M)
# 返回变量M的定义类型
# 当M为命令行定义值的时候,向下执行
ifeq ("$(origin M)", "command line")
KBUILD_EXTMOD := $(M)
endif
六、shell函数
1、语法:$(shell <shell_cmd> , …)
2、功能 : 执行一个shell命令
3、举例
# ifneq(...)
# 当变量KBUILD_OUTPUT值不为空时,向下执行
# $(shell ...)
# 执行mkdir -p $(KBUILD_OUTPUT) 命令
# 执行cd $(KBUILD_OUTPUT) 命令
# 执行 /bin/pwd 命令
ifneq ($(KBUILD_OUTPUT),)
# check that the output directory actually exists
saved-output := $(KBUILD_OUTPUT)
KBUILD_OUTPUT := $(shell mkdir -p $(KBUILD_OUTPUT) && cd $(KBUILD_OUTPUT) \
&& /bin/pwd)