1. define 多行定义

采用 "define IMMEDIATE ... DEFERRED" 方式定义变量。它定义一个包含多行字符串的变量。

define VARIABLE
...
endef

 利用这个特点,可以实现一个完整命令包的定义。例如:

bar = abcd
define two-lines
    @echo foo
    @echo $(bar)
endef

all:
    @$(two-lines)

2. 条件判断

所有使用条件语句在产生分支的地方,make程序会根据预设条件将正确的分支展开,就是说条件分支展开是"立即"的。其中包含:"ifdef"、"ifeq"、"ifndef" 和 "ifneq" 所确定的所有分支命令。

一个示例,如下:

...
libs_for_gcc = -lgnu
normal_libs =

...
foo: $(objects)
ifeq ($(CC),gcc)
    $(CC) -o foo $(objects) $(libs_for_gcc)
else
    $(CC) -o foo $(objects) $(normal_libs)
endif
...

其中,有三个关键字:"ifeq"、"else" 和 "endif"。具体说明如下:

  • "ifeq" 表示条件语句的开始,并指定一个比较条件(相等)。括号和关键字之间要使用空格分隔,两个参数之间要使用逗号分隔。参数中的变量引用在进行变量值比较时被展开。"ifeq" 之后是当条件满足时,make 需要执行的部分,条件不满足时忽略。

  • "else" 之后是当条件不满足时的执行部分,不是所有的条件语句都要执行此部分。

  • "endif" 是条件语句的结束标志,任何一个条件表达式都必须以 "endif" 结束。

2.1 ifeq

此关键字用来判断参数是否相等,格式如下:

ifeq (A, B)
ifeq 'A' 'B'
ifeq "A" "B"
    TEXT-IF-TRUE
else
    TEXT-IF-FALSE
endif

首先替换并展开 A 和 B ,对它们的值进行比较。如果相同(条件判断结果为真),则将 "TEXT-IF-TRUE" 作为 make 要执行的一部分,否则将 "TEXT-IF-FALSE" 作为 make 要执行的一部分。其中 "TEXT-IF-TRUE" 和 "TEXT-IF-FALSE" 可以是若干任何文本行。

2.2 ifneq

关键字 "ifndef" 实现的条件判断语句和 "ifeq" 相反,格式如下:

ifneq (A, B)
ifneq 'A' 'B'
    TEXT-IF-TRUE
else
    TEXT-IF-FALSE
endif

首先替换并展开 A 和 B,对它们的值进行比较。如果不相同(条件判断结果为真)则将 "TEXT-IF-TRUE" 作为 make 要执行的一部分,否则将 "TEXT-IF-FALSE" 作为make要执行的一部分。

2.3 ifdef

关键在 "ifdef" 用来判断一个变量是否已经定义,格式如下:

ifdef VARIABLE
    TEXT-IF-TRUE
else
    TEXT-IF-FALSE
endif

如果变量 "VARIABLE" 值非空,则将 "TEXT-IF-TRUE" 作为 make 要执行的一部分。否则,表达式为假,若存在 "TEXT-IF-FALSE" ,就将它作为 make 要执行的一部分。

2.4 ifndef

关键字 "ifndef" 实现功能和 "ifdef" 相反,格式如下:

ifndef VARIABLE
    TEXT-IF-TRUE
else
    TEXT-IF-FALSE
endif

其中,条件判断语句(包含 "endif")可以以若干空格开始,make 处理时会忽略这些空格。但不能以 [Tab] 字符作为开始,否则就被认为是命令。

例如:"else" 和 "endif" 属于判断语句的一部分,在书写时它们都是没有任何参数的,可以多个空格开始(不能以 [Tab] 字符开始),多个空格或 [Tab] 字符结束。行尾同样可以有注释内容。

3. 包含其它 Makefile

include FILE
-include FILE
sinclude FILE

Makefile 中包含其它文件所需要使用的关键字是 "include",和 c 语言对头文件的包含方式一致。

"include" 指示符告诉 make 暂停读取当前的 Makefile,而转去读取 "include"指定的一个或者多个文件,读取完成后,再继续当前 Makefile 的读取。 Makefile 中指示符 "include" 书写在独立的一行,其形式如下:

include FILENAMES...

FILENAMES 可以是当前操作系统 shell 的文件模式(可以包含路径和通配符)

在 include 前面可以有一些空字符,但绝不能是 [Tab] 键开始。

指示符 "include" 和 <filename> 之间,多个文件之间可以使用空格或者[tab]键隔开。行位的空白符会在处理时被忽略。如下:

include foo.make *.mk $(bar)

等价于:

include foo.make a.mk b.mk c.mk e.mk f.mk

make 命令开始时,会找寻include所指出的其它 Makefile,并把其内容安置在当前位置,类似C/C++的#include指令一样。

