记录一下常用的makefile功能,方便往后查询。
makefile基本格式
target : prerequisites
[TAB]command1
[TAB]command2
[TAB]...
[TAB]commandN
target: 目标文件,可以是object file,也可以是可执行文件
prerequisites: 生成target所需的依赖文件(目标)
command: make需要执行的命令,必须以"tab"
开头,command太长, 可以用 "\"
作为换行符
一个makefile中存在两个以上的target,如果此次make不指定生成哪一个target,那么make会自动执行第一个target
事实上make工具能理解两种类型的依赖目标:
正常依赖目标(Normal Prerequisites)
正常依赖目标能达成两个目的:
1.影响build command执行顺序, 即在生成目标(target)的命令被执行前,所有的需要生成的依赖目标(Prerequisites)的命令都需要被执行。
2.影响依赖关系, 即如果任何一个依赖目标(Prerequisites)比生成目标(target)要新时, 生成目标都将被认为太旧而需要被重新生成。
通常,上面的这两个目的正是你所需要的:当依赖目标更新时,生成目标也需要更新。
命令依赖目标(order-only Prerequisites)
偶尔的,我们会遇到这样的情况, 我们需要执行某个或某些规则, 但不能引起生成目标被重新生成, 此时你就需要使用命令依赖目标. 命令依赖目标由一个管道符号即竖线 "|" 指示, 位于依赖 目标列表中. 竖线左边的目标就是正常依赖目标, 竖线右边的目标就是命令依赖目标, 形式如下:
target : normal-prerequisites | order-only-prerequisites
=, :=, ?=, +=这几个赋值运算符的区别
=
是最基本的赋值,make会将整个makefile展开后,再决定变量的值。
x = foo
y = $(x) bar
x = xyz
y的值将会是 xyz bar ,而不是 foo bar
:=
是覆盖之前的值,变量的值决定于它在makefile中的位置,而不是整个makefile展开后的最终值,注意与=
的区别。
x := foo
y := $(x) bar
x := xyz
y的值将会是 foo bar ,而不是 xyz bar 了
?=
如果没有赋过值,就赋值
+=
连接值
shell命令前缀@ 和 -
3种格式的shell命令区别:
不加前缀: 输出执行的命令以及命令执行的结果,出错的话停止执行
前缀 @ : 只输出命令执行的结果,出错的话停止执行
前缀 - : 命令执行有错的话,忽略错误,继续执行
all:
echo "没有前缀"
cat this_file_not_exist
echo "错误之后的命令"
分别替换 cat 为 -cat, @cat
伪目标
伪目标的作用是,在执行make时可以指定这个目标来执行其所在规则定义的命令。使用伪目标可以避免和同名文件冲突,改善性能。
格式: .PHONY target
典型的伪目标是 Makefile 中用来清理编译过程中中间文件的 clean 伪目标
.PHONY: clean
clean:
-rm -f *.o
条件判断
ifeq, ifneq: 变量是否相等
ifdef, ifndef: 变量是否已赋值
ifdef DEFINE
msg = "Hello World!"
endif
ifeq ($(OPT),define)
msg += "define"
else
msg += "nu define"
endif
all :
@echo $(msg)
foreach
for循环处理,格式: $(foreach <var>, <list>, <text>)
targets := a b c d
objects := $(foreach i,$(targets),$(i).o)
all:
@echo $(targets)
@echo $(objects)
if
条件判断,格式:
$(if <condition>,<then-part>)
$(if <condition>,<then-part>,<else-part>)
val := a
objects := $(if $(val),$(val).o,nothing)
no-objects := $(if $(no-val),$(val).o,nothing)
all:
@echo $(objects)
@echo $(no-objects)
自动变量
makefile有很多时候通过自动变量来简化书写,常用的自动变量含义如下:
$@ : 目标文件
$^ : 所有的依赖文件,会去除重复的依赖文件
$+ : 所有的依赖文件,不会去除重复的依赖文件
$< : 第一个依赖文件
转义$$
dir=/*
.PHONY: show
show:
@for i in $(dir);do echo $$i;done
#例子中 $$i,$$是转义$,$$i最终shell看到的是$i;而$(dir)最终shell看到的是$(dir)的值
#需要在shell中执行的是 for i in value-of-dir-in-makefile; do echo $i ; doen 这个语句写到makefile中,
#$i 中的 $ 当然需要转义了,要不然 Shell 看到的就是 for i in value-of-dir-in-makefile; do echo value-of-i-in-makefile; done 这个显然是不正确的。
call函数
call函数是用于创建新参数化的函数。你可以写一个表达式,里面定义了许多参数,然后你用call函数来向这个表达式传递参数,语法如下
$(call <expression>, <parm1>, <parm2>, <parm3>...)
当make执行这个函数时,
test = $(1)$(2)
test2 = $(2)$(1)
foo = $(call test, a, b)
foo2 = $(call test, b, a)
all:
@echo $(foo)
@echo $(foo2)
foo值为"ab", foo2值为"ba"
makefile中一些约定的伪目标
在linux上,从源码安装软件,都会对make clean,make install比较熟悉。像clean,install这些伪代码,广为人知。如果在我们自己项目的makefile合理使用这些伪目标的话,可以是我们 的项目变得更专业。
伪目标 | 说明 |
---|---|
all | 所有目标的目标,其功能一般是编译所有的目标 |
clean | 删除所有被make创建的文件 |
install | 安装已编译好的程序,其实就是把目标可执行文件拷贝到指定的目录中去 |
列出改变过的源文件 | |
tar | 把源程序打包备份. 也就是一个tar文件 |
dist | 创建一个压缩文件, 一般是把tar文件压成Z文件. 或是gz文件 |
TAGS | 更新所有的目标, 以备完整地重编译使用 |
check 或 test | 一般用来测试makefile的流程 |
其他详情可以参考此链接:
http://www.cnblogs.com/wang_yb/p/3990952.html
http://www.cnblogs.com/liangxiaxu/archive/2012/07/31/2617384.html