Linux下Makefile文件的伪目标,条件判断以及函数使用

2019-10-31 08:37发布

Makefile 有一种特殊的目标——伪目标,一般的目标名都是要生成的文件,而伪目标不代表真正的目标名,在执行 make 命令的时候通过指定这个伪目标来执行其所在规则的定义的命令。

make保证目标代码由最新模块组成

使用伪目标的主要是为了避免 Makefile 中定义的只执行命令的目标和工作目录下的实际文件出现名字冲突,有时候我们需要编写一个规则用来执行一些命令,但是这个规则不是用来创建文件的,比如在前面的代码中有如下代码用来完成清理工程的功能:

clean:
rm *.o rm main

上述规则中并没有创建文件 clean 的命令,因此工作目录下永远都不会存在文件 clean,当我们输入“make clean”以后,后面的“rm *.o”和“rm main”总是会执行。可是如果我们“手贱”,在工作目录下创建一个名为“clean”的文件,那就不一样了,当执行“make clean”的时候,规则因为没有依赖文件,所以目标被认为是最新的,因此后面的 rm 命令也就不会执行,我们预先设想的清理工程的功能也就无法完成。为了避免这个问题,我们可以将 clean 声明为伪目标,声明方式如下:

 .PHONY : clean 

我们使用伪目标来更改代码,修改完成以后如下:

1 objects = main.o input.o calcu.o
2 main: $(objects)
3 gcc -o main $(objects) 4
5 .PHONY : clean
6
7 %.o : %.c
8 gcc -c $<
9
10 clean:
11 rm *.o
12 rm main

上述代码第 5 行声明 clean 为伪目标,声明 clean 为伪目标以后不管当前目录下是否存在名为“clean”的文件,输入“make clean”的话规则后面的 rm 命令都会执行。

在 C 语言中我们通过条件判断语句来根据不同的情况来执行不同的分支,Makefile 也支持条件判断,语法有两种如下:

<条件关键字>
<条件为真时执行的语句>
endif

以及:

<条件关键字>
<条件为真时执行的语句>
else
<条件为假时执行的语句>
endif

其中条件关键字有 4 个:ifeq、ifneq、ifdef 和 ifndef,这四个关键字其实分为两对、ifeq 与ifneq、ifdef 与 ifndef,先来看一下 ifeq 和 ifneq,ifeq 用来判断是否相等,ifneq 就是判断是否不相等,ifeq 用法如下:

ifeq (<参数 1>, <参数 2>)
ifeq ‘<参数 1 >’,‘ <参数 2>’
ifeq “<参数 1>”, “<参数 2>”
ifeq “<参数 1>”, ‘<参数 2>’
ifeq ‘<参数 1>’, “<参数 2>”

上述用法中都是用来比较“参数 1”和“参数 2”是否相同,如果相同则为真,“参数 1”和“参数 2”可以为函数返回值。ifneq 的用法类似,只不过 ifneq 是用来了比较“参数 1”和“参数 2”是否不相等,如果不相等的话就为真。

ifdef 和 ifndef 的用法如下:

 ifndef <变量名> 

如果“变量名”的值非空,那么表示表达式为真,否则表达式为假。“变量名”同样可以是一个函数的返回值。ifndef 用法类似,但是含义用户 ifdef 相反。

Makefile 支持函数,类似 C 语言一样,Makefile 中的函数是已经定义好的,我们直接使用,不支持我们自定义函数。make 所支持的函数不多,但是绝对够我们使用了,函数的用法如下:

 $(函数名 参数集合) 

或者

 ${函数名 参数集合} 

可以看出,调用函数和调用普通变量一样,使用符号“$”来标识。参数集合是函数的多个参数,参数之间以逗号“,”隔开,函数名和参数之间以“空格”分隔开,函数的调用以“$”开头。接下来我们介绍几个常用的函数。

1、函数 subst

函数 subst 用来完成字符串替换,调用形式如下:

 $(subst ,,) 

此函数的功能是将字符串中的内容替换为,函数返回被替换以后的字符串,比如如下示例:

 $(subst zzk,ZZK,my name is zzk) 

把字符串“my name is zzk”中的“zzk”替换为“ZZK”,替换完成以后的字符串为“my name is ZZK”。

2、函数 patsubst

函数 patsubst 用来完成模式字符串替换,使用方法如下:

 $(patsubst ,,) 

此函数查找字符串中的单词是否符合模式,如果匹配就用来替换掉,可以使用包括通配符“%”,表示任意长度的字符串,函数返回值就是替换后的字符串。如果中也包涵“%”,那么中的“%”将是中的那个“%”所代表的字符串,比如:

 $(patsubst %.c,%.o,a.c b.c c.c) 

将字符串“a.c b.c c.c”中的所有符合“%.c”的字符串,替换为“%.o”,替换完成以后的字符串为“a.o b.o c.o”。

3、函数 dir

函数 dir 用来获取目录,使用方法如下:

 $(dir ) 

此函数用来从文件名序列中提取出目录部分,返回值是文件名序列的目录部分,比如:

 $(dir ) 

提取文件“/src/a.c”的目录部分,也就是“/src”。

4、函数 notdir

函数 notdir 看名字就是知道去除文件中的目录部分,也就是提取文件名,用法如下:

 $(notdir ) 

此函数用与从文件名序列中提取出文件名非目录部分,比如:

 $(notdir ) 

提取文件“/src/a.c”中的非目录部分,也就是文件名“a.c”。

5、函数 foreach

foreach 函数用来完成循环,用法如下:

 $(foreach , ,) 

此函数的意思就是把参数中的单词逐一取出来放到参数中,然后再执行所包含的表达式。每次都会返回一个字符串,循环的过程中,中所包含的每个字符串会以空格隔开,最后当整个循环结束时,所返回的每个字符串所组成的整个字符串将会是函数 foreach 函数的返回值。

6、函数 wildcard

通配符“%”只能用在规则中,只有在规则中它才会展开,如果在变量定义和函数使用时,通配符不会自动展开,这个时候就要用到函数 wildcard,使用方法如下:

 $(wildcard PATTERN…) 

比如:

 $(wildcard *.c) 

上面的代码是用来获取当前目录下所有的.c 文件,类似“%”。

关于 Makefile 的相关内容就讲解到这里,Makefile 还有大量的知识没有提到,有兴趣的可以自行参考《跟我一起写 Makefile》这份文档来深入学习 Makefile。