Makefile最基本的规则:target....:prerequisites.....

command

或:target....:prerequisites.....;command

target:目标文件,prerequisites:依赖文件,command:要执行的操作。命令太长可以使用“\”来换行不断行,其中的命令使用UNIX的标准shell,/bin/sh来执行。

                                          基本等同于直接在terminal中输入命令的效果。

伪目标一般指不需要依赖文件的一类目标,可以使用“.PHONY”来显式的指出。

Makefile中的注释以“#”开头,命令以“[Tab]键开头”。注意加注释时,不要直接加在变量定义后边,因为这是Makefile会将空格也计算在变量内。

Makefile默认会将第一个目标设置为最终的目标。

在命令行输入make命令时,默认会在当前目录按“GNUmakefile”,“makefile”,“Makefile”的文件来顺序搜索。如果需要指定特定的Makefile,可以使用make的参数

             “-f”,"--file"。在Makefile中可以使用“include”关键字将别的Makefile包含进来。在include前加“-”号,可以让make继续执行,而不论文件是否能读取

    所有的make命令之前加-号,都是忽略函数返回值的。   -rm -rf ./

makefile中的include,有三种形式,

1) include,  2) -include,3) sinclude,sinclude与-include类似,但是兼容性好一些。

Makefile中调用include的方式:

1) 首先在当前或者指定的目录下寻找被调用文件;

2) 如果没有找到,从-I所指定的include目录中寻找,

3) 仍然没有找到,makefile试图寻找匹配规则来生成对应的文件

  常见的应用模式,生成dependence文件 .d文件:

  sinclude $(SOURCE:.c = .d)  #include .d文件:

  %.d:%.c

    @set -e;\

    $(CC) -MM $(INC_FLAG) $(DEF_FLAG) $< > $@.$$$$;

环境变量MAKEFILES,make会把这个变量的值做成一个类似include的动作,其中有一个区别是,从这个环境变量引入的Makefile的目标不会被识别。这个变量中的值,

用空格分隔。

make中的命令执行时,如果需要之后的一条命令,在前一条的基础上执行,则这两条命令必须写在同一行上,并且用分号隔开

    exec:

      cd /home/hchen;   pwd;

在描述Makefile中的规则时,make支持三种通配符“*”,“?”,“[...]”

  objects = *.o

  当变量中定义了通配符时,makefile并不会展开,变量的值就是*.o

  objects := $(wildcard *.o)

  需要展开时,需要加入wildcard关键字,这时,变量中的值就是所有.o文件的集合

在寻找目标文件和依赖文件的时候,在当前文件中找不到的情况下,make命令会自动搜索“VPATH”所指定的路径。“VPATH”变量中的值用“冒号”分隔。

  VPATH = src:../headers

  makefile会按顺序,一次搜索./src文件夹和../headers文件夹;

Makefile还有一种关键字“vpath”,用来指定符合模式的文件的所搜路径。 Eg  vpath %.c ../foo   makefile会在../foo中搜索所有的.c文件

静态模式:<targets...>:<target-pattern>:<prereq-patterns....>

<command>

适用于使用“%”来定义一个目标集模式。prereq-patterns一般也是用“%”来表示某种依赖文件。

可以有两个target,相同的依赖关系以及操作;

  bigoutput  littleoutput : text.g

    generate text.g -$(subst  output, , $@) > $@

$@中有几个目标,便等同于几个target

-MM自动生成依赖关系,gcc -MM main.c文件

Makefile中的变量,是大小写敏感的,传统的Makefile的变量名全是大写的命名方式。变量在声明时需要给予初值,在使用时,需要在前边加上“$”符号。可以用“()”

和“{}”来括起变量。如果要表示真实的“$”字符,需要使用“$$”表示。

几种定义方式:A=1234

A:=1234    前边的变量不能使用后边才定义的变量,这样防止上一种定义方式可能发生的变量嵌套时的死锁。

A?=1234    如果A前边没有定义过,这条语句才会有效。

A+=1234    为变量A追加值,以空格隔开,如果变量之前有定义,“+=”会自动继承前次操作的赋值符。“=” “:=” "+="

如果有变量是通过命令行参数来定义的,同时Makefile内部也对它进行了定义,则默认忽略Makefile中的定义。除非加“override”关键字在变量定义时

  对变量列表中的变量可以直接进行替换: $(sources:.c = .d)将之前source中的.c文件都替换为.d文件。

Makefile中还有针对目标的变量和针对模式的变量。

从terminal中将变量传入makefile, 直接make   var=2接口,makefile内部直接将var作为一个为赋值的变量就可以。该var的值也可以作为target,来从外部控制makefile流程。

