在 Makefile 中,变量是一个名字(像是 C 语言中的宏),代表一个文本字符串(变量的值)。在 Makefile 的目标、依赖、命令中引用变量的地方,变量会被它的值所取代(与 C 语言中宏引用的方式相同,因此其他版本的 make 也把变量称之为“宏”)。在Makefile 中变量有以下几个特征:

  1. Makefile 中变量和函数的展开 (除规则命令行中的变量和函数以外),是在 make读取 makefile 文件时进行的,这里的变量包括了使用“ =”定义和使用指示符“ define”定义的。

  2. 变量可以用来代表一个文件名列表、编译选项列表、程序运行的选项参数列表、搜索源文件的目录列表、编译输出的目录列表和所有我们能够想到的事物。

  3. 变量名是不包括“ :”、“ #”、“ =”、前置空白和尾空白的任何字符串。需要注意的是,尽管在GNU make中没有对变量的命名有其它的限制,但定义一个包含除字母、数字和下划线以外的变量的做法也是不可取的,因为除字母、数字和下划线以外的其它字符可能会在make的后续版本中被赋予特殊含义,并且这样命名的变量对于一些shell来说是不能被作为环境变量来使用的。

  4. 变量名是大小写敏感的。变量“ foo”、“ Foo”和“ FOO”指的是三个不同的变量。 Makefile 传统做法是变量名是全采用大写的方式。推荐的做法是在对于内部定义定义的一般变量(例如:目标文件列表 objects)使用小写方式,而对于一些参数列表(例如:编译选项 CFLAGS)采用大写方式,但这并不是要求的。但需要强调一点:对于一个工程,所有 Makefile 中的变量命名应保持一种风格,否则会显得你是一个蹩脚的程序员(就像代码的变量命名风格一样)。

  5. 另外有一些变量名只包含了一个或者很少的几个特殊的字符(符号)。称它们为自动化变量。像“ $<”、“ $@”、“ $?”、“ $*”等。

  当我们定义了一个变量之后,就可以在 Makefile 的很多地方使用这个变量。变量的引用方式是:“ $( VARIABLE_NAME)”或者“ ${ VARIABLE_NAME }”来引用一个变量的定义。例如:“ $(foo) ”或者“ ${foo}”就是取变量“ foo”的值。

  美元符号“ $”在 Makefile 中有特殊的含义,所有在命令或者文件名中使用“ $”时需要用两个美元符号“ $$”来表示。

  注意: Makefile 中在对一些简单变量的引用,我们也可以不使用“()”和“ {}”来标记变量名,而直接使用“ $x”的格式来实现,此种用法仅限于变量名为单字符的情况。另外自动化变量也使用这种格式。对于一般多字符变量的引用必须使用括号了标记,否则 make 将把变量名的首字母作为作为变量而不是整个字符串 (“ $PATH”在 Makefile中实际上是“ $(P)ATH”)。这一点和 shell 中变量的引用方式不同。 shell 中变量的引用可以是 “ ${xx}”或者“ $xx”格式。但在 Makefile 中多字符变量名的引用只能是 “ $(xx)”或者“ ${xx}”格式。

  第一种风格的变量是递归方式扩展的变量。这一类型变量的定义是通过“ =”或者使用指示符“ define”定义的。这种变量的引用,在引用的地方是严格的文本替换过程,此变量值的字符串原模原样的出现在引用它的地方。如果此变量定义中存在对其他变量的引用,这些被引用的变量会在它被展开的同时被展开。就是说在变量定义时,变量值中对其他变量的引用不会被替换展开;而是变量在引用它的地方替换展开的同时,它所引用的其它变量才会被一同替换展开。

  为了避免“递归展开式”变量存在的问题和不方便。 GNU make 支持另外一种风格的变量,称为“直接展开”式。这种风格的变量使用“ :=”定义。在使用“ :=”定义变量时,变量值中对其他量或者函数的引用在定义变量时被展开(对变量进行替换)。所以变量被定义后就是一个实际需要的文本串,其中不再包含任何变量的引用。

  GNU make 中,还有一个被称为条件赋值的赋值操作符“ ?=”。被称为条件赋值是因为:只有此变量在之前没有赋值的情况下才会对这个变量进行赋值。

  

  通常,一个通用变量在定义之后的其他一个地方,可以对其值进行追加。这是非常有用的。我们可以在定义时(也可以不定义而直接追加)给它赋一个基本值,后续根据需要可随时对它的值进行追加(增加它的值)。在 Makefile 中使用“ +=”(追加方式)来实现对一个变量值的追加操作。

  通常在执行 make 时,如果通过命令行定义了一个变量,那么它将替代在 Makefile中出现的同名变量的定义。就是说,对于一个在 Makefile 中使用常规方式(使用“ =”、“ :=”或者“ define”)定义的变量,我们可以在执行 make 时通过命令行方式重新指定这个变量的值,命令行指定的值将替代出现在 Makefile 中此变量的值。如果不希望命令行指定的变量值替代在 Makefile 中的变量定义,那么我们需要在 Makefile 中使用指示符“ override”来对这个变量进行声明,变量在定义时使用了“ override”,则后续对它值进行追加时,也需要使用带有“ override”指示符的追加方式。否则对此变量值的追加不会生效。

