在Makefile中可以使用Makefile特点的函数来出来问题,例如在源码搜寻中使用的函数SRC =
(wildcard
(DIR_SRC)/*.c)
与变量相识,用关键字wildcard修饰,该函数的作用是实现通配符“*”,因为在Makefile变量定义中通配符不会自动展开,需要关键字修饰。整个函数的作用是:定义变量SRC,将目录$(DIR_SRC)/下的所有后缀为.c的文件都赋给变量SRC,这个定义与SRC = ./src/main.c ./src/module_func的功能是一样的。
与C语言类似,变量SRC其实就是函数的返回形式,也可以看做是这个函的宏定义。
Makefile的函数调用以关键字为核心修饰形式,结合变量定义来使用。
函数基本书写方法:$( )
function:函数名、关键字
arguments:函数传参
例如SRC = (wildcard (DIR_SRC)/.c)函数,源码路径不止只有一个,多个源码路径可以写成SRC = (wildcard (DIR_SRC)/.c $(DIR_SRC)/module/*.c)
变量定义展开通配符函数 $(wildcard parameter1 parameter2 …)
与上文描述的一样,通过该函数关键字的修饰,后面的参数就可以使用Linux下的通配符,参数以空格间隔。
条件判断函数
非空判断函数 $(if …)、ifdef、ifndef
函数写法:
$(if <condition>,<then-part>,<else-part>)
ifdef <condition>
ifndef <condition>
该函数判断的条件是判断condition是否非空,非空函数返回then-part的部分,空值则返回else-part的部分。该函数if没有判断condition里面逻辑是否为真假的能力,如果condition的值为1>2,对于Makefile来说,这个就是一个字符串,为非空值,所以判断为真。若不需要执行else-part部分,可以省略不写。
TESTIF1 = string
TESTIF2 =
IFFUNC1 = $(if 1>2,ture,false)
IFFUNC2 = $(if $(TESTIF1),then-part,else-part)
IFFUNC3 = $(if $(TESTIF2),then-part,else-part)
all:
@echo "this is all project"
@echo "$(IFFUNC1)"
@echo "$(IFFUNC2)"
@echo "$(IFFUNC3)"
执行结果
ghost@ghost-machine:~/workspace/testMakefile$ make
this is all project
ture
then-part
else-part
对于ifdef与ifndef,条件需要endif来约束,其判断的条件与上面的判断不同,但变量的标准是一致的。
TESTIF1 = string
TESTIF2 =
all:
@echo "this is all project"
ifdef $(TESTIF1)
@echo "test if 1 call true"
else
@echo "test if 1 call salse"
endif
ifdef TESTIF1
@echo "test if 1 true"
else
@echo "test if 1 salse"
endif
ifdef TESTIF2
@echo "test if 2 true"
else
@echo "test if 2 salse"
endif
执行结果:
ghost@ghost-machine:~/workspace/testMakefile$ make
this is all project
test if 1 call salse
test if 1 true
test if 2 salse
ifdef $(TESTIF1)
编译过程中展开:ifdef string
在Makefile文件中没有定义到“string”这个变量,执行else选项。
ifdef TESTIF1
在Makefile文件中定义了这个变量,并且这个变量的值非空,执行if选项。
ifdef TESTIF2
在Makefile文件中定义了这个变量,但这个变量的值为空,执行else选项。
相等与不等判断函数 ifeq、ifneq
书写方式:
相等判断:ifeq (string1,string2)
不等判断:ifneq (string1,string2)
该函数严格来说不是Makefile专用的函数,仅仅作为脚本判断语句,该函数是判断字符串string1与string2是否相等,根据相等或不等来执行下面的脚本,if执行脚本的范围由endif约束。
函数中可以不需要else的部分,但是不能去掉if的结尾部分endif来约束范围。
STRINFG1 = test
STRINFG2 = test
all:
@echo "this is all project"
ifeq ($(STRING1),$(STRING2))
@echo "true"
else
@echo "salse"
endif
ifneq ($(STRING1),$(STRING2))
@echo "true"
else
@echo "salse"
endif
执行结果
ghost@ghost-machine:~/workspace/testMakefile$ make
this is all project
true
salse
赋值shell命令函数 $(shell command)
Makefile本身就可以兼容一些shell脚本,比如在Makefile语句中直接输入:
gcc main.c -o main.o
或者
./test.sh
这些都是可以直接运行的,但这个赋值shell命令函数是将系统执行shell语句后,将结果返回给变量,最常见的是返回地址“pwd”的内容。
TESTSHELL1 = $(shell echo ./src/module/*.c)
TESTSHELL2 = $(shell pwd)
all:
@echo "this is all project"
@echo "$(TESTSHELL1)"
@echo "$(TESTSHELL2)"
@./test.sh
test.sh内容
#!/bin/bash
echo "this is shell test!!!"
执行结果:
ghost@ghost-machine:~/workspace/testMakefile$ make
this is all project
./src/module/module_func.c ./src/module/module_system.c
/home/ghost/workspace/testMakefile
this is shell test!!!
字符串处理函数
字符串替换函数 $(subst ,,)
该函数是以string为基础,在其中搜索找到source字符串,并将其替换为target字符串,这里的字符串可以是纯粹的字符串也可以是变量。
纯粹的字符串在Makefile有两种写法
1、带引号的字符串
TEST = $(subst abc,def,"abc test")
all:$(BIN_TARGET)
@echo "this is all project"
@echo $(TEST)
2、不带引号的变量
TEST = $(subst abc,def,abc test)
all:$(BIN_TARGET)
@echo "this is all project"
@echo $(TEST)
输出的结果都是一样的
ghost@ghost-machine:~/workspace/testMakefile$ make
this is all project
def test
通过变量可以被替换,那么在实际应用中,最多使用的是源码与目标文件的变换,例如将.c替换为.o
以Makefile书写风格为例工程的书写为
SRC = $(wildcard $(DIR_SRC)/*.c)
DIR_TARGET = $(subst %.o,%.c,$(SRC))
CFLAGS = -g -Wall $(DIR_INC)
all:$(BIN_TARGET)
@echo "this is all project"
$(BIN_TARGET):$(DIR_TARGET)
$(CC) $(CFLAGS) -o $@ $(DIR_TARGET)
$(DIR_TARGET):
@$(CC) $(CFLAGS) -c $(SRC)
函数DIR_TARGET =
(subst
(SRC))输出的结果是
将SRC中的所有.c文件描述的字符串都转换为.o文件描述的字符串
文件名操作函数
取文件名目录函数 $(dir …)
该函数是将类似地址的字符串中的目标文件以目录的形式剥离出来,类似地址的字符串是指带有反斜杠“/”的字符串,若没有遇到反斜杠,函数直接返回“./”,多个地址由空格间隔,返回的地址也是以空格间隔。
NAME1 = $(dir dir1/dir2/dir3/test1.c ./dir1/dir2/test2.c)
NAME2 = $(dir dir1dir2dir3test.c)
all:$(BIN_TARGET)
@echo "this is all project"
@echo "$(NAME1)"
@echo "$(NAME2)"
输出结果
ghost@ghost-machine:~/workspace/testMakefile$ make
this is all project
dir1/dir2/dir3/ ./dir1/dir2/
./
该函数的功能是处理类似地址的字符串功能,得到文件名的地址,该函数是为了方便转换,例如有些Makefile对源文件的写法
SRC = main.c ./src/module_func.c
利用该函数就可以得到这些源码文件的地址。
取目录文件名函数 $(notdir …)
该函数也是处理类似地址的字符串,类似地址的字符串中的目标文件以文件名形式剥离出来,与取文件名目录函数相反,函数返回的是文件名而不是目
DIR1 = $(notdir dir1/dir2/dir3/test1.c ./dir1/dir2/test2.c)
DIR2 = $(notdir dir1dir2dir3test.c)
all:$(BIN_TARGET)
@echo "this is all project"
@echo "$(DIR1)"
@echo "$(DIR2)"
执行结果
ghost@ghost-machine:~/workspace/testMakefile$ make
this is all project
test1.c test2.c
dir1dir2dir3test.c
取后缀函数 $(suffix …)
该函数处理类似有后缀的字符串,函数返回的是该字符串的后缀,该函数的判断标准是以字符串末尾的“.”结尾的后缀。
SUFFIX = $(suffix dir1/init.d/test.c test.tar.gz)
all:$(BIN_TARGET)
@echo "this is all project"
@echo "$(SUFFIX)"
执行结果
ghost@ghost-machine:~/workspace/testMakefile$ make
this is all project
.c .gz
取前缀函数 $(basename …)
该函数处理类似有后缀的字符串,函数返回的是该字符串的前缀,与取后缀函数相反,该函数的判断标准是字符串末尾的“.”为判断标准。如果是带有目录的字符串,返回的也是带有目录的,即该函数返回的是除后缀名以外的所有字符串。
BASENAME = $(basename dir1/init.d/test.c test.tar.gz)
all:$(BIN_TARGET)
@echo "this is all project"
@echo "$(BASENAME)"
执行结果
ghost@ghost-machine:~/workspace/testMakefile$ make
this is all project
dir1/init.d/test test.tar
加后缀函数 $(addsuffix , …)
该函数的作用是在字符串的末尾添加后缀名,后缀名与后面的文件名以逗号“,”间隔。
ADDSUF = $(addsuffix .c,dir1/dir2/test ./dir1/dir2/test.o)
all:
@echo "this is all project"
@echo "$(ADDSUF)"
执行结果
ghost@ghost-machine:~/workspace/testMakefile$ make
this is all project
dir1/dir2/test.c ./dir1/dir2/test.o.c
加前缀函数 $(addprefix , …)
该函数的作用是在字符串的开始添加前缀,前缀与后面的文件名以逗号“,”间隔。
ADDPRE1 = $(addprefix .c,dir1/dir2/test ./dir1/dir2/test.o)
ADDPRE2 = $(addprefix dir1/dir2/,test.c dir3/test)
all:
@echo "this is all project"
@echo "$(ADDPRE1)"
@echo "$(ADDPRE2)"
执行结果
ghost@ghost-machine:~/workspace/testMakefile$ make
this is all project
.cdir1/dir2/test .c./dir1/dir2/test.o
dir1/dir2/test.c dir1/dir2/dir3/test