变量的定义

makefile中的变量,与C语言中的宏类似,它为一个文本字符串(变量的值,其类型只能是字符串类型)提供了一个名字(变量名)。

变量的基本格式:

变量名   赋值符   变量值

变量名指的就是该变量的名字,是不包括“:”、“#”、“=”、前置空白和尾空白的任何字符串。需要注意的是,尽管在GNU make中没有对变量的命名有其它的限制,但定义一个包含除字母、数字和下划线以外的变量的做法也是不可取的,因为除字母、数字和下划线以外的其它字符可能会在以后的make版本中被赋予特殊含义,并且这样命名的变量对于一些shell来说不能作为环境变量使用。变量名是大小写敏感的。变量“foo”、“Foo”和“FOO”指的是三个不同的变量。Makefile传统做法是变量名是全采用大写的方式。推荐的做法是在对于内部定义定义的一般变量(例如:目标文件列表objects)使用小写方式,而对于一些参数列表(例如:编译选项CFLAGS)采用大写方式。

变量值,指的是变量所代表的内容,可以是一个文件名列表、编译选项列表、程序运行的选项参数列表、搜索源文件的目录列表、编译输出的目录列表和所有我们能够想到的事物。变量的值,其本质就是一个字符串。

赋值符,有= 、 := 、 ?=和 +=四种格式,其中= 和 := 为基本定义类型, ?=和 +=为基于=的扩展定义类型。

一个在makefile中定义变量的例子:

  objects = program.o foo.o utils.o

变量的引用

当我们定义了一个变量之后,我们就可以在makfile中的目标、依赖、命令中引用我们的变量;而所谓的变量引用,就是在引用变量名的地方,用变量所代表的内容,执行一个严格的文本替换过程(该过程也称为变量被展开的过程 ),替换掉变量的名字。

变量的引用有以下几种方式:

${变量名}

$(变量名)

$单字符变量名 ,变量名仅包含一个字符,如$@ 、$^等

一个在makefile中引用变量的例子:

# 变量定义
objects = program.o foo.o utils.o program : $(objects) #在依赖中引用变量
gcc -o program ${objects} #在命令中引用变量 $(objects) : defs.h #在目标中引用变量

变量的分类与赋值

根据变量定义时所使用的赋值操作符的不同,可以将变量分成两种类型(或者说是两种风格):

递归展开式变量和直接展开式变量;

使用赋值操作符= 、 += 和 ?=定义的变量都是递归展开式变量,使用赋值操作符 :=定义的变量为直接展开式变量

两种变量类型的的最根本区别在于:变量值的求值时机,递归式变量的求值时机在于变量被引用时,直接展开式的求值时机在于变量被定义时。

由于变量foo1的变量值是在执行echo命令时才求的值,所以foo1的值被递归的展开为Huh?; 而变量foo2的变量值在定义时就被求值了,此时由于变量bar的值为空,因此foo2的值也为空。

注意:使用递归展开式的变量定义,可能会由于出现变量的递归定义而导致make陷入到无限的变量展开过程中,最终使make执行失败。

+= 和 ?=是基于=扩展而来的两种变量赋值操作符;

+= 称为追加赋值操作符,它实现对于一个已经存在定义的变量进行追加赋值,如下例子:

?=称为条件赋值的赋值操作符,被称为条件赋值为:只有此变量在之前没有赋值的情况下才会对这个变量进行赋值。看一下例子:

特殊的变量

在makefile 中用户除了可以自定义变量外,还可以使用make工具为我们提供的一些特殊的变量及用法。

自动化变量:

所谓自动化变量,就是在每条规则中,make自动为我们提供的用于指定规则各个组成部分的变量,一般情况下常用的有以下几个自动化变量:

$@ -- 代表规则中的目标文件名

$< -- 代表规则的第一个依赖的文件名

$^ -- 代表规则中所有依赖文件的列表,文件名用空格分割

说明:

$字符在makefile中有特殊用途,因此如果要取消其特殊用途当成一个普通字符传递给echo命令执行,需要使用$$

$@在bash shell中也有特殊用途,因此如果希望echo命令在bash中正常输出$@, 需要加上\字符

该makefile的最后一行first second third: 看起来有点奇怪,这是一条没有依赖和命令的多目标规则,读者可自行将它删除看有什么效果,并思考原因。

变量的替换引用

变量的分类与赋值

对于一个已经定义的变量,可以使用“替换引用”将其值使用指定的字符(字符串)进行替换。格式为$(VAR:A=B)或者${VAR:A=B},意思是,将变量“VAR”所表示的值中所有字符串“A”结尾的字符替换为“B”的字。“结尾”的含义是空格之前(变量值的多个字以空格分开)。而对于变量其它部分的“A”字符不进行替换。例如:

在这个定义中,变量“objects”的值就为“a.c b.c c.c d.d”。使用变量的替换引用将变量“sources”以空格分开的值中的所有的字的尾字符“o”替换为“c”,其他部分不变,注意这里的d.d并不会被替换。

使用变量修改前面的makefile

