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文件。

    

Android mk文件 变量 android makefile详解_Android mk文件 变量

 

      

 

 

 

 

 

    3、自动产生依赖

      使用gcc编译时会自动产生对应的头文件依赖。

      foo.o : foo.c#foo.c中include了foo.h

      执行:gcc –M foo.c

      输出:foo.o : foo.c foo.h

      

Android mk文件 变量 android makefile详解_Android mk文件 变量_02

Android mk文件 变量 android makefile详解_Android mk文件 变量_03

Android mk文件 变量 android makefile详解_Android mk文件 变量_04

    4、make自动推导依赖

      all: foo.o bar.o

      则make检测到foo.o,则会自动将foo.c加入依赖文件,并自动推导出

      gcc -c foo.c

      

Android mk文件 变量 android makefile详解_未定义_05

Android mk文件 变量 android makefile详解_Android mk文件 变量_06

Android mk文件 变量 android makefile详解_伪目标_07

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

    

Android mk文件 变量 android makefile详解_未定义_08

             echo $$VAR     => 将$$先执行一次扩展,得到shell命令echo $VAR将给shell执行,因为shell中已定义VAR=4,所以结果为4

6、条件判断

  

Android mk文件 变量 android makefile详解_伪目标_09

 

  

    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 ...>;)