定义变量的另外一种方式是使用“ define”指示符。它定义一个包含多行字符串的变量,我们就是利用它的这个特点实现了一个完整命令包的定义。

   define”定义变量的语法格式:以指示符“ define”开始,“ endif”结束,之间的所有内容就是所定义变量的值。所要定义的变量名字和指示符“ define”在同一行,使用空格分开;指示符所在行的下一行开始一直到“ endif”所在行的上一行之间的若干行,是变量值。        define two-lines

       echo foo

       echo $(bar)

       endef

  如果将变量“ two-lines”作为命令包执行时,其相当于:

     two-lines = echo foo; echo $(bar)

  使用“ define”定义的变量和使用“ =”定义的变量一样,属于“递归展开”式的变量,两者只是在语法上不同。因此“ define”所定义的变量值中,对其它变量或者函数引用不会在定义变量时进行替换展开,其展开是在“ define”定义的变量被展开的同时完成的。

sds

GNU make使用变量⑤变量的引用、定义等的更多相关文章

  1. 【转】变量的声明和定义,从C到编译原理到C++,再到Java

    基础学了太久,时间一长有些东西就可能记得不太清楚,俗话说得好,"好记性不如烂笔头",所以把基础中的基础-变量的声明和定义,从C到编译原理到C++,再到Java用烂笔头记录下来 最早 ...

  2. PHP 7: PHP 变量和常量的定义

    原文:PHP 7: PHP 变量和常量的定义 本章说说变量的定义.如果对于变量和常量的定义,你会注意几个方面呢?你可能会想到: 如何定义变量,它和C# 等语言有什么不同呢? 变量区分大小写吗? PHP ...

  3. 变量的声明和定义以及extern的用法

    变量的声明和定义以及extern的用法                                          变量的声明不同于变量的定义,这一点往往容易让人混淆. l         变量 ...

  4. 继承的基本概念: (1)Java不支持多继承,也就是说子类至多只能有一个父类。 (2)子类继承了其父类中不是私有的成员变量和成员方法,作为自己的成员变量和方法。 (3)子类中定义的成员变量和父类中定义的成员变量相同时,则父类中的成员变量不能被继承。 (4)子类中定义的成员方法,并且这个方法的名字返回类型,以及参数个数和类型与父类的某个成员方法完全相同,则父类的成员方法不能被继承。 分析以上程

    继承的基本概念: (1)Java不支持多继承,也就是说子类至多只能有一个父类. (2)子类继承了其父类中不是私有的成员变量和成员方法,作为自己的成员变量和方法.(3)子类中定义的成员变量和父类中定义的 ...

  5. 面试题:使用finalkeyword修饰一个变量时,是引用不能变,还是引用的对象不能变?

    /* * 问题:使用finalkeyword修饰一个变量时,是引用不能变,还是引用的对象不能变 * 答: * 使用finalkeyword修饰一个变量时,是指引用变量不能变,引用变量所指向的对象中的内 ...

  6. php面试专题---1、php中变量存储及引用的原理

    php面试专题---1.php中变量存储及引用的原理 一.总结 一句话总结: 查看变量的存储结构可以安装xdebug扩展,用xdebug_debug_zval()方法,不推荐使用memory_get_ ...

  7. Java并发之原子变量和原子引用与volatile

    我们知道在并发编程中,多个线程共享某个变量或者对象时,必须要进行同步.同步的包含两层作用:1)互斥访问(原子性):2)可见性:也就是多个线程对共享的变量互斥地访问,同时线程对共享变量的修改必须对其他线 ...

  8. c#变量缺少using引用,如何快速加上using,加Using的快捷键[bubuko.com]

    在vs的“工具”->“选项”中,左侧树形菜单,“环境”下的“键盘”中设置快捷键. 在“显示命令包含”输入框内输入“显示智能标记”,找到“视图.显示智能标记”,可以看到该命令的快捷键已经分配了2个 ...

  9. php入门变量之变量的间接引用、连接字符串和连接赋值运算符

    [1]变量的间接引用: <?php $a = 'b'; $$a = '123'; echo $b; ?> 上面的输出结果是123 我们可以看到在第二行代码中多了一个$,并通过指定的名称访问 ...

随机推荐

  1. 【linux草鞋应用编程系列】_2_ 环境变量和进程控制

    一. 环境变量     应用程序在执行的时候,可能需要获取系统的环境变量,从而执行一些相应的操作.     在linux中有两种方法获取环境变量,分述如下.   1.通过main函数的参数获取环境变量 ...

  2. 深入研究Java类装载机制

    目录 1.为什么要研究java类装在机制? 2.了解类装载机制,对于我们在项目开发中有什么作用? 3.装载实现细节. 4.总结 一.为什么药研究Java类装载机制 java类加载机制,便于我们使用自定 ...

  3. Manage application.conf in several environments

    When you work in a team, different developers will use different configuration keys in theirapplicat ...

  4. javascript 模式(1)——代码复用

    程序的开发离不开代码的复用,通过代码复用可以减少开发和维护成本,在谈及代码复用的时候,会首先想到继承性,但继承并不是解决代码复用的唯一方式,还有其他的复用模式比如对象组合.本节将会讲解多种继承模式以实 ...

  5. DrawSVG - SVG 路径动画 jQuery 插件

    jQuery DrawSVG 使用了 jQuery 内置的动画引擎实现 SVG 路径动画,用到了 stroke-dasharray 和 stroke-dashoffset 属性.DrawSVG 是完全 ...

  6. 原生js使用forEach()与jquery使用each遍历数组,return false 的区别

    原生js使用forEach()与jquery使用each()遍历数组,return false 的区别: 1.使用each()遍历数组a,如下: var a=[20,21,22,23,24]; $.e ...

  7. 网络分析之networkx(转载)

    图的类型 Graph类是无向图的基类,无向图能有自己的属性或参数,不包含重边,允许有回路,节点可以是任何hash的python对象,节点和边可以保存key/value属性对.该类的构造函数为Graph ...

  8. CLR线程概览(一)

    托管 vs. 原生线程 托管代码在“托管线程”上执行,(托管线程)与操作系统提供的原生线程不同.原生线程是在物理机器上执行的原生代码序列:而托管线程则是在CLR虚拟机上执行的虚拟线程. 正如JIT解释 ...

  9. Windows 8.1 低功耗蓝牙开发

    1. 概述 在蓝牙4.0发布以前,给大家的直观印象就是蓝牙耳机,它就是用来满足短距离内中等带宽的音频通信需求.然而蓝牙4.0发布之后,用途就大不一样了,特别是现在物联网和可穿戴之风盛行的年代,很多小玩 ...

  10. ORA-01102: cannot mount database in EXCLUSIVE mode

    安装完ORACEL 10g数据库后,启动数据库时遇到ORA-01102: cannot mount database in EXCLUSIVE mode [oracle@DB-Server ~]$ s ...