Makefile中的条件判断:make是在读取Makefile时就计算表达式的值,并根据条件表达式的值来选择语句,所以不应该吧自动化变量如($@)放在条件表达式中。

1)ifeq, else, endif

2)ifneq

3)ifdef

4)ifndef

for循环:必须使用$$(),来调用循环变量。

rule1:

  for i in $(SOURCE); do echo $$(i); done

Makefile默认会将要执行的命令,在执行前输出到屏幕,当我们用“@”字符在命令前时,这个命令就不会被显示出来了用“-”在命令前,则该命令即使出现问题,make

也不会退出。

在Makefile中执行命令时,如果要让上一条命令的结果应用于下一条命令时,应该使用“分号”来分隔这两条命令。

Eg: cd /home/hchen         cd /home/hchen;

pwd                          pwd

在Makefile间传递变量,直接在当前环境生成环境变量,在定义变量时,使用“export”关键字。只加一个export后没有变量,则传递所有变量。如果有从命令过来的变量,Makefile会自动在嵌套式的

Makefie中传递。也可以使用unexport来拒绝传递变量;

Makefile中的字符串处理函数:函数调用与变量的使用很像,也是使用“$”来标识。

1)$(subst <from>,<to>,<text>):字符串替换函数。

2)$(patsubst <%from>,<%to>,<text>):模式字符串替换函数。

3)$(strip <string>):去掉字符串的前后空格。

4)$(findstring <fing>,<in>):查找字符串并返回。

5)$(filter <pattern.....>, <text>):过滤函数,返回符合模式的单词。

6)$(filter-out <pattern.....>, <text>):反过滤函数,返回不符合模式的单词。

7)$(sort <list>):给字符串<list>中的单词排序,去除相同的单词。

8)$(word <n>, <text>):取单词函数。

9)$(wordlist <s>, <n>, <text>):取多个单词函数。

10)$(words <text>):统计单词个数函数。

11)$(firstword <text>):取首个单词函数。

Makefile中的文件名操作函数:

1)$(dir <name....>) 取目录函数,可以是多个数据的列表,返回多个。

2)$(notdir <name....>) 取文件函数,与上一函数相反。

3)$(suffix <name.....>) 取后缀函数,如文件后缀。

4)$(basename <name....>) 取前缀函数,除了文件后缀的其他部分。

5)$(addsuffix <suffix>, <name....>) 加后缀函数,加文件后缀。

6)$(addprefix <prefix>, <name....>) 加前缀函数,加除了文件后缀之外的部分。

7)$(join <list1>, <list2>) 连接函数,将<list2>的单词对应的加到<list1>的后边。

Makefile中的其他函数:

1)$(if <condition>, <then-part>, <else_part>)

2)$(origin <variable>) 返回变量的来历

  返回值是固定的几个,undefined,default,file,command line,override,automatic,environment,

    一般用在变量是否被重新定义,override太过暴力,可以在来自env的进行重定义;

    ifeq “$(origin bletch)"  "environment"

      bletch = barf,

3)$(shell xxx) 引用UNIX的shell命令,与“反引号”作用相同。

  contents := $(shell  cat foo)

4)$(error <text...>) 表示出现错误,打出text,退出。

5)$(warning <text...>) 表示出现warning,打出text。

6)   $(call <expression>, <param1>, <param2> ....)自定义一个参数化的函数

    reverse  = $(1) $(2)   ##首先自定义一个复杂的表达式

    foo = $(call reverse , a, b)  ##直接调用

    ##返回a b。

Makefile中的参数“-w”或是“--print-directory”,在切换目录时,输出信息。

“-n”或是“--just-print",只打印出命令及其规则,但是不执行,适合调试。

 “-C”或是“--directory”,指定读取makefile的目录。

        "-s" make时的参数,全面禁止命令的显示。

        “-i” 执行过程中,忽略所有的error;

        “-k” 执行过程中,一个target执行错误之后,执行其他的target;

1)嵌套式的makefile,一般讲make和makefiag定义为变量,这样方便一些  make 参数的传递,

2)makefile中定义命令包,命名空间与变量相同,调用也相同;以define开头, endef结束;

   define run-yacc

    yacc $(firstword $^)

    mv y.tab.c $@

   endef

自动化变量$@,表示规则中的目标文件集合,用于匹配目标模式中定义的集合;

     $<,依赖目标中的第一个目标的名字,如果依赖目标是以%来定义的,那么$< 表示符合模式的一系列的文件集合,是一一取出来的。

     $*,目标模式 %,及其之前的部分;

        %.d : %.c

          gcc $(INC_FLAG) -o $*.o  //其中的$*表示.d文件名 

$(shell pwd | sed 's///');来进行目录的操作。

05-20 18:14