2016/02/22

记录一点makefile


记录一下常用的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执行这个函数时,参数中的变量,如$(1),$(2),$(3)等,会被参数,,依次替换。而的返回值就是call函数的返回值。

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 安装已编译好的程序,其实就是把目标可执行文件拷贝到指定的目录中去
print 列出改变过的源文件
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