变量定义和使用:
Makefile里的变量类型只有一种,即string
定义:
object = name 或者object := name,或者object::=name,效果是一样的。注意名称中不能有#,=,:等字符
引用:
${},$()都可以,如果变量名是一个字母的,比如a,也可以直接用$引用,但是为了避免出错,建议还是用括号括起来
变量赋值:
:= 是直接展开,即读到这一行的时候就展开;=是延迟展开,在第二阶段更新的时候展开,即在运行到这个命令的时候,会把脚本里面所有这个name的变量值都读一遍,后面的会覆盖前面的。
条件赋值:
?=,意为如果该变量没有被定义,那就把这个值赋给它,如果已经赋值过了就跳过。
追加:
+=,意为在原有的基础上追加上额外的值。如下图为在files后追加scr。
shell运行赋值:
= 后面是shell命令的返回值,并把这个值赋给变量,适用于有返回值的shell命令。如下图,shell命令pwd被定义给变量INVS_DIR:
多行变量定义:
语法为:
define var_name
##变量内容
endef
这种定义类型就是把一行的变量名写成多行的形式,不用加\,这种包装命令的形式可以用在比如说命令有很多行,并且在多个地方用到了这些命令的情况。
一个变量在定义之后也可以取消定义,在后面加上undefine var_name,取消定义之后再输出就会是空的内容。
变量替换引用:
$(var:a=b),意思是将变量的值中的每一项结尾的a替换为b,或者$(var:%a=%b),%a会匹配以a结尾的所有值然后替换为值的结尾为b。
makefile中的变量可以在执行make的时候进行覆盖,比如在makefile里面变量var=start linking……,如果再执行make var=12345(等号两边不能有空格),这个时候打印出来的就会变成123456,如果指定的值当中有空格,需要使用双引号引起来,否则会报错。如果不想一个变量在执行的时候被覆盖,可以在前面加一个修饰词override
自动变量:
$@:一条规则的目标名。
$<:一条规则的第一个依赖名称。
$^:所有依赖文件名,文件名不会重复,不包含order-only依赖。
$+:类似$^, 表示所有依赖文件名,不去除重复的文件名,不包含order-only依赖。
$|:所有order-only依赖文件名。
$*:目标文件名的主干部分,%表示的内容,不包含后缀。
$%:如果目标不是归档文件,则为空;如果目标是归档文件成员,则为对应的成员文件名。
绑定目标的变量:
makefile 里的变量一般都为全局变量,在定义之后可以在makefile的任意位置使用。绑定目标的变量是可以将这个变量定义在某个目标的范围内,此时变量只能在这个目标对应的规则里面使用。
语法为:目标:指定变量,target:var-assignment
二次展开:
只限于用在依赖中,.SECONDEXPANSION,添加之后在依赖中使用变量时用$$,可以让变量在第二阶段进行二次展开。
多目标多规则:
显示规则中一条规则可以有多个目标,多个目标可以是相互独立的,也可以是组合起来的。
独立多目标:相互独立的多个目标与依赖之间用:,独立多目标每个目标在更新的时候都需要调用一次方法。 应用场景: (1)只需要写目标和依赖,不需要写方法。
(2)生成目标的方法写法一样,但是依赖与目标不一样 图1中生成.o目标的方法都一样,为g++ -c %.cpp(以.cpp结尾的文件),如果不考虑依赖源文件进行更新的话,图1中的内容可以写成图2,subst是一个字符串替换,(subst .o,.cpp,$@)意为将目标名称中的.o文件替换为.cpp文件。
目标与依赖不一样但是方法的写法一致,就可以写成独立多目标的形式。
组合多目标:目标与依赖之间用&:,组合多目标调用一次方法即可以更新所有目标。所有的目标更新方法都写到一起,每次更新只会调用一次。
一般组合多目标的方法不会对所有的目标都更新,它会把目标当成一个整体只更新一次。如下图:
补充:如果所有的目标更新方法都写到一起,每次更新也只会调用一次。如下图为想要对每个目标都进行更新,把每个方法都写进去之后它会分别对每个目标更新一次。
同一目标多条规则:
同一目标的所有规则中的依赖会被合并。但如果同一目标对应的多条规则都写了更新方法,则会使用最新的一条更新方法,并且会输出警告信息。
执行结果:(1)会报warning,提示你all这个目标的旧规则已经被忽略,新的规则覆盖了旧的规则; (2)合并依赖,输出新的依赖对应的方法执行后的结果。
如果一个目标对应了多条规则,则只会执行最后一个规则的方法,对应的多条依赖会合并。 同一目标多条规则可以用于需要给一个目标添加新的依赖但是又不想改变它前面已经写好的规则,此时第二条规则可以不写方法,目标会自动执行前面规则的方法。
上图的例子中删除了新依赖的方法,输出结果如图,会自动执行原来已经写好的方法,不会报warning。
静态模式:
独立多目标可以简化makefile的书写,但是无法将各个目标的依赖分开,让每一个目标文件根据自己的依赖进行更新。静态模式可以一定程度上改进独立多目标的依赖问题。 静态模式使用 % 来推导出对应的依赖。
如上图中,第270行,block.tcl表示目标,%.tcl表示目标模式,%.v和%.h都表示依赖模式 工具对于第270行的推导结果等同于第274行,即推导出block.tcl这个目标的依赖是block.v block.h。 执行结果为block.v。
如下图,如果有多个独立目标,需要更新其中一个目标的话,在依赖部分就只需要写上该目标对应的依赖写法,在执行时会更新该目标,对其他目标会报warning。
条件判断:
条件判断指令是让Makefile跳过或者执行文件中的某一部分内容。
ifdef判断一个变量是否已定义,如下图使用ifdef判断变量version是否已被定义,打印出已被定义的值。
也可以多添加几层嵌套: