规则中的recipes包含一或多行shell命令。其总是由/bin/sh来执行(除非makefile指定了其他的shell)
5.1方法的语法
(规则开始行)-(下一个规则开始行或变量定义行)中间的所有以tab开头的行均被看作recipes。
recipes中使用的是shell的语法,make对recipes的处理很少:
1:recipes如果被 "反斜杠+换行符"分割;则被看作一行recipe,由一个shell实例进行处理。但"反斜杠+换行符"不会被删除,而是直接交给shell。如果"反斜杠+换行符"后的第一个字符是'tab',并且没有被单引号或双引号括住,则其会被删除。
2:recipes出现"$(var)";var会被替换为其代表的值。"$$(var)",代表var是一个shell变量;
5.2方法的回显
默认每行recipe在执行前会被打印。如果recipe以'@'开头,则不打印。
-n 或 --just-print 只打印recipe,不执行
-s 或 --silent 不打印任何recipe
5.3方法是如何执行的
默认每行recipe由独立的子shell进程执行。
如果在任意行定义了".ONESHELL",任意规则的recipes均会在同一个shell中执行。如果recipes的第一行出现特殊字符 ('@','+','-'),余下recipes在执行前会自动添加该字符(调用shell时会被舍弃)
5.4并行执行
略
5.5执行过程中出现错误
默认当出现错误(某行recipe的返回值不为0),立刻放弃当前规则;如果该规则的目标是其他规则的依赖,其它规则也不会执行;
如果recipe以'-'开头,忽略该行的错误。如果执行make时指定"-i"或"--ignore-errors"参数,忽略所有recipes的错误。如果某行recipe的错误被忽略且该行发生错误时,make会像成功一样处理。但会打印错误码并告知用户
如果执行make时指定"-k"或"--keep-going"参数,则make会尽可能执行更多的规则。
出现错误后,目标一般会被错误的更新,需要手动删除该目标。如果定义了".DELETE_ON_ERROR",make会自动删除。
5.6强制停止Make
强制停止后,目标一般会被错误的更新,make会自动删除该目标。如果该目标是".PERCIOUS"的依赖,不会被自动删除。
5.7递归使用make
进入subdir子目录执行该目录下的makefile:
subsystem:
cd subdir && $(MAKE)
subsystem:
$(MAKE) -C subdir
当makefile开始执行时,CURDIR会被自动设定为当前的工作目录,且以后不会再更改。手动更改CURDIR并不会导致工作目录的变化。
如果$(MAKE)出现在recipe,'-t','-n','-q'标志会被忽略,相当于该行有'+'前缀。而这些标志会通过MAKEFLAGS传递给下一级make.
默认make会export命令行中定义的变量和已经存在的环境变量。MAKEFLAGS总会被export,如果MAKEFILES不为空,也会被export。MAKELEVEL在传递时会不断自加(0表示主make,1表示sub-make,2表示sub-sub-make...)
export后不加变量代表默认export所有的变量
默认所有的sub-make通过MAKEFLAGS的内容获得命令行的标志和变量,用户可以在makefile中修改MAKEFLAGS来改变sub-make得到的值。注意:MAKEFLAGS不存在'-C','-f','-o','-W'选项以及它们的全称,不建议包含'-t','-n','-q'选项。
MAKEOVERRIDES仅包含命令行的变量。可以被makefile修改,且被MAKEFLAGS引用。
MFLAGS仅包含命令行的标志。不能被makefile修改,不会自动export
如果makefile中存在多级递归调用,建议在命令行中使用'-w' 或'--print-directory'选项。会在改变目录是打印目录信息。
5.8定义封装的方法
定义方法时变量和函数不展开,等执行时才会展开。
define run-yacc =
yacc $(firstword $^)
mv y.tab.c $@
endef
foo.c : foo.y
$(run-yacc)
如果在使用时对封装的方法加前缀,则该前缀会作用到该方法的每一行。例如下面的用法不会打印执行的recipe
foo.c:foo.y
@$(run-yacc)
5.9使用空方法
当规则的recipe仅是一个空格时,即定义了一个空方法。
空方法可以用来避免使用隐含规则,也可以用来确保目标需要重建(类似.PHONY)