外观
04.条件判断语句、函数定义及调用、变量与函数的综合示例
约 1758 字大约 6 分钟
函数定义及调用变量与函数的综合示例个人条件判断
2022-06-18
第八部分 :条件判断语句
8.1 makefile 中支持条件判断语句
- 可以根据条件的值来决定make的执行
- 可以比较两个不同变量或者变量和常量值
ifxxx (arg1,arg2)
# for ture
else
# for false
endif
- 注意事项
条件判断语句只能用于控制make 实际执行的语句;但是,不能控制规则中命令的执行过程。
8.2 条件判断语句的语法说明
常用形式
- ifxxx(arg1,arg2)
其它合法形式
- ifxxx "arg1" "arg2"
- ifxxx 'arg1' 'arg2'
- ifxxx "arg1" 'arg2'
- Ifxxx 'arg1' "arg2"

- 条件判断关键字

8.3 编程实验:条件判断语句初探
.PHONY : test
var1 := A
var2 := $(var1) b
var3 :=
test:
ifeq ($(var1),$(var2))
@echo "var1 == var2"
else
@echo "var1 != var2"
endif
ifneq ($(var2),)
@echo "var2 is NOT empty"
else
@echo "var2 is empty"
endif
ifdef var2
@echo "var2 is NOT empty"
else
@echo "var2 is empty"
endif
ifndef var3
@echo "var3 is empty"
else
@echo "var3 is NOT empty"
endif
8.4 一些工程经验
- 条件判断语句之前可以有空格,但不能有Tab 字符('\t'),命令前用Tab键。
- 在条件语句中不要使用自动变量($@, ,< )
- 一条完整的条件语句必须位于同一个makefile 中
- 条件判断类似C语言中的宏,预处理阶段有效,执行阶段无效
- make 在加载makefile时
- 首先计算表达式的值(赋值方式不同,计算方式不同)
- 根据判断语句的表达式决定执行的内容
8.5 下面代码的输出相同吗?

不相同,右边的var2在编译阶段就无法确定,是否被赋值
8.6 编程实验:深入make行为
.PHONY : test
var1 :=
var2 := $(var1)
var3 =
var4 = $(var3)
#var3 = 3
test:
ifdef var1
@echo "var1 is defined"
else
@echo "var1 is NOT defined"
endif
ifdef var2
@echo "var2 is defined"
else
@echo "var2 is NOT defined"
endif
ifdef var3
@echo "var3 is defined"
else
@echo "var3 is NOT defined"
endif
ifdef var4
@echo "var4 is defined"
else
@echo "var4 is NOT defined"
endif
8.7 小结
- 条件判断根据条件的值来决定make 的执行
- 条件判断可以比较两个不同变量或者变量和常量值
- 条件判断在预处理阶段有效,执行阶段无效
- 条件判断不能控制规则中命令的执行过程
第九部分 :函数定义及调用
9.1 makefile 中支持函数的概念
- make 解释器提供了一系列的函数供makefile 调用
- 在makefile 中支持自定义函数实现,并调用执行
- 通过define关键字实现自定义函数
9.2 自定义函数的语法
- 函数定义:

- 函数调用:

9.3 深入理解自定义函数
- 自定义函数是一个多行变量,无法直接调用
- 自定义函数是一种过程调用,没有任何的返回值
- 自定义函数用于定义命令集合,并应用于规则中
9.4 编程实验:自定义函数
.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) #call作用下将实参的值替换到对应的位置
new := $(func1)
test :
@echo "new => $(new)"
@echo "var => $(var)" #call的作用只是替换入参变量,并没有执行
$(call func1) #① 将实参的值替换到对应的位置 ② @echo My name is func1
$(call func2, Sumjess, Exp.Joker)
9.5 make解释器中的预定义函数
- make的函数提供了处理文件名,变量和命令的函数
- 可以在需要的地方调用函数来处理指定的参数
- 函数在调用的地方被替换为处理结果
9.6 预定义函数的调用

9.7 问题:为什么自定义函数和预定义函数的调用形式完全不同?
9.8 本质剖析
- makefile 中不支持真正意义上的自定义函数
- 自定义函数的本质是多行变量
- 预定义的call函数在调用时将参数传递给多行变量
- 自定义函数是call函数的实参,并在call中被执行
9.9 编程实验:函数剖析
.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 makefile)
test :
@echo "var1 => $(var1)"
@echo "var2 => $(var2)"
@echo "var3 => $(var3)"
@echo "var4 => $(var4)"
9.10 小结
- make解释器提供了一系列的函数供makefile调用
- 自定义函数是一个多行变量,无法直接调用
- 自定义函数用于定义命令集合,并应用于规则中
- 预定义的call函数在调用时将参数传递给多行变量
- 自定义函数是call函数的实参,并在call中被执行
第十部分 :变量与函数的综合示例
10.1 实战需求
- 自动生成target 文件夹存放可执行文件
- 自动生成objs 文件夹存放编译生成的目标文件( *.o )
- 支持调试版本的编译选项
- 考虑代码的扩展性
10.2 工具原料
$(wildcard _pattern)
- 获取当前工作目录中满足_pattern的文件或目录列表
$(addprefix _prefix,_names)
- 给名字列表_names中的每一个名字增加前缀_prefix
10.3 关键技巧
自动获取当前目录下的源文件列表(函数调用)
- SRCS := $(wildcard *.c)
根据源文件列表生成目标文件列表(变量的值替换)
- OBJS := $( SRCS: .c=.o)
对每一个目标文件列表加上路径前缀(函数调用)
- OBJS := $( addprefix path/ , $(OBJS ) )
10.4 规则中的模式替换(目录结构)
当前工作目录下逐个对工作目录中的文件进行,与6.4相对应.

10.5 编译规则的依赖

10.6 编程实验:综合示例
CC := gcc
MKDIR := mkdir
RM := rm -fr
DIR_OBJS := objs
DIR_TARGET := target
DIRS := $(DIR_OBJS) $(DIR_TARGET)
TARGET := $(DIR_TARGET)/hello-makefile.out
# main.c const.c func.c
SRCS := $(wildcard *.c)
# main.o const.o func.o
OBJS := $(SRCS:.c=.o)
# objs/main.o objs/const.o objs/func.o
OBJS := $(addprefix $(DIR_OBJS)/, $(OBJS))
.PHONY : rebuild clean all
$(TARGET) : $(DIRS) $(OBJS)
$(CC) -o $@ $(OBJS)
@echo "Target File ==> $@"
$(DIRS) :
$(MKDIR) $@
$(DIR_OBJS)/%.o : %.c
ifeq ($(DEBUG),true)
$(CC) -o $@ -g -c $^ #生成调试信息。GNU 调试器可利用该信息。
else
$(CC) -o $@ -c $^
endif
rebuild : clean all
all : $(TARGET)
clean :
$(RM) $(DIRS)

反编译:objdump -S hello-makefile.out
上为生成调试信息,下为不生成调试信息


10.7 小结
- 目录可以成为目标的依赖,在规则中创建目录
- 预定义函数是makefile 实战时不可或缺的部分
- 规则中的模式匹配可以直接针对目录中的文件
- 可以使用命令行变量编译特殊的目标版本
