一,定义多行变量
前面定义的变量都是单行的。
变量值有多行,多用于定义shell指令
语法
perldefine <varable_name> # 默认为 = # 变量内容 endef define <varable_name> := # 变量内容 endef define <varable_name> += # 变量内容 endef示例:
然后可以看到我们可以用define和endef来定义一个多行变量
二,取消变量
如果想清除一个变量,用以下方法
undefine <变量名> 如 undefine files, undefine objs
不难看到这样输出的就是Nothing to be done没有东西可以执行,那么就是表示执行成功,这里因为要强制将all输出出来,这里就把all设置为了伪目标。
三,环境变量的使用
系统中的环境变量可以直接在Makefile中直接使用,使用方法跟普通变量一样
perlall: @echo $(USERNAME) @echo $(JAVA_HOME) @echo $(SystemRoot)这样就可以使用环境变量了
四,变量替换引用
语法:$(var:a=b),意思是将变量var的值当中每一项结尾的a替换为b,直接上例子
perlfiles = main.cpp hello.cpp objs := $(files:.cpp=.o) # main.o hello.o # 另一种写法 objs := $(files:%.cpp=%.o)这样我们可以看到这样对于我们操作更简便了
五,变量覆盖
这样就可以将原先的变量进行覆盖
六,局部变量和全局变量
局部变量就是在前面加上对应的目标,这样就知道这个局部变量是从属于哪一个目标了,然后全局变量就是直接变量等于一直值就可以。
七,自动变量
$@:①本条规则的目标名;②如果目标是归档文件的成员,则为归档文件名;③在多目标的模式规则中, 为导致本条规则方法执行的那个目标名;
$<:本条规则的第一个依赖名称
$?:依赖中修改时间晚于目标文件修改时间的所有文件名,以空格隔开
$^:所有依赖文件名,文件名不会重复,不包含order-only依赖
$+:类似上一个, 表示所有依赖文件名,包括重复的文件名,不包含order-only依赖
$|:所有order-only依赖文件名
$*:(简单理解)目标文件名的主干部分(即不包括后缀名)
$%:如果目标不是归档文件,则为空;如果目标是归档文件成员,则为对应的成员文件名
以下变量对应上述变量,D为对应变量所在的目录,结尾不带/,F为对应变量除去目录部分的文件名
(@D) (@F)
(\*D) (*F)
(%D) (%F)
(\
(<F) (\^D) (^F)
(+D) (+F)
(?D) (?F)
八,二次展开
前面说过依赖中的变量都是在Makefile读取阶段立即展开的。如果想让依赖的的变量延迟展开,可以使用.SECONDEXPANSION:,添加之后,在依赖中使用变量时用
$$,可以让变量在第二阶段进行二次展开,从而达到延迟展开的效果。
perlVAR1 = main.cpp .SECONDEXPANSION: all: $$(VAR1) @echo $^ VAR1 = hello.cpp
九,多目标与多规则(简写)
显式规则中一条规则可以有多个目标,多个目标可以是相互独立的目标,也可以是组合目标,用写法来区分
独立多目标
相互独立的多个目标与依赖之间直接用
:,常用这种方式的有以下两种情况
只需要写目标和依赖,不需要写方法的时候
block.o input.o scene.o : common.h这种写法等价于
block.o : common.h input.o : common.h scene.o : common.h生成(更新)目标的方法写法一样的,只是依赖与目标不一样时。之前写的Makfile中,有如下代码:
block.o: block.cpp common.h block.h color.h g++ -c block.cpp command.o: command.cpp command.h scene.h g++ -c command.cpp input.o: input.cpp common.h utility.inl g++ -c input.cpp main.o: main.cpp scene.h input.h test.h g++ -c main.cpp scene.o: scene.cpp common.h scene.h utility.inl g++ -c scene.cpp test.o: test.cpp test.h g++ -c test.cpp所有.o文件的生成都用的同一方法
g++ -c <文件名>如果不考虑依赖源文件进行更新时,可以进行简写如下:
block.o command.o input.o main.o scene.o test.o : common.h block.h command.h ... g++ -c $(@:%.o=%.cpp)这种写法实际上等价于
block.o : common.h block.h command.h ... g++ -c $(@:%.o=%.cpp) command.o : common.h block.h command.h ... g++ -c $(@:%.o=%.cpp) input.o : common.h block.h command.h ... g++ -c $(@:%.o=%.cpp) main.o : common.h block.h command.h ... g++ -c $(@:%.o=%.cpp) scene.o : common.h block.h command.h ... g++ -c $(@:%.o=%.cpp) test.o : common.h block.h command.h ... g++ -c $(@:%.o=%.cpp)独立多目标虽然写在一起,但是每个目标都是单独调用一次方法来更新的。和分开写效果一样。
最后也可以是这种形式,多目标形式
这里就是利用隐式规则来判断,就是make他自己判断依赖文件是什么组合多目标
多目标与依赖之前用
&:,这样的多个目标称为组合目标。与独立多目标的区别在于,独立多目标每个目标的更新需要单独调用一次更新方法。而组合多目标调用一次方法将更新所有目标
block.o input.o scene.o &: block.cpp input.cpp scene.cpp common.h g++ -c block.cpp g++ -c input.cpp g++ -c scene.cpp所有目标的更新方法都写到其中,每次更新只会调用一次。
同一目标多条规则
同一目标可以对应多条规则。同一目标的所有规则中的依赖会被合并。但如果同一目标对应的多条规则都写了更新方法,则会使用最新的一条更新方法,并且会输出警告信息。
同一目标多规则通常用来给多个目标添加依赖而不用改动已写好的部分。
input.o: input.cpp utility.inl g++ -c input.cpp main.o: main.cpp scene.h input.h test.h g++ -c main.cpp scene.o: scene.cpp scene.h utility.inl g++ -c scene.cpp input.o main.o scene.o : common.h同时给三个目标添加了一个依赖common.h,但是不用修改上面已写好的部分。










