Makefile学习之路——4
变量的类别有递归扩展变量和简单扩展变量。只用一个“=”符号定义的变量被称为递归扩展变量。通过下面例子观察递归扩展变量的特点。
.PHONY: all foo=$(bar)
bar=$(ugh)
ugh=Huh? all:
@echo $(foo)

从结果来看,递归扩展变量的引用是递归的。
.PHONY: all x=foo;
y=$(x) b
x=later xx:=foo
yy:=$(xx) b
xx:=later all:
@echo "X=$(y), xx=$(yy)"

递归和简单扩展变量相比的差距应该看出来了吧。递归相当于c++中的引用,而简单扩展变量make只对其进行一次展开。
下面对于同一个变量采取不同的赋值操作,看看会有什么效果。
.PHONY: all objs=main.o foo.o bar.o utils.o
objs:=$(objs) another.o all:
@echo $(objs)

如果把第二个简单扩展变量变成递归的即
objs=$(objs) another.o
make会报错

makefile:4:***递归变量'objs'引用本身(最终)。看来想引用自身的递归变量,编译器不会允许这样的行为。
在Makefile中还可以实现条件赋值:当变量没有被定义时就定义它,并且将右边的值赋值给它,如果变量已经定义了,则不改变其原值。条件赋值可用于为变量赋默认值。条件赋值运用“?=”来实现。下面用条件赋值运行一个Makefile:
.PHONY: all foo=x
foo?=y bar?=y
all:
@echo "foo=$(foo),bar=$(bar)"

foo已经定义,故保持原样,bar未定义,故把右侧数据赋值给bar。
另外一个非常有用的赋值方法是通过“+=”实现追加赋值:
.PHONY: all objs=main.o foo.o bar.o utils.o
objs +=another.o
all:
@echo $(objs)

变量及其值的来源
从前面的示例可以看出,在Makefile中可以对变量进行定义。此外,还有其他的方式让make获得变量。比如:
(1)对于自动变量,其值是在每一个规则中根据上下文自动获得的
(2) 在运行make时,通过命令参数定义变量。如果以make bar=x的形式运行它,得到的结果则完全不同。从结果可以看出,在运行make的命令参数中定义的变量在Makefile中是可见的。其实完全可以通过make命令行中定义变量的方式覆盖Makefile文件中所定义变量的值。

(3)变量还可以来自shell环境,采用shell中的export命令定义一个bar变量之后运行Makefile。
export命令:设置或显示环境变量,具体用法请查看linux命令手册。

高级变量引用功能:
下面示例说明了变量引用的一种高级功能,即在赋值的同时完成文件名后缀替换操作。
.PHONY: all foo = a.c b.c c.c
bar :=$(foo:.c=.o) all:
@echo "bar= $(bar)"

但是需要注意,$(foo:.c=.o)中,foo:.c在":"和 "."之间不能有空格,有空格将使后缀替换失败,$(foo:.c=.o),相当于把foo变量后缀为.c的全部替换成.o的。
.PHONY: all foo = a.c b.c c.c d.d
bar :=$(foo:.c=.o) all:
@echo "bar= $(bar)"

可以看到,d.d并没被替换,只是替换后缀为.c的。
避免变量被覆盖的方法:
我们在设计Makefile时,可能并不希望发生变量被覆盖的现象,此时需要使用override指令进行限制。
.PHONY: all override foo=x
foo=y all:
@echo "foo= $(foo)"

借助“模式”精简规则:
对于目前simple项目的Makefile,其中存在多个规则用于构建目标文件。 比如main.o 和foo.o,都是采用不同的规则进行描述的。如果对于每一个目标文件,都得写一个不同的规则来描述,那真是一种体力活。Makefile中的模式就是用来解决这个问题的。

.PHONY: clean CC = gcc
RM = rm EXE =simple
OBJS =main.o foo.o $(EXE): $(OBJS)
$(CC) -o $@ $^
11 #main.o:main.c\
12 $(CC) -o $@ -c $^\
13 foo.o:foo.c\
14 $(CC) -o $@ -c $^ 被屏蔽的代码段
%.o : %.c
$(CC) -o $@ -c $^
clean:
$(RM) -rf $(EXE) $(OBJS)