如果文件都没有指定绝对路径或相对路径的话,make会在当前目录下首先查找,如果当前目录没有,那么,make还会在下面的几个目录下找:

  1. 如果make执行时,有 "-I" 或 "--include-dir" 参数,那么 make 就会出现在这个参数所指定的目录去寻找。

  2. 如果目录 <prefix>/include (一般为:usr/local/bin 或 usr/include)存在的话,make也会去找。

如果文件没有找到的话,make会生成一条警告信息,但不会马上出现致命错误。它会继续载入其它文件,一旦完成Makefile的读取,make会再重试这些没有找到,或者不能读取的文件,如果还是不行,make才会出现一条致命信息。如果想让make不理那些无法读取的文件,而继续执行,你可以在include前加一个 "-" 号,如下:

-include <filename>

标识,无论include过程出现什么错误,都不要报错继续执行。

4. override 指示符

通常在执行 make 时,如果通过命令行定义了一个变量,那么它将替代在 Makefile 中出现的同名变量的定义。如果不希望命令行指定的变量值替代在Makefile中的变量定义,那么就需要在 Makefile 中使用指示符 "override" 来对变量进行生命。例如:

overrride VARIABLE=VALUE
override VARIABLE:=VALUE
override VARIABLE+=VALUE
override VARIABLE?=VALUE

override define VARIABLE
endef

5. export 声明

上层 make 过程要将所执行的 Makefile 中的变量传递给子 make 过程,需要明确地指出。在 GNU make 中,实现此功能的指示符是 "export" 。当一个变量使用 "export" 进行生命后,变量和它的值将被加入到当前工作的环境变量中,以后再 make 执行的所有规则的命令都可以使用这个变量。

当没有使用指示符 "export" 对任何变量进行生命的情况下,上层 make 只将那些已经初始化的环境变量(在执行 make 之前已经存在的环境变量)和使用命令行指定的变量(如:"make CFLAGS +=-g" 或者 "make -e CFLAGS +=-g")传递给子 make 程序,通常这些变量由字符、数字和下划线组成。

在没有使用关键字 "export" 声明变量,make 执行时它们不会被自动传递给子make,因此下层 Makefile 中可以定义和上层同名的变量,不会引起变量定义冲突。

需要将一个在上层定义的变量传递给子 make,应该在上层 Makefile 中使用指示符 "export" 对此变量进行声明。格式如下:

export VARIABLE ...

当不希望将一个变量传递给子 make 时,可以使用指示符 "unexport" 来声明这个变量。格式如下:

unexport VARIABLE ...

6. 目录搜索

一般搜索,采用变量 VAPTH 来完成,具体介绍可查看章节 VPATH

另一个设置文件搜索路径的方法是使用 make 的 "vpath" 关键字(全小写)。它不是一个变量,而是一个 make 的关键字,它所实现的功能和 VPATH 类似,但是更为灵活。

它可以为不同类型的文件(由文件名区分)指定不同的搜索目录。使用方法有以下三种:

  • vpath PATTERN DIRECTORIES

    为所有符合模式 "PATTERN" 的文件指定搜索目录 "DIRECTORIES"。多个目录使用空格或者冒号(:)分开。

  • vpath PATTERN

    清除之前为符合模式 "PATTERN" 的文件设置的搜索路径。

  • vpath

清除所有已被设置的文件搜索路径。

vpath 使用方法中的 "PATTERN" 需要包含模式字符 "%"。

"%" 意思是匹配一个或者多个字符,例如,"%.h" 表示所有以 ".h" 结尾的文件。

如果在 "PATTERN" 中没有包含模式字符 "%",那么它就是一个明确的文件名,这样就是给定了此文件的所在目录。

"PATTERN" 表示了具有相同特征的一类文件,而 "DIRECTORIES" 则指定了搜索此类文件目录。当规则的依赖文件列表中的文件不能在当前目录下找到时,make 程序将依次在 "DIRECTORIES" 所描述的目录下找此文件。例如:

vpath %.h ../headers

Makefile 中出现的 .h 文件,如果不能在当前目录下找到,则到目录 "./headers" 下寻找。

注意:

这里指定的路径仅限于在 Makefile 文件内容中出现的 .h 文件。并不能指定源文件中包含的头文件所在的路径(在 .c 源文件中所包含的头文件路径需要使用 gcc 的 "-I" 选项指定)。

在 Makefile 中如果存在连续的多个 vpath 语句使用了相同的 "PATTERN",make 就对这些 vpath 语句一个一个进行处理,搜索某种模式文件的目录将是所有 vpath 指定的符合此模型的多个目录,且搜索目录的顺序由 vpath 语句在 Makefile 出现的先后次序来决定。例如:

vpath %.c foo
vpath % blish
vpath %.c bar

表示对所有的 .c 文件,make 依次查找目录:"foo"、"blish"、"bar"。

下一篇:《Makefile 笔记(4)— GNU make 控制函数》

注意:本站所有文章除特别说明外,均为原创,转载请务必以超链接方式并注明作者出处。 标签:makefile,gnumake,make指示符