Makefile教程 7-10
Makefile教程7:变量
这一章节的内容,基本在makefile教程:变量部分都介绍过了。
Makefile教程8:变量,条件判断
环境变量
这个本意很简单,就是可以读取操作系统的环境变量,比如:
.PHONY:
debug:
env=1;export env;echo $(env)
;
的这个用法见makefile之命令之间的关联
这里就是定义了一个变量env
,并且将其设置为环境变量:export env
,这部分属于操作系统的知识,和makefile无关。
之后就是在makefile中读取:echo $(env)
读取操作系统中定义的环境变量。
在编译的过程中,可以使用参数-e
来指定环境变量,比如还是上面的makefile,在运行时:
make -e env=2 debug
就是可以覆盖掉系统中的环境变量。
目标变量
这个玩意本意很简单,先回顾一下makefile中命令的基本格式:makefile基础
target ... : prerequisites ...
command
其中,如果我们想定义一些变量,仅仅在这个target
中生效,就可以采用这个,比如下面的例子,注意看其中的注释:
.PHONY:
# 这个变量仅仅在 debug 中生效
debug: cmd = pwd
# 这个变量仅仅在 debug2 中生效
debug2: cmd = whoami
debug:
$(cmd)
debug2:
$(cmd)
所以运行make debug
的时候,真正执行的是pwd
,运行make debug2
的时候,真正执行的是whoami
。
模式变量
这个也很简单,就是如果有一些变量我们想放在多个目标变量里,就可以使用这个,比如:
.PHONY:
# 模式变量,顾名思义,它自己本身就是目标变量中的变量
de%: cmd = whoami
debug:
$(cmd)
debug2:
$(cmd)
其中debug
和debug2
都可以使用这个变量。
条件判断
这个很简单,就是在makefile中增加条件判断,比如下面这个例子:
example = hello
# 注意,ifeq 后面一定要空一格,否则会报错
ifeq ($(example),hello)
output=world
else
output=makefile
endif
.PHONY:
debug:
@echo "$(example) $(output)"
条件判断的格式是:
<conditional-directive>
<text-if-true>
else
<text-if-false>
endif
其中重点是<conditional-directive>
这一部分,可以使用的关键字有:
- ifeq / if equal
- ifneq / if not equal
- ifdef / if define
- ifndef / if not define
首先是比较两个值是否相同,格式如下:
ifneq (<arg1>, <arg2>)
ifneq '<arg1>' '<arg2>'
ifneq "<arg1>" "<arg2>"
ifneq "<arg1>" '<arg2>'
ifneq '<arg1>' "<arg2>"
也可以像这样,直接根据第一个值是否存在来进行判断
ifeq (ifTrue,)
比如上面的例子:
# 这里假设我们使用了一个未定义的变量
# example = hello
ifeq ($(example),)
# 条件满足,进入这种情况
output=world
else
output=makefile
endif
.PHONY:
debug:
@echo "$(example) $(output)"
接下来就是判断变量是否定义:
ifdef <variable-name>
makefile教程9:makefile函数
这里好像主要就是介绍makefile支持的函数。
首先是函数的调用方法:
$(<function> <arguments>)
$(函数名 变量1,变量2,变量3)
下面如果有数字参数的话,不允许小于0。
下面是字符串相关的函数。
字符串替换函数:subst
$(subst <from>,<to>,<text>)
模式字符串替换函数:patsubst
$(patsubst <pattern>,<replacement>,<text>)
所谓“模式”,就是可以模糊搜索的效果,比如%
就代表1到多个字符串。
去掉空格:strip
$(strip <string>)
去掉字串中开头和结尾的空字符。
判断是否包含某字符串:findstring
$(findstring <find>,<in>)
如果在in
中找到find
字符串,则返回find
,否则就返回空字符串。
过滤函数:filter
$(filter <pattern...>,<text>)
在text
中筛选符合pattern
的值
反过滤函数:filter-out
$(filter-out <pattern...>,<text>)
跟filter
操作相同,结果不同,filter
是符合pattern
的值输出,filter-out
则是不符合pattern
的值输出。
排序函数:sort
$(sort <list>)
对list
中的值进行排序。排序规则是特殊字符,数字,大写字母,小写字母。
获取字符中的第n个单词数:word
$(word <n>,<text>)
获取text
中的第n
个值。比如$(word 2, foo bar baz)
就是bar
。如果超过设置的值,则返回为空。
统计单词中的子单词数量:wordlist
$(wordlist <s>,<e>,<text>)
$(wordlist 2, 3, foo bar baz)
返回值就是bar baz
。
统计单词数:words
$(words <text>)
比如$(words, foo bar baz)
的值就是3。
获取首个单词数:firstword
$(firstword <text>)
比如$(firstword foo bar)
的值就是foo
。
下面就是一些例子:
.PHONY:
debug:
@echo $(subst world,makefile,hello world)
# hello makefile
@echo $(patsubst %hello,say hello,hello again)
# say again
@echo $(strip without Empty )
# without Empty
@echo $(findstring php,php is the best language)
# php
@echo $(filter makefile%,makefile1 makefile2 makefile3 1.c 2.c)
# makefile1 makefile2 makefile3
@echo $(filter-out makefile%,makefile1 makefile2 makefile3 1.c 2.c)
# 1.c 2.c
@echo $(sort 1 2 3 a b c A B , %)
# % , 1 2 3 A B a b c
@echo $(word 2,a b c)
# b
@echo $(wordlist 1,3,a b c d e f)
# a b c
@echo $(words a b c d e f)
# 6
@echo $(firstword a b c d e f)
# a
文件相关函数。
获取目录值:dir
$(dir <names...>)
就是获取names
中的目录部分。比如$(dir ./main.c ./src/function.c)
就是./ ./src/
。
获取文件名:notdir
$(notdir <names...>)
就是获取上面部分中的文件部分。比如$(notdir ./main.c ./src/function.c)
就是main.c function.c
。
获取非文件后缀部分:basename
$(basename <names...>)
就是将names
中的文件非后缀部分,比如$(basename ./main.c ./src/function.c)
就是./main ./src/function
。
增加文件后缀:addsuffix
$(addsuffix <suffix>,<names...>)
就是增加文件后缀。比如$(addsuffix .c,1 2 3)
,输出就是1.c 2.c 3.c
。
增加文件前缀:addprefix
$(addprefix <prefix>,<names...>)
跟上面类似,就是增加文件前缀,比如$(addprefix ./,1.c 2.c 3.c)
,输出./1.c ./2.c ./3.c
。
拼接字符串:join
$(join <list1>,<list2>)
这个list2
会尽量贴近list1
,比如list1
比list2
多,那么没有list2
链接的list1
就会维持原样。
同样,如果list2
比list1
多,那么没有list1
链接的list2
就会维持原样。
下面就是一些例子:
.PHONY:
debug:
@echo $(dir ./main.c ./src/function.c)
# ./ ./src
@echo $(notdir ./main.c ./src/function.c)
# main.c function.c
@echo $(basename ./main.c ./src/function.c)
# ./main ./src/function
@echo $(addsuffix .c,1 2 3)
# 1.c 2.c 3.c
@echo $(addprefix ./,1.c 2.c 3.c)
# ./1.c ./2.c ./3.c
@echo $(join ./,1 2)
# ./1 2
@echo $(join ./ ./src/,1)
# ./1 ./src/
@echo $(join ./ ./src/,1 2)
# ./1 ./src/2
Makefile10:函数
循环函数:foreach
$(foreach <var>,<list>,<text>)
这个参数的变量解释:
- list:定义待处理的数据
- var:定义每次处理的数据的变量名
- text:处理函数
条件判断:if
$(if <condition>,<then-part>)
或者
$(if <condition>,<then-part>,<else-part>)
这个就是if else
的结构。
自定义函数:call
$(call <expression>,<parm1>,<parm2>,<parm3>...)
获取变量的出处:origin
$(origin <variable>)
首先就是<variable>
中不能加上$(variable)
,而仅仅是variable
就可以。
其次,可能的返回值有:
- undefined:未定义
- default:makefile内部定义的变量
- enviroment:环境变量,export内容见这里
- file:定义在当前makefile中
- command line:命令行定义的,见下面这个例子。
这里分享一下直接拿Linux中的环境变量例子:
.PHONY:
debug:
debug="hello world" && export debug && echo $(debug)
debug="hello world"
就是定义一个变量。
export debug
就是定义一个操作系统的环境变量。
echo $(debug)
就是调用环境变量。
&&
中的内容见这里:命令的关联
- override:使用
override
重新定义的。
override
的简单作用就是可以覆盖之前定义的变量,比如下面定义的变量:
override debug="hello again"
.PHONY:
debug:
debug="hello world" && export debug && echo $(debug)
- automatic:自动化变量。
自动变量就是类似$@,@<这样的变量,更多的变量说明在后面还会讲。
调用 shell 函数
$(shell shellFunction param)
就是$(shell shell函数 参数)
。
make控制函数
-
产生一个致命错误:
$(error <text ...>)
-
产生一个警告:
$(warning <text ...>)
下面是一个例子:
list=1 2 3 4
files=$(foreach item,$(list),$(item).c)
empty=
hasFile=$(if $(empty),yes)
hasCFile=$(if $(files),yes,no)
privateFunction=$(words $(1))
listNumber=$(call privateFunction,$(list))
.PHONY:
debug:
@echo $(list)
# 1 2 3 4
@echo $(files)
# 1.c 2.c 3.c 4.c
@echo $(hasFile)
#
@echo $(hasCFile)
# yes
@echo $(listNumber)
# 4
@echo $(origin privateFunction)
# file
@echo $(shell pwd)
#
error:
# 这里是直接停止,不会首先运行 @echo $(shell whoami) 的部分
@echo $(shell whoami)
$(error 停止)
warn:
# 这里是先运行 makefile:28: 警告
# 接下来再运行一块一块的命令
@echo $(shell whoami)
$(warning 警告)
@echo $(shell whereis make)