makefile(一):变量

来源:互联网 发布:arm linux 外设使用 编辑:程序博客网 时间:2024/06/05 18:04

makefile简介

对于linux来说,IDE环境并不多,就算有IDE也没有命令行好用。在这种情况下,没有ID E的帮助,要管理一个工程的编译是非常困难的,此时make工具诞生了。
make将管理一个工程的规则,写入文件中,然后,make读取这里面的规则,来决定如何编译一个工程(比如,那些文件先编译,那些文件后编译等)
那么这里面的重中之重就是规则了。下面来一个简单的规则文件。

main:main.c print.c    gcc –o main main.c print.c

简单说明如下:

第一行:表示一个规则的前部,前部由两部分组成:冒号之前的称为目标,冒号之后的称为依赖。就是说:要生成main这个目标,必须依赖main.c和print.c这两个文件。第二行:表示一个规则的后部,后部表示的是生成这个目标要如何操作。比如上例:要生成main这个目标,就是执行gcc –o main main.c print.c来生成。

同时make也会根据依赖的修改时间来决定是否要更新目标,当依赖比目标的时间新时,表示目标需要更新,因此执行规则的后部。

我们将上面的规则写入一个名字为makefile的文件中。这样当我们直接执行make的时候,make会去读取当前文件夹下的makefile,并解析这个规则。

**

makefile的变量

**
makefile中规则是真正的主体,但是如果有了变量,编写起来会更简单。makefile中的变量分为两种:直接展开变量,延时展开变量
直接展开变量是通过“:=”进行赋值的。
延时展开变量是通过“=”进行赋值的。例子如下:

name := wanbiaoname = wanbiao
第一个为直接展开变量,后一个为延时展开变量。

关于这两种变量的区别,后面有详细描述。

这里先讨论变量的命名规范。
一 长度:makefile的变量并没有规定变量的长度,但是笔者这里推荐最好不好超过31个字符,只是经验之谈,并没有什么具体的例子支撑。
二 名字:变量名不能包括:# =等特殊字符。gnu make并没有明确说变量不能包含点号。但是这里并不推荐使用此种变量命名法,因为在后续的make版本中,很肯能将使用这些特殊字符。更加通用的做法是,使用字母,数字,下划线,进行变量的命名。
有了变量的名字,来看看变量的值。

makefile中变量的值,可以是任何有效字符,如果遇到特殊字符,可以使用反斜杠进行转义,变量的值,可以包含在单引号,双引号之内,也可以不用包含。例子如下

name := wanbiaoname := “wanbiao”name :=’wanbiao’name := wanbiao zhangsan lisi

makefile将变量的值都当作字符串进行处理。尽管你赋值给他的是一个数字,浮点数,例子如下:

age := 20weight := 59.5

makefile的赋值操作
makefile的赋值分两种,一种是直接展开,另外一种是延时展开。
直接展开是:在变量赋值时,当一个变量引用另外一个变量,直接将另外的变量展开,赋值给当前的变量。
延时展开是:在变量引用时,才将一个变量引用的两外一个变量展开。
例子如下:

name = $(firstname) $(lastname)firstname = wanlastname = biaodisplay:    @echo $(name)

那么当需要更新display时,会打印wan biao.解释如下:
当make扫描到第一行时,并不会马上将$(firstname)和$(lastname)的值展开。而是要在引用的时候,才展开,即当执行echo $(name) 的时候,才去展开,发现$(firstname)为wan $(lastname)为biao,因此输出结果为wan biao
这就是延时展开。下面看看一个立即展开的例子
我们将上面的例子中的“=”换成“:=”如下:

name := $(firstname) $(lastname)firstname := wanlastname := biaodisplay:    @echo $(name)

当需要更新display的时候,会打印为空。解释如下:
当扫描到第一行的时候,会立即将$(firstname) 和$(lastname)的值展开,因为这两个变量都没有在前面赋值过,所以name的值为空。当执行到echo $(name)的时候,直接打印出name的值,为空。

对于这两种赋值方法的异同如下:
延时展开:
优点:可以先使用,后定义。
缺点:容易陷入死循环中。当一个变量直接或者间接的引用自己的时候,容易出现死循环,如下:

    name = wanbiao    name += $(name) zhangsan