#define variable of executable file
executable := complicated #define variable of source document
sources := main.c complicated.c #using repalce with a reference to a variable
#and define the 'object' file list
objects := $(sources:.c=.o) #Define compile command variables
CC := gcc #Ultimate goal rule,generating complicate executor
$(executable):$(objects)
#using an automated variable to transfer compilation command
$(CC) -o $@ $^ #subrule to generate main.o
main.o : main.c
$(CC) -o $@ -c $< #subrule to generate complicated.o
complicated.o : complicated.c
$(CC) -o $@ -c $<

一起学Makefile(四)的更多相关文章

  1. Mina、Netty、Twisted一起学(四):定制自己的协议

    在前面的博文中,介绍一些消息分割的方案,以及MINA.Netty.Twisted针对这些方案提供的相关API.例如MINA的TextLineCodecFactory.PrefixedStringCod ...

  2. 从头开始学JavaScript (四)——操作符

    原文:从头开始学JavaScript (四)--操作符 一.一元操作符 1.自增自减操作符:分为前置型和后置型: 前置型:++a;--a; 后置型:a++;a--; 例: <script typ ...

  3. 跟我学Makefile(三)

    紧接着跟我学Makefile(二)继续学习:变量高级用法 (1)变量值的替换 :替换变量中的共有的部分,其格式是“$(var:a=b)”或是“${var:a=b}”,把变量“var”中所有以“a”字串 ...

  4. 跟我学Makefile(四)

    使用函数:函数调用,很像变量的使用,也是以“$”来标识的,其语法如下: $(<function> <arguments>) 或是 ${<function> < ...

  5. 一起学makefile

    Unix.Linux必学知识哈哈,网上看到一哥们写得挺好挺详细的,直接复制地址就分享哈哈哈. 跟我一起写 Makefile(一) 概述 跟我一起写 Makefile(二) make是如何工作的 跟我一 ...

  6. 跟我学Makefile(七)

    定义模式规则 使用模式规则来定义一个隐含规则.一个模式规则就好像一个一般的规则,只是在规则中,目标的定义需要有“%”字符.“%”的意思是表示一个或多个任意字符.在依赖目标中同样可以使用“%”,只是依赖 ...

  7. 跟我一起学Makefile

    概述 什么是makefile?或许很多Winodws程序员都不知道这个东西,因为那些Windows IDE都为你做了这个工作,但我觉得要做一个好的和professional的程序员,makefile还 ...

  8. 跟我学Makefile(六)

    shell 函数 :和反引号“`”是相同的功能 . shell 函数把执行操作系统命令后的输出作为函数返回. contents := $(shell cat foo) files := $(shell ...

  9. 跟我一起写Makefile(四)

    书写命令———— 每条规则中的命令和操作系统Shell的命令行是一致的.make会一按顺序一条一条的执行命令,每条命令的开头必须以[Tab]键开头,除非,命令是紧跟在依赖规则后面的分号后的.在命令行之 ...

随机推荐

  1. oracle 根据字段分组取第一条数据及rank函数说明

    当前有这样一个需求,根据外键对子表数据进行分组,取每组中的一条数据就行了,如图: 如:COMMANDID = 26的有两条,只取一条数据. sql语句: select * from(select SY ...

  2. Java可视化计算器

    利用java中的AWT和SWING包来做可视化界面. 首先来简单了解一下这两个包: AWT和Swing都是Java中用来做可视化界面的.AWT(Abstract Window Toolkit):抽象窗 ...

  3. Google Chrome 浏览器JS无法更新解决办法

    JS无法更新原因: 浏览器为了加载快,默认是按照自定规则更新缓存,非实时更新. 我们在开发的时候,JS变动很快,需要即时让浏览器加载最新文件,也就是禁用浏览器缓存 (1)使用F12进入开发者模式,找到 ...

  4. DevExpress之GridControl控件小知识

    DevExpress之GridControl控件小知识 一.当代码中的DataTable中有建数据关系时,DevExpress 的 GridControl 会自动增加一个子视图 .列名也就是子表的字段 ...

  5. win10环境变量PATH——路径添加

    我的电脑---->属性---->环境变量---->系统变量,选择path,点击“编辑”,“新建”,然后将路径添加上去即可

  6. Java的Stream流式操作

    前言 最近在实习,在公司看到前辈的一些代码,发现有很多值得我学习的地方,其中有一部分就是对集合使用Stream流式操作,觉得很优美且方便.所以学习一下Stream流,在这里记录一下. Stream是什 ...

  7. centos从零开始安装elasticSearch

    前言:elasticSearch作为一款优秀的分布式搜索工具,被广泛用在数据搜集和整理的业务中,知名的比如有github就是采用es来精准的搜索几千万行代码,百度也大量应用es做数据爬取分析,本篇博客 ...

  8. vue-cli2和3中的config

    最近在网上找了个vue搭建的后台管理的框架,在使用的时候发现没有了config和build文件夹,所以当时就蒙圈了,以为是作者自己改了什么东西,所以感觉自己不知道从何下手了,不过通过查资料发现原来是v ...

  9. jquery问题,如何调用带this的函数?

    这样写: 1 2 3 4 5 6 7 8 9 10 11 12 $(".aa").on("mouseout",function(){     var obj = ...

  10. select用法 多并发处理

    select默认最大检查套接口数量是1024,有定义 #define __NFDBITS (8 * sizeof(unsigned long)) #define __FD_SETSIZE 1024 # ...