文章目录
- 0.概述
- 1.常用规则
- 1.1 清空目录的规则
- 1.2 文件搜寻 (用起来比较爽)
- 1.3 伪目标(可用生成多个目标和配置工程删除规则)
- 1.4 静态模式(用起来也很爽)
- 1.5 显示命令(有助于调试makefile)
- 1.6 命令执行
- 1.7 命令出错
- 1.8 变量的定义和用法
- 1.9 使用条件判断
- 1.10 指定目标
- 1.11 检查规则
- 1.12 隐含规则(能够熟练应用可提升效率)
- 2.常用函数
- 2.1 函数的调用语法
- 2.2 函数概览
0.概述
记录工作中makefile编写常用方法和函数,详细的用法见跟我一起写Makefile无法下载的可以在评论区@我。
1.常用规则
1.1 清空目录的规则
.PHONY : clean
clean :
-rm edit $(objects)
.PHONY 表示 clean 是一个“伪目标”。而在 rm 命令前面加了一个小减号的意思就是,也许某些文件出现问题,但不要管,继续做后面的事。
不成文的规矩是——“clean从来都是放在文件的最后”。
1.2 文件搜寻 (用起来比较爽)
Makefile文件中的特殊变量 VPATH 就是完成这个功能的。
VPATH = src:../headers
上面的定义指定两个目录,“src”和“…/headers”,make会按照这个顺序进行搜索。目录由“冒号”分隔。(当然,当前目录永远是最高优先搜索的地方)
1.3 伪目标(可用生成多个目标和配置工程删除规则)
Makefile需要一口气生成若干个可执行文件,但你只想简单地敲一个make完事,并且,所有的目标文件都写在一个Makefile中,那么你可以使用“伪目标”这个特性:
all : prog1 prog2 prog3
.PHONY : all
prog1 : prog1.o utils.o
cc -o prog1 prog1.o utils.o
prog2 : prog2.o
cc -o prog2 prog2.o
prog3 : prog3.o sort.o utils.o
cc -o prog3 prog3.o sort.o utils.o
.PHONY : all 声明了“all”这个目标为“伪目标”。 “all” 是一个伪目标,执行make不会生成“all”文件,而执行后面的多个目标。
.PHONY : cleanall cleanobj cleandiff
cleanall : cleanobj cleandiff
rm program
cleanobj :
rm *.o
cleandiff :
rm *.diff
“make cleanall”将清除所有要被清除的文件。“cleanobj”和“cleandiff”这两个伪目标有点像“子程序”的意思。我们可以输入“make cleanall”和“make cleanobj”和“make cleandiff”命令来达到清除不同种类文件的目的。
1.4 静态模式(用起来也很爽)
静态模式可以更加容易地定义多目标的规则,可以让我们的规则变得更加的有弹性和灵活。
<targets ...> : <target-pattern> : <prereq-patterns ...>
<commands>
...
targets定义了一系列的目标文件,可以有通配符。是目标的一个集合。
target-pattern是指明了targets的模式,也就是的目标集模式。
prereq-patterns是目标的依赖模式,它对target-pattern形成的模式再进行一次依赖目标的定义。
objects = foo.o bar.o
all: $(objects)
$(objects): %.o: %.c
$(CC) -c $(CFLAGS) $< -o $@
上面的例子中,指明了我们的目标从$object中获取, %.o 表明要所有以 .o 结尾的目标,也就是 foo.o bar.o ,也就是变量 $object 集合的模式,而依赖模式 %.c 则取模式 %.o 的 % ,也就是 foo bar ,并为其加下 .c 的后缀,于是,我们的依赖目标就是 foo.c bar.c 。而命令中的 $< 和 $@ 则是自动化变量, $< 表示第一个依赖文件, $@ 表示目标集(也就是“foo.o bar.o”)。于是,上面的规则展开后等价于下面的规则:
foo.o : foo.c
$(CC) -c $(CFLAGS) foo.c -o foo.o
bar.o : bar.c
$(CC) -c $(CFLAGS) bar.c -o bar.o
1.5 显示命令(有助于调试makefile)
通常,make会把其要执行的命令行在命令执行前输出到屏幕上。当我们用 @ 字符在命令行前,那么,这个命令将不被make显示出来。
......
当make执行时,会输出“正在编译XXX模块……”字串,但不会输出命令,如果没
有“@”,那么,make将输出:
echo 正在编译XXX模块......
正在编译XXX模块......
正在编译XXX模块
如果make执行时,带入make参数 -n 或 --just-print ,那么其只是显示命令,但不会执行命令,这个功能很有利于我们调试我们的Makefile。
1.6 命令执行
如果你要让上一条命令的结果应用在下一条命令时,你应该使用分号分隔这两条命令。
exec:
cd /home/hchen; pwd
当我们执行 make exec 时,cd起作用了,pwd会打印出“/home/hchen”。
1.7 命令出错
忽略命令的出错,可在Makefile的命令行前加一个减号 - (在Tab键之后),标记为不管命令出不出错都认为是成功的。如:
clean:
-rm -f *.o
还有一个全局的办法是,给make加上 -i 或是 --ignore-errors 参数,那么,Makefile中所有命令都会忽略错误。
1.8 变量的定义和用法
变量在声明时需要给予初值,使用时在变量名前加上 $ 符号,最好用小括号 () 或是大括号 {} 把变量给包括起来。如果你要使用真实的 $ 字符,那么你需要用 $$ 来表示。
- 变量中的变量(使用的是 := 操作符)
x := foo
y := $(x) bar
x := later
其等价于:
y := foo bar
x := later
这种方法,前面的变量不能使用后面的变量,只能使用前面已定义好了的变量。
还有一个比较有用的操作符是 ?= ,先看示例:
FOO ?= bar
其含义是,如果FOO没有被定义过,那么变量FOO的值就是“bar”,如果FOO先前被定义过,那么这条语将什么也不做,其等价于:
ifeq ($(origin FOO), undefined)
FOO = bar
endif
- 变量高级用法(变量值的替换)
替换变量中的共有的部分,其格式是 $(var:a=b) 或是 ${var:a=b} ,其意思是,把变量“var”中所有以“a”字串“结尾”的“a”替换成“b”字串。这里的“结尾”意思是“空格”或是“结束符”。
foo := a.o b.o c.o
bar := $(foo:.o=.c)
这个示例中,我们先定义了一个 $(foo) 变量,而第二行的意思是把 $(foo) 中所有以 .o 字串“结尾”全部替换成 .c ,所以我们的 $(bar) 的值就是“a.c b.c c.c”。
另外一种变量替换的技术是以“静态模式”
foo := a.o b.o c.o
bar := $(foo:%.o=%.c)
这依赖于被替换字串中的有相同的模式,模式中必须包含一个 % 字符,这个例子同样让 $(bar) 变量的值为“a.c b.c c.c”。
- 变量高级用法(把变量的值再当成变量)
x = y
y = z
a := $($(x))
1.9 使用条件判断
使用条件判断,可以让make根据运行时的不同情况选择不同的执行分支。条件表达式可以是比较变量的值,或是比较变量和常量的值。如:
判断 $(CC) 变量是否 gcc ,如果是的话,则使用GNU函数编译目标
libs_for_gcc = -lgnu
normal_libs =
foo: $(objects)
ifeq ($(CC),gcc)
$(CC) -o foo $(objects) $(libs_for_gcc)
else
$(CC) -o foo $(objects) $(normal_libs)
endif
1.10 指定目标
makefile都包含了编译、安装、打包等功能。我们可以参照这种规则来书写我们的makefile中的目标。
- all:这个伪目标是所有目标的目标,其功能一般是编译所有的目标。
- clean:这个伪目标功能是删除所有被make创建的文件。
- install:这个伪目标功能是安装已编译好的程序,其实就是把目标执行文件拷贝到指定的目标中去。
- print:这个伪目标的功能是例出改变过的源文件。
- tar:这个伪目标功能是把源程序打包备份。也就是一个tar文件。
- dist:这个伪目标功能是创建一个压缩文件,一般是把tar文件压成Z文件。或是gz文件。
- TAGS:这个伪目标功能是更新所有的目标,以备完整地重编译使用。
- check和test:这两个伪目标一般用来测试makefile的流程。
1.11 检查规则
有时候,我们不想让我们的makefile中的规则执行起来,我们只想检查一下我们的命令,或是执行的序列。
1.12 隐含规则(能够熟练应用可提升效率)
可以把隐含规则中使用的变量分成两种:一种是命令相关的,如 CC ;一种是参数相的关,如 CFLAGS 。
- 关于命令的变量
- 关于命令参数的变量
下面的这些变量都是相关上面的命令的参数。如果没有指明其默认值,那么其默认值都是空。
- 自动化变量
四个变量( $@ 、 $< 、 $% 、 $* )在扩展时只会有一个文件,而另三个的值是一个文件列表。
下面是对于上面的七个变量分别加上 D 或是 F 的含义:
对于 $< ,为了避免产生不必要的麻烦,我们最好给 $ 后面的那个特定字符都加上圆括号,比如, $(<) 就要比 $< 要好一些。
2.常用函数
在Makefile中可以使用函数来处理变量,从而让我们的命令或是规则更为的灵活和具有智能。
2.1 函数的调用语法
函数调用,很像变量的使用,也是以 $ 来标识的,其语法如下:
$(<function> <arguments>)
或是:
${<function> <arguments>}
参数间以逗号 , 分隔,而函数名和参数之间以“空格”分隔。函数调用以 $ 开头,以圆括号或花括号把函数名和参数括起。
comma:= ,
empty:=
space:= $(empty) $(empty)
foo:= a b c
bar:= $(subst $(space),$(comma),$(foo))
为了风格的统一,函数和变量的括号最好一样。
2.2 函数概览
具体用法见跟我一起写Makefile无法下载的可以在评论区@我。