Makefile学习2
Makefile条件判断
使用条件判断,可以让make在编译程序时,根据不同的情况,执行不同的分支:可以执行不同的命令,使用不同的编译参数,生成不同的目标。
ifeq 关键字
ifeq关键字用来判断两个参数是够相等,相等时条件成立为true,不相等为false。
条件判断语句由三个关键字组成:ifeq、else、endif。
ifeq后面的比较语句使用小括号抱起来,ifeq和小括号之间要用空格隔开,小括号里的两个参数用逗号隔开。当小括号里的条件满足时,make就会执行这个分支的命令,否则执行else部分。endif表示一个条件语句的结束。
ifeq一般和变量结合使用:
mode = debug hello: hello.c ifeq ($(mode),debug) @echo "debug mode" gcc -g -o hello hello.c else @echo "release mode" gcc -o hello hello.c endif
ifneq 关键字
ifneq 关键字和ifeq关键字恰恰相反,用来判断参数是否不相等。当比较的参数不相等时,条件语句才成立,值为true,否则为false。
mode = debug hello: hello.c ifneq ($(mode),) @echo "debug mode" gcc -g -o hello hello.c else @echo "release mode" gcc -o hello hello.c endif
在上面的语句中,我们让mode变量和一个空字符串比较,不相等,条件语句成立。
ifdef 关键字
ifdef 关键字用来判断一个变量是否已经定义。如果变量的值非空(在Makefile中,没有定义的变量的值为空),表达式为真。
mode = hello: hello.c ifdef mode @echo "debug mode" gcc -g -o hello hello.c else @echo "release mode" gcc -o hello hello.c endif
如果在Makefile定义一个变量没有赋值,或者没有定义变量,那么这个变量的值都为空。
ifndef 关键字
ifndef关键字和ifdef相反,如果一个变量没有定义,表达式为真。
Makefile函数
GNU make 提供了大量的函数用来处理文件名、变量、文本和命令。通过这些函数,用户可以节省很多精力,编写出更加灵活和健壮的Makefile。
函数的使用和变量引用的展开方式相同:
$(function arguments) ${function arguments}
注意:
- 函数主要分为两类:make内嵌函数和用户自定义函数。对于 GNU make内嵌的函数,直接引用就可以了;对于用户自定义的函数,要通过make的call函数来间接调用。
- 函数和参数列表之间要用空格隔开,多个参数之间使用逗号隔开。
- 如果在参数中引用了变量,变量的引用建议和函数引用使用统一格式:要么是一对小括号,要么是一对大括号。
wildcard函数:如果我们想要获取某个目录下所有的C文件列表,可以使用扩展通配符函数
SRC = $(wildcard *.c) HEAD = $(wildcard *.h) all: @echo "SRC = $(SRC)" @echo "HEAD = $(HEAD)"
用户自定义函数
用户自定义函以define开头,endef结束。
给函数传递的参数在函数中使用( 0 ) 、 (0)、(0)、(1)引用。
用户自定义函数使用call函数间接调用,各个参数之间使用空格隔开。
PHONY: all define func @echo "pram1 = $(0)" @echo "pram2 = $(1)" endef all: $(call func, hello zz.cc)
文本处理函数
GNU make提供了一系列文本处理函数:subst、patsubst、strip、findstring、filter、filer-out、sort、word、wordlist、words、fistword。
subst函数:用来实现字符串的替换,将字符串text中的old替换为new
$(subst old,new,text)
.PHONY: all SRC = $(wildcard *.c) OBJ = $(subst .c,.o,$(SRC)) all: @echo "OBJ = $(OBJ)" @echo $(subst banana, apple, "banana is good, I like banana")
# ls add.c add.h hello.c main.c makefile sub.c sub.h # make OBJ = hello.o main.o add.o sub.o apple is good, I like apple
patsubst函数:主要用来模式替换,使用通配符 % 代表一个单词中的若干字符,在PATTERN和REPLACEMENT如果都包含这个通配符,表示两者表示的是相同的若干个字符,并执行替换操作。
.PHONY: all SRC = $(wildcard *.c) OBJ = $(patsubst %.c, %.o, $(SRC)) all: @echo "OBJ = $(OBJ)"
strip函数:去空格函数,一个字符串通常有多个单词,单词之间使用一个或多个空格进行分割,strip函数用来将多个连续的空字符合并成一个,并去掉字符串开头、末尾的空字符。空字符包括:空格、多个空格、tab等不可显示的字符。
.PHONY: all STR = hello a b c STRIP_STR = $(strip $(STR)) all: @echo "STR = $(STR)" @echo "STRIP_STR = $(STRIP_STR)"
# make STR = hello a b c STRIP_STR = hello a b c
strip函数经常用在条件判断语句的表达式中,去掉多余的空格等因素,确保表达式比较的可靠和健壮。
ifeq ($(strip $(foo)),) echo "foo is empty" endif
findstring函数:用来查找一个字符串,在字符串IN中查找“FIND”字符串,如果找到,则返回字符串FIND,否则,返回空。
$(findstring FIND, IN)
.PHONY: all STR = hello a b c FIND = $(findstring hello, $(STR)) all: @echo "STR = $(STR)" @echo "FIND = $(FIND)"
filter函数:用来过滤掉一个指定的字符串,用来过滤掉字符串TEXT中所有不符合PATTERN模式的单词,只留下符合PATTERN格式的单词。
$(filter PATTERN…,TEXT)
.PHONY: all FILE = a.c b.h c.s d.cpp SRC = $(filter %.c, $(FILE)) all: @echo "FILE = $(FILE)" @echo "SRC = $(SRC)"
filer-out函数:是一个反过滤函数,功能和filter函数恰恰相反:该函数会过滤掉所有符合PATTERN模式的单词,保留所有不符合此模式的单词。
.PHONY: all FILE = a.c b.h c.s d.cpp SRC = $(filter-out %.c, $(FILE)) all: @echo "FILE = $(FILE)" @echo "SRC = $(SRC)"
sort函数:对字符串LIST中的单词以首字母为准进行排序,并删除重复的单词。
.PHONY: all FILE = e.c a.c b.h c.s d.cpp all: @echo "FILE = $(FILE)" @echo $(sort $(FILE))
word函数:从一个字符串TEXT中,按照指定的数目N取单词
$(word N,TEXT)
wordlist函数:用来从一个字符串TEXT中取出从N到M之间的一个单词串
$(wordlist N, M, TEXT)
words函数:用来统计一个字符串TEXT中单词的个数
$(words TEXT)
foreach函数:做一些循环或遍历操作
$(foreach VAR,LIST,TEXT)
把LIST中使用空格分割的单词依次取出并赋值给变量VAR,然后执行TEXT表达式。重复这个过程,直到遍历完LIST中的最后一个单词。函数的返回值是TEXT多次计算的结果。
自动搜索各个目录下的C源文件:
.PHONY: all dirs = lcd usb media keyboard srcs = $(foreach dir, $(dirs), $(wildcard $(dir)/*)) all: @echo "srcs = $(srcs)"
Makefile 通配符
在Makefile中表示一个文件名时,可以使用通配符。
在Makefile中可以使用的通配符有:* 、? 、 […]。通配符的使用方法和含义和在shell中一样。
通配符 | 使用说明 |
* | 匹配0个或者是任意个字符 |
? | 匹配任意一个字符 |
[] | 我们可以指定匹配的字符放在 “[]” 中 |
除此之外,Makefile还有经常使用的几个自动变量也可以看做特殊通配符:
- $@:所有目标文件
- $^:目标依赖的所有文件
- $<:第一个依赖文件
- $?:所有更新过的依赖文件
在Makefile中,通配符主要用在两个场合:
用在规则的目标和依赖中:make在读取Makefile时会自动对其进行匹配处理
test: *.o gcc -o $@ $^ *.o: *.c gcc -c $^
用在规则的命令中:通配符的通配处理在shell执行命令时完成
clean: rm -f *.o
除了以上两种情况,在其他地方都不能直接使用通配符。需要一些函数(如wildcard)来实现。如果想列举当前目录下的所有C文件,可以直接使用wildcard函数:
$(wildcard *.c)