1、格式
#注释以“#”开始,下面是一条规则的格式
一条规则由目标、依赖文件及命令行组成。
targets… : normal-prerequisites …|order-by-prerequisites ; command
[tab]command
…
targets: 目标,多个目标用空格隔开。
normal-prerequisites:目标依赖的文件或者中间目标,多项用空格隔开。
order-by-prerequisites:目标依赖的文件或者中间目标,不存在时先重建本身,然后更新目标。用“|”隔开,只检查是否存在。
command:执行的命令,新行以TAB开头,或直接用“;”隔开放入目标行。
1 #sample makefile
2 LIBS = libtest.a
3 foo : foo.c | $(LIBS)
4 gcc $< -o $@ $(LIBS)
foo是目标,foo.c和libtest.a是依赖文件,foo.c是normal-prerequisites, libtest.a是order-by-prerequisites。
当foo.c改变时,执行make,则重建foo;libtest.a不存在时,执行make,则先重建libtest.a,然后重建foo。只更新libtest.a,则foo在上次重建后,本次执行make不重新构建。
gcc $< -o $@ $(LIBS)属于执行构建的命令行
一条规则的含义是:
当目标是一个文件时,如果它的任何一个普通依赖文件的时间戳比目标文件新(被改动),则这条规则的命令将被执行。
2、目标
- 普通目标:代表文件名,有依赖文件
targets… : normal-prerequisites
- 伪目标:不代表文件名,仅是一个标签,用于执行make时,执行该规则定义的命令
1 clean: #该目标被定义为伪目标,make clean时,执行rm *.o temp
3 rm *.o temp
1 #避免本目录下存在clean文件,则用.PHONY明确声明clean为伪目标
3 .PHONY: clean
5 clean:
7 rm *.o temp
- 强制目标:一个规则没有命令和依赖,而且它的目标不是一个存在的文件。
1 a:=bar.c
2 clean: FORCE
3 rm $(a)
4 FORCE:
#FORCE这个规则本身没有依赖和命令,同时本身作为依赖,目标clean不是一个存在的文件,则make clean,FORCE被认为已经更新过,因此rm $(objects)执行。
- 空目标:伪目标的变种,目标可以是一个存在的文件,但该文件内容通常为空。
- 约定俗成的伪目标命名
“all”
这个伪目标是所有目标的目标,其功能一般是编译所有的目标。
“clean”
这个伪目标功能是删除所有被make创建的文件。
“install”
这个伪目标功能是安装已编译好的程序,其实就是把目标执行文件拷贝到指定的目标中去。
“print”
这个伪目标的功能是例出改变过的源文件。
“tar”
这个伪目标功能是把源程序打包备份。也就是一个tar文件。
“dist”
这个伪目标功能是创建一个压缩文件,一般是把tar文件压成Z文件。或是gz文件。
“TAGS”
这个伪目标功能是更新所有的目标,以备完整地重编译使用。
“check”和“test”
这两个伪目标一般用来测试makefile的流程。
3、依赖
- 依赖文件是构建目标文件需要的源文件或库文件
- 声明目标和依赖可以有如下方法:
1、明确声明
foo.o bar.o : foo.c bar.c
2、静态模式
1 objects=foo.o bar.o
2 all:$(objects)
3 $(objects):%.o:%.c
4 #声明每一个.o文件依赖于同名的.c文件。
3、自动产生依赖
使用gcc编译时会自动产生对应的头文件依赖。
foo.o : foo.c#foo.c中include了foo.h
执行:gcc –M foo.c
输出:foo.o : foo.c foo.h
4、make自动推导依赖
all: foo.o bar.o
则make检测到foo.o,则会自动将foo.c加入依赖文件,并自动推导出
gcc -c foo.c
4、命令
[tab]command
1. 未指定shell,则由/bin/sh解析。
2. 命令回显:@command,不显示命令本身,只显示结果。
3. 同一行中多个命令属于一个 命令行,多行命令属于多个命令行。
先切换工作目录到bar,然后执行命令。
[tab]cd bar
不切换工作目录。
4. 通过make -jN来并发执行,N为并发数,如make –j8
5、变量
xy= hello.c#java code:String xy = “hello.c”;
program : $(xy)
xy叫做变量, $(xy) 叫做变量的引用,实际是变量的值。
1、变量引用的展开过程是严格的文本替换过程
2、必须使用$()或者${}来展开变量,即获取变量的值。
如果使用$xy,则执行时被解析为$x + y,x变量由于未定义,则$x 为空字符串,y为普通字符串,因此$xy展开结果为y
3、变量名是不包括“:”、“#”、“=”、前后置空白的字符串
4、变量名是大小写敏感的
5、“$<”、“$@”、“$?”、“$*”等属于自动化变量
foo.a(bar.o):a.c b.c a.c#上次build后,b.c更新过
$@ 规则中的目标名 :foo.a
$< 规则中的第一个依赖文件:a.c
$? 比目标文件新的依赖文件列表,不含重复文件:b.c
$^ 规则的依赖文件列表,不含重复文件:a.c b.c
$+ 规则的依赖文件列表,含有重复的文件:a.c b.c a.c
$%目标是一个静态库文件时,代表静态库的一个成员名:bar.o
$* 在模式规则和静态模式规则中,代表“茎”。
目标“dir/a.foo.b”,当目标的模式为“a.%.b”时,“$*”的值为“dir/a.foo”
6、变量的定义赋值:
1)递归展开式,使用“=”
y=$(x)
x=1
#z先展开为$(x),最后z为1
2)直接展开式,使用“:=”
y:=2$(x)
x:=1
#由于y定义时x还未定义,y实际为2,最后z为2,而不是21
3)条件赋值,使用“?=”
#如果xy未定义,则定义xy=bar,否则不修改xy。
4)追加赋值,使用“+=”
#需要根据xy的定义来确定是递归展开还是直接展开
7、 变量值的替换
1)格式: “$(var:a=b)”或是“${var:a=b}”
示例:
foo := a.o b.o c.o
bar := $(foo:.o=.c) or $(foo:%.o=%.c)#结果为bar := a.c b.c c.c
2)把变量的值再当成变量
示例:
x = $(y)
y = $(z)
z = u
a := $($($(x)))#结果为a := u
3)引用shell内的变量,而非Makefile变量
示例:
1 VAR=3
2 target:
3 echo $(VAR);\
4 VAR=4;\
5 echo $(VAR);\
6 echo $$VAR
echo $$VAR => 将$$先执行一次扩展,得到shell命令echo $VAR将给shell执行,因为shell中已定义VAR=4,所以结果为4
6、条件判断
1、ifeq用于判断两个值是否相等
2、else 当条件不满足时执行
3、ifdef 用于判断变量是否定义,下面两种情况返回假,其他都为真
①变量未定义
②用“arg=”空字符串定义arg
自动化变量不能作为条件判断
7、函数
1. 定义
define <function-name>
...
endef
2. 使用
$(function-name arg1,arg2)
参数间以逗号“,”分隔,而函数名和参数之间以“空格”分隔。函数调用以“$”开头,以圆括号或花括号把函数名和参数括起。
$(function arg1, arg2)
$(subst ee,EE,feet on the street)
3.函数对应
$(wildcard *.c) 获取当前目录所有c文件
$(patsubst %.c,%.o,x.c.c bar.c) “x.c.o bar.o”
$(strip a b c ) “a b c”
$(filter %.c, foo.c bar.c baz.s) “foo.c bar.c”
$(filter-out %.c, foo.c bar.c baz.s) “baz.s”
$(sort foo bar lose) “bar foo lose”
$(word 2, foo bar baz) “bar”
$(wordlist 2, 3, foo bar baz) “bar baz”
$(words foo bar baz) “3”
$(firstword foo bar) “foo”
$(dir src/foo.c hacks) “src/ ./”
$(notdir src/foo.c hacks) “foo.c hacks”
$(suffix src/foo.c src-1.0/bar.c hacks) “.c .c”
$(basename src/foo.c src-1.0/bar.c hacks) “src/foo src-1.0/bar hacks”
$(addsuffix .c,foo bar) “foo.c bar.c”
$(addprefix src/,foo bar) “src/foo src/bar”
$(join aaa bbb , 111 222 333) “aaa111 bbb222 333”
files := $(foreach n,a b c,$(n).o) “a.o b.o c.o”
$(warning <text ...>;)