Makefile学习2

2023-10-17 18:02:49 浏览数 (1)

Makefile学习2

Makefile条件判断

使用条件判断,可以让make在编译程序时,根据不同的情况,执行不同的分支:可以执行不同的命令,使用不同的编译参数,生成不同的目标。

ifeq 关键字

ifeq关键字用来判断两个参数是够相等,相等时条件成立为true,不相等为false。

条件判断语句由三个关键字组成:ifeq、else、endif。

ifeq后面的比较语句使用小括号抱起来,ifeq和小括号之间要用空格隔开,小括号里的两个参数用逗号隔开。当小括号里的条件满足时,make就会执行这个分支的命令,否则执行else部分。endif表示一个条件语句的结束。

ifeq一般和变量结合使用:

代码语言:javascript复制
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。

代码语言:javascript复制
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中,没有定义的变量的值为空),表达式为真。

代码语言:javascript复制
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。

函数的使用和变量引用的展开方式相同:

代码语言:javascript复制
$(function arguments)
${function arguments}

注意:

  • 函数主要分为两类:make内嵌函数和用户自定义函数。对于 GNU make内嵌的函数,直接引用就可以了;对于用户自定义的函数,要通过make的call函数来间接调用。
  • 函数和参数列表之间要用空格隔开,多个参数之间使用逗号隔开。
  • 如果在参数中引用了变量,变量的引用建议和函数引用使用统一格式:要么是一对小括号,要么是一对大括号。

wildcard函数:如果我们想要获取某个目录下所有的C文件列表,可以使用扩展通配符函数

代码语言:javascript复制
SRC  = $(wildcard *.c)
HEAD = $(wildcard *.h)
all:
    @echo "SRC = $(SRC)"
    @echo "HEAD = $(HEAD)"
用户自定义函数

用户自定义函以define开头,endef结束。

给函数传递的参数在函数中使用

(0)、

(1)引用。

用户自定义函数使用call函数间接调用,各个参数之间使用空格隔开。

代码语言:javascript复制
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

代码语言:javascript复制
$(subst old,new,text)
代码语言:javascript复制
.PHONY: all
SRC  = $(wildcard *.c)
OBJ  = $(subst .c,.o,$(SRC))
all:
    @echo "OBJ = $(OBJ)"
    @echo $(subst banana, apple, "banana is good, I like banana")
代码语言:javascript复制
# 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如果都包含这个通配符,表示两者表示的是相同的若干个字符,并执行替换操作。

代码语言:javascript复制
.PHONY: all
SRC  = $(wildcard *.c)
OBJ  = $(patsubst %.c, %.o, $(SRC))
all:
    @echo "OBJ = $(OBJ)"

strip函数:去空格函数,一个字符串通常有多个单词,单词之间使用一个或多个空格进行分割,strip函数用来将多个连续的空字符合并成一个,并去掉字符串开头、末尾的空字符。空字符包括:空格、多个空格、tab等不可显示的字符。

代码语言:javascript复制
.PHONY: all
STR =     hello a    b   c   
STRIP_STR = $(strip $(STR))
all:
    @echo "STR = $(STR)"
    @echo "STRIP_STR = $(STRIP_STR)"
代码语言:javascript复制
# make
STR = hello a    b   c   
STRIP_STR = hello a b c

strip函数经常用在条件判断语句的表达式中,去掉多余的空格等因素,确保表达式比较的可靠和健壮。

代码语言:javascript复制
ifeq ($(strip $(foo)),)
    echo "foo is empty"
endif

findstring函数:用来查找一个字符串,在字符串IN中查找“FIND”字符串,如果找到,则返回字符串FIND,否则,返回空。

代码语言:javascript复制
$(findstring FIND, IN)
代码语言:javascript复制
.PHONY: all
STR =     hello a    b   c   
FIND = $(findstring hello, $(STR))
all:
    @echo "STR = $(STR)"
    @echo "FIND = $(FIND)"

filter函数:用来过滤掉一个指定的字符串,用来过滤掉字符串TEXT中所有不符合PATTERN模式的单词,只留下符合PATTERN格式的单词。

代码语言:javascript复制
$(filter PATTERN…,TEXT)
代码语言:javascript复制
.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模式的单词,保留所有不符合此模式的单词。

代码语言:javascript复制
.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中的单词以首字母为准进行排序,并删除重复的单词。

代码语言:javascript复制
.PHONY: all
FILE = e.c a.c b.h c.s d.cpp   
all:
	@echo "FILE = $(FILE)"
	@echo $(sort $(FILE))

word函数:从一个字符串TEXT中,按照指定的数目N取单词

代码语言:javascript复制
 $(word N,TEXT)

wordlist函数:用来从一个字符串TEXT中取出从N到M之间的一个单词串

代码语言:javascript复制
$(wordlist N, M, TEXT)

words函数:用来统计一个字符串TEXT中单词的个数

代码语言:javascript复制
$(words TEXT)

foreach函数:做一些循环或遍历操作

代码语言:javascript复制
$(foreach VAR,LIST,TEXT)

把LIST中使用空格分割的单词依次取出并赋值给变量VAR,然后执行TEXT表达式。重复这个过程,直到遍历完LIST中的最后一个单词。函数的返回值是TEXT多次计算的结果。

自动搜索各个目录下的C源文件:

代码语言:javascript复制
.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时会自动对其进行匹配处理

代码语言:javascript复制
test: *.o
    gcc -o $@ $^
*.o: *.c
    gcc -c $^

用在规则的命令中:通配符的通配处理在shell执行命令时完成

代码语言:javascript复制
clean:
    rm -f *.o

除了以上两种情况,在其他地方都不能直接使用通配符。需要一些函数(如wildcard)来实现。如果想列举当前目录下的所有C文件,可以直接使用wildcard函数:

代码语言:javascript复制
$(wildcard *.c)

0 人点赞