当引用时展开它,发现引用了$(name),然后继续展开,又发现了引用$(name),一直这样下去,陷入无限循环之中

立即展开:
优点:不会陷入死循环中
缺点:无法在定义之前使用变量。
建议:在大型项目中使用立即展开“:=”,这样更符号先定义后使用,同时排错起来也相对较易。

变量赋值的其他操作

一个变量可能需要在后面增加值,此时可以使用+=如下:

    name := wanbiao    name += zhangsan

此时,name的值为wanbiao zhangsan。同样当+=后面有其他变量的引用时,name是立即展开还是延时展开,取决于+=前面变量的定义,如下:

    name := wanbiao    name += zhangsan $(others)

因为name是使用“:=”为立即展开,所以$(others)也是立即展开。
如果要根据一个变量以前是否赋值来决定是否要赋于新的值,可以使用 ?= 用法如下:

    name ?= zhangsan

表示:当name没有赋值的时候,将zhangsan赋值给name,当name已经有值了,那么就不进行操作。
此种操作还可以使用后面讲述的条件判断。

变量的引用

在makefile中变量的引用是使用关键字$(变量名)或者${变量名},如果变量名只有一个字符,那么可以省略小括号或者大括号。如下:

    n := wanbiao    lastname := $(n)    display:        echo ${n}

上面的echo ${n} 还可以写成echo $(n) 或者echo $n.
注意:在shell中变量的引用同样使用了$加变量名的情况,并且变量名不用()或者{}括起来。

定义一个空格变量

当需要传递一个空格的时候,不能直接书写空格,原因有二:1,空格并不容易阅读,常常造成误会。2.空格常用作分隔符,使用不当,很可能被当作分隔符,而提示错误。可以使用一个变量来代替空格,以弥补这种缺憾。
同时需要注意的是,在变量的赋值时,变量值的前导空格会被忽略掉,如下,将会忽略掉前面的空格。

    name :=      wan   biao

wan前面的空格将会忽略,所以直接将空格赋值给变量并不能实现。我们可以使用如下的方法,进行规避。

empty :=#定义一个空格。space :=$(empty) $(empty)

通过在两个$(empty)中间输入一个空格,来实现空格的定义。

变量的替换引用

makefile可以在变量使用的时候进行一种替换。如下:

    name := wanbiao    realename := $(name:biao=jie)

表示的是:将name变量值末尾的biao替换成jie,即wanjie,然后再将结果赋值给realename变量。
此种用法常用来替换后缀,比如将.c文件替换成.o文件,如下:

    src := a.c b.c c.c    object := $(src:.c=.o)    all:$(object)        gcc –o main $(object)

override关键字

变量不仅可以通过在makefile中定义,还可以在make的命令行中进行赋值。如下的makefile文件

    name := wanbiao    display :        echo $(name)
在执行的时候,运行如下的命令make name=zhangsan

那么运行的结果将是zhangsan。这是因为在make命令行中赋值的变量会覆盖掉makefile文件中的同名变量。
有时为了防止这种情况的出现,可以在makefile中使用override关键字。如下:

    override name := wanbiao    display:        echo $(name)
那么这种关键字的用处在什么情况下呢,通常有如下的使用情况,
    override name += wanbiao    display:        echo $(name)

那么无论在make的命令行下指定了什么样的name值,那么name一定会有一个wanbiao的值。这种方法可以在一些命令行的参数必须保留某个参数时使用,如下:
override CFLAGS += -g
这样无论在命令行下制定了CFLAGS是什么,那么当编译c文件时,一定会添加一个-g选项,这个选项用来在gdb调试时使用

目标指定变量

当在makefile中定义一个变量,那么这个变量在整个文件内都可使用。我们也可以定义一个在指定的目标中才能使用的变量,这种变量成为目标指定变量,格式如下:
目标:变量声明
举例如下:

%.o :CFLAGS +=-o

表示在满足%.o这个目标的所有上下文中,CFLAGS的变量都会增加-o值

原创粉丝点击