我们在前面学习了 makefile 中的相关知识,今天我们来看看在 makefile 中变量值的替换。它的替换是指使用指定字符(串)替换变量值中的后缀字符(串),语法格式为:$(var:a=b) 或 ${var:a=b}。注意:a> 替换表达式中不能有任何的空格;b> make 中支持使用 ${ } 对变量进行取值。格式如下
还有种便是变量的模式替换是指使用 % 保留变量值中的指定字符,替换其他字符。语法格式为:$(var:a%b=x%y) 或 ${var:a%b=x%y}。注意:a> 替换表达式中不能有任何的空格;b> make 中支持使用 ${ } 对变量进行取值。格式如下
规则中的模式替换如下
它的意义是通过 target-pattern 从 targets 中匹配子目标;再通过 prereq-pattern 从子目标生成依赖;进而构成完整的规则。我们来看看规则中的模式替换示例如下
下来我们通过代码来分析说明
src1 := a.cc b.cc c.cc obj1 := $(src1:cc=o) test1 : @echo "obj1 => $(obj1)" src2 := a11b.c a22b.c a33b.c obj2 := $(src2:a%b.c=x%y) test2 : @echo "obj2 => $(obj2)"
我们根据之前说的,在 obj1 中将会把 .cc 替换成 .o,把 obj2 中的 a11b.c a22b.c a33b.c 替换成 x11y x22y x33y。我们来看看编译器效果
我们看到结果和我们分析的是一样的。下来再来看看模式替换,将之前的 makefile 进行改编
CC := g++ TARGET := hello-makefile.out OBJS := func.o main.o $(TARGET) : $(OBJS) $(CC) -o $@ $^ $(OBJS) : %.o : %.c $(CC) -o $@ -c $^ .PHONY : rebuild clean all rebuild : clean all all : $(TARGET) clean : $(RM) *.o $(TARGET)
我们来看看编译效果和之前的是一样的吗?
结果是一样的,这样的写的意义在哪呢?在大型的工程项目中,.c源文件是成千上万的。我们就可以利用模式替换来代替重复的工作,比如我们想添加一个 const.c 文件,便可以直接在第 3 行直接加上 const.o 就OK了。我们来试试看
const.c 源码
const char* g_hello = "hello makefile";
func.c 源码
#include "stdio.h" extern char* g_hello; void foo() { printf("void foo() : %s\n", g_hello); }
main.c 源码
extern void foo(); int main() { foo(); return 0; }
我们来看看编译效果
我们看到在编译的时候自动加上了编译 const.c 的命令,并最终正确打印出结果。这样感觉是不是很方便哈。那么在 makefile 中变量值还可以嵌套引用,就是一个变量名之中可以包含对其它变量的引用,嵌套引用的本质是使用一个变量来表示另外一个变量。格式如下
下来我们来说说命令行变量,在运行 make 时直接在命令行定义变量。命令行变量默认覆盖 makefile 中定义的变量,格式如下
那么命令行变量可以覆盖 makefile 中定义的变量,如果我们不小心手误覆盖了呢?这时 override 关键字就登场了。它是用于指示 makefile 中定义的变量不能被覆盖,变量的定义个赋值都需要使用 override 关键字。格式如下
下来我们来看看 makefile 中的 define 关键字,它是用于在 makefile 中定义多行变量,多行变量的定义从变量名开始带 endef 结束。可使用 override 关键字防止变量被覆盖,define 定义的变量等价于使用 = 定义的变量。格式入下
下来我们还是以代码为例来进行说明
hm := hello makefile override var := override-test define foo I'm fool! endef override define cmd @echo "run cmd ls ..." @ls endef test : @echo "hm => $(hm)" @echo "var => $(var)" @echo "foo => $(foo)" ${cmd}
我们来编译看看结果
我们看到在没有被 override 关键字修饰的变量 hm 可以在命令行对它进行改写,但是变量 cmd 因为被 override 修饰了,因此就在命令行里面的修改是无效的。下来我们还说说 makefile 中的环境变量(全局变量),在 makefile 中能够直接使用环境变量的值。它是在定义了同名变量的话,环境变量将被覆盖,运行 make 时指定“-e”选项,优先使用环境变量。那么为什么要在 makefile 中使用环境变量呢?它的优势是环境变量可以在所有的 makefile 中使用,劣势是过多的依赖于环境变量便会导致移植性降低。那么变量在不同的 makefile 支架的传递方式有哪些呢?a> 直接在外部定义环境变量进行传递;b> 使用 export 定义变量进行传递;c> 定义 make 命令进行传递(一般推荐使用这种)。
下来我们还是以代码为例来进行分析
export var := D.T.Software new := TDelphi test : @echo "make another file ..." @$(MAKE) -f makefile.4 @$(MAKE) -f makefile.4 new:=$(new)
makefile.4 源码
test : @echo "var => $(var)" @echo "new => $(new)"
我们来看看编译结果
我们看到在第一次的时候 new 为空,在第二次的时候 new 为我们设置的字符串。两次的 var 都传递过去了就是因为我们使用了 export 这个关键字。下来我们来看看目标变量(局部变量),其作用域只在指定目标及连带规则中。格式如下
那么模式变量便是目标变量的扩展,其作用域只在符合模式的目标及连带规则中。格式如下
下来还是以代码为例来进行分析说明
var := D.T.Software new := TDelphi test : var := test-var %e : override new := test-new test : another @echo "test :" @echo "var => $(var)" @echo "new => $(new)" another : @echo "another :" @echo "var => $(var)" @echo "new => $(new)" rule : @echo "rule :" @echo "var => $(var)" @echo "new => $(new)"
我们来看看编译结果
因为 %e 的匹配规则,所以在目标 rule 中,它的 new 为 test-new,凡是跟 test 目标相关的 var 都是 test-var。通过对 makefile 中变量的学习,总结如下:1、makefile 中的变量值能够嵌套引用;2、命令行中定义的变量能够覆盖 makefile 中定义的变量;3、override 用于提示 makefile 中定义的变量不能被覆盖;4、define 用于在 makefile 中定义值为多行的变量;5、makefile 中的三种变量:a> 全局变量是指 makefile 外部定义的环境变量;b> 文件变量是在 makefile 中定义的变量;c> 局部变量是指定目标的变量。
欢迎大家一起来学习 makefile,可以加我QQ:243343083。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。