与前一个版本的相比,最为直观的改变就是将两条用于构建目标文件的规则变成了一条。模式类似与Windows操作系统中所使用的通配符,用“%”加以表示。采用了模式之后,无论有多少个源文件要编译都可以使用同一条规则,这极大地简化了Makefile。
同样,"%" 和"."之间不能有空格。还有一点,上面的代码使用了Makefile中的#加上反斜杠\的注释方式,是为了凸显和之前版本Makefile的差别。
Makefile学习之路——4的更多相关文章
- Makefile学习之路——2
让你的makefile更专业. 在上一个Makefile所在目录下通过touch命令创建一个clean文件,执行make clean,将发现make总是提示clean文件是最新的,而不是按我们期望的那 ...
- Makefile学习之路——3
特殊变量: 在Makefile中,有两个变量特殊变量会经常用到:MAKE和MAKECMDGOALS.MAKE变量表示的是当前处理Makefile的命令名是什么.当需要在Makefile中运行另一个Ma ...
- Makefile学习之路——1
编写makefile,不是一个猛子扎进去试着写一个规则并对之调试,而应该先采用面向依赖关系的思考方法勾勒出makefile要表达怎样的依赖关系,这一点尤为重要.通过不断地练习这种思考方法,才可能达到流 ...
- Makefile学习之路6——让编译环境更加有序
在大多项目中都会合理设计目录结构来提高维护性,在编译一个项目时会产生大量中间文件,如果中间文件直接和源文件放在一起,就显得杂乱而不利于维护.在为现在这个complicated项目编写makefile之 ...
- Makefile学习之路5——通过函数增强功能
通过函数能显著增强Makefile的功能.对于simple项目的Makefile,尽管使用了模式规则,但还是有一件比较麻烦的事情,就是要在Makefile中指明每一个项目源文件.下面介绍几个后期会使用 ...
- 运用Autoconf和Automake生成Makefile的学习之路
作为Linux下的程序开发人员,大家一定都遇到过Makefile,用make命令来编译自己写的程序确实是很方便.一般情况下,大家都是手工写一个简单Makefile,如果要想写出一个符合自由软件惯例的M ...
- Qt 学习之路 2(7):MainWindow 简介
Qt 学习之路 2(7):MainWindow 简介 豆子 2012年8月29日 Qt 学习之路 2 29条评论 前面一篇大致介绍了 Qt 各个模块的相关内容,目的是对 Qt 框架有一个高屋建 ...
- Qt 学习之路 2(3):Hello, world!
豆子 2012年8月22日 Qt 学习之路 2 107条评论 想要学习 Qt 开发,首先要搭建 Qt 开发环境.好在现在搭建 Qt 开发环境还是比较简单的.我们可以到 Qt 官方网站找到最新版 ...
- jQuery学习之路(1)-选择器
▓▓▓▓▓▓ 大致介绍 终于开始了我的jQuery学习之路!感觉不能再拖了,要边学习原生JavaScript边学习jQuery jQuery是什么? jQuery是一个快速.简洁的JavaScript ...
随机推荐
- python之函数用法execfile()
# -*- coding: utf-8 -*- #python 27 #xiaodeng #python之函数用法execfile() #execfile() #说明:用来执行一个文件,相对于双击的效 ...
- redis编译
简介: Redis是Nosql中比较出名的,分布式数据库缓存,提升相应的速度,降低对数据库的访问! Redis是一种高级key-value数据库.它跟memcached类似,不过数据可以持久化,(永久 ...
- 利用 AFN 上传相册或拍照图片
概述 自定义上传图片请求,自定义调取相册及拍照,方便多处使用时调用. 详细 代码下载:http://www.demodashi.com/demo/10718.html 由于项目中多处需要上传图片,我们 ...
- [Table] pm_result
', '20160501.17:30 - 20160501.17:45', '2.1', '3.1', '3.1', '3.11', '3.44', '12.30', null, null, null ...
- 小白心目中的Java抽象类(abstract class)
在java开发中,我们有时会定义了一个父类,这个父类只有对方法的描述,但却没有在父类中写出对方法的实现,这种被定义的方法称为抽象方法.那么理所当然,含有抽象方法的类就称为抽象类.用关键字abstrac ...
- Bugtags 让你的 APP 测试轻松、上线安心
Bug 管理系统再进化 Bugtags 的创业团队,在过去几年,做了很多方向的尝试——没错,是开发了很多 APP. 每一轮迭代,都会被繁琐的 APP 测试困扰:无休止的截屏上传电脑,无数次的开发与测试 ...
- TortoiseSVN 清空已保存的用户信息
http://blog.csdn.net/zb358983019/article/details/72898231.如果使用的是安装版的SVN,则打开系统开始菜单中Tortoise下的Settings ...
- js时间戳转成日期格式
将时间戳转换成日期格式:// 简单的一句代码var date = new Date(时间戳); //获取一个时间对象 注意:如果是uinx时间戳记得乘于1000.比如php函数time()获得的时间戳 ...
- iOS拦截导航栏返回按钮事件的正确方式
当我们使用了系统的导航栏时,默认点击返回按钮是 pop 回上一个界面.但是在有时候,我们需要在点击导航栏的返回按钮时不一定要 pop 回上一界面,比如一个视频播放界面,进入横屏后,默认点击返回按钮仍然 ...
- surging+CentOS7+docker+rancher2.0 菜鸟部署运行笔记
https://blog.csdn.net/q5934/article/details/82661250 目录 准备工作 开始干活 1.从github 获取surging源码 2.发布Surging. ...