函数

makefile 中支持函数的概念

  • make 解释器提供了一系列的函数供 makefile 调用
  • 在 makefile 中支持自定义函数实现,并调用执行
  • 通过 define 关键字实现自定义函数

自定义函数语法

zidingyihanshuyufa

$(0) 表示这个函数的第 0 个参数;即这个函数的名字

$(1) 表示i这个函数的第 1 个参数;即 func2 调用时候,后面跟着的第一个参数

深入理解自定义函数

  • 自定义函数是一个多行变量,无法直接调用
  • 自定义函数是一种过程调用,没有任何返回值
  • 自定义函数用于定义命令集合,并应用于规则中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 示例
.PHONY : test

define func1
@echo "My name is $(0)"
endef

define func2
@echo "My name is $(0)"
@echo "Param 1 => $(1)"
@echo "Param 2 => $(2)"
endef

var := $(call func1)
new := $(func1)

test :
@echo "new => $(new)" # new => @echo "My name is"
@echo "var => $(var)" # var => @echo "My name is func1"
$(call func1) # My name is func1
$(call func2, D.T.Software, delphi_tang)
# My name is func2
# Param 1 => D.T.Software
# Param 2 => delphi_tang

为什么 new => @echo “My name is、var => @echo “My name is func1?

是因为define 关键字是用来定义多行变量的,只不过 call 关键字将它(func1、func2)当作了一个自定义函数进行使用;当这个使用不在规则中的时候,make 解释器就将他当成了一个变量来进行使用,所以输出的是命令的内容;

而为什么 var 多了一个 func1 呢?是因为 call 关键字将实参替换到函数体当中对应的位置;

由上述执行结果可以看出

define 关键字是用来定义多行变量的,只不过在 call 关键字的作用下被当作了一个自定义函数进行使用;只不过这个使用是有限制的,只有在规则中才可以进行使用。

预定义函数

make 解释器中的预定义函数

  • make 的函数提供了处理文件名,变量和命令的函数
  • 可以在需要的地方调用函数来处理指定的参数
  • 函数在调用的地方被替换为处理结果

预定义函数的调用

yudingyihanshudiaoyong

为什么自定义函数与预定义函数的调用形式完全不同?

  • makefile 中不支持真正意义上的自定义函数,自定义函数的本质是多行变量
  • 预定义的 call 函数在调用时将参数传递给多行变量
  • 自定义函数是 call 函数的实参,并在 call 中被执行

call 函数就是将参数传递给多行变量,是用来处理参数值的;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 示例1
.PHONY: test

define func1
@echo "My name is $(0)"
endef

func2 := @echo "My name is $(0)"

test:
$(call func1)
$(call func2)

# make
# My name is func1
# My name is

func1 是个多行变量,使用时 call 将参数传递给了多行变量;

func2 是个普通变量,call 无法处理普通变量,所以这里 $(0) 是空值;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 示例2
.PHONY: test

define func1
@echo "My name is $(0)"
endef

define func2
@echo "My name is $(0)"
endef

var1 := $(call func1)
var2 := $(call func2)
var3 := $(abspath ./)
var4 := $(abspath tst.app)


test:
@echo "var1 => $(var1)"
@echo "var2 => $(var2)"
@echo "var3 => $(var3)"
@echo "var4 => $(var4)"

# make
# var1 => @echo "My name is func1"
# var2 => @echo "My name is func2"
# var3 => /hom/kay
# var4 => /hom/kay/tst.app

小结

  • make 解释器提供了一系列的函数供 makefile 调用
  • 自定义函数是一个多行变量,无法直接调用
  • 自定义函数用于定义命令集合,并应用于规则中
  • 预定义的 call 函数在调用时将参数传递给多行变量
  • 自定义函数是 call 函数的实参,并在 call 中被执行

变量与函数的综合示例

实战需求

  • 自动生成 target 文件夹存放可执行文件
  • 自动生成 objs 文件夹存放编译生成的目标文件(*.o)
  • 支持调试版本的编译选项
  • 考虑代码的扩展性

工具原料

  • $(wildcard_pattern)
    • 获取当前工作目录中满足 _pattern 的文件或者目录列表
  • $(addprefix _prefix,_names)
    • 给名字列表 _names 中每一个名字增加前缀 _prefix

技巧

  1. 自动获取当前目录下的源文件列表(函数调用)
    • SRCS := $(wildcard *.c)
  2. 根据源文件列表生成目标文件列表(文件的值替换)
    • OBJS := $(SRCS:.c=.o)
  3. 对每一个目标文件列表加上路径前缀(函数调用)
    • OBJS := $(addprefix path/, $(OBJS))

规则中的模式替换(目录结构)

guizezhongdemoshitihuan