分类: LINUX
2010-11-07 21:41:21
八、eval函数
函数功能:函数“eval”是一个比较特殊的函数。使用它我们可以在我们的Makefile中构造一个可变的规则结构关系(依赖关系链),其中可以使用其它变量和函数。函数“eval”对它的参数进行展开,展开的结果作为Makefile的一部分,make可以对展开内容进行语法解析。展开的结果可以包含一个新变量、目标、隐含规则或者是明确规则等。也就是说此函数的功能主要是:根据其参数的关系、结构,对它们进行替换展开。
返回值:函数“eval”的返回值时空,也可以说没有返回值。
函数说明:“eval”函数执行时会对它的参数进行两次展开。第一次展开过程发是由函数本身完成的,第二次是函数展开后的结果被作为Makefile内容时由make解析时展开的。明确这一点对于使用“eval”函数非常重要。在理解了函数“eval”二次展开的过程后。实际使用时,当函数的展开结果中存在引用(格式为:$(x))时,那么在函数的参数中应该使用“$$”来代替“$”(参考 5.1 变量的引用 一节)。因为这一点,所以通常它的参数中会使用函数“value”来取一个变量的文本值。我们看一个例子。例子看起来似乎非常复杂,因为它综合了其它的一些概念和函数。不过我们可以考虑两点:其一,通常实际一个模板的定义可能比例子中的更为复杂;其二,我们可以实现一个复杂通用的模板,在我们的所有Makefile中包含它,以可作到一劳永逸。相信这一点可能是大多数程序员所推崇的。
示例:
# sample Makefile
PROGRAMS = server client
server_OBJS = server.o server_priv.o server_access.o
server_LIBS = priv protocol
client_OBJS = client.o client_api.o client_mem.o
client_LIBS = protocol
# Everything after this is generic
.PHONY: all
all: $(PROGRAMS)
define PROGRAM_template
$(1): $$($(1)_OBJ) $$($(1)_LIBS:%=-l%)
ALL_OBJS += $$($(1)_OBJS)
endef
$(foreach prog,$(PROGRAMS),$(eval $(call PROGRAM_template,$(prog))))
$(PROGRAMS):
$(LINK.o) $^ $(LDLIBS) -o $@
clean:
rm -f $(ALL_OBJS) $(PROGRAMS)
我们来看一下这个例子:它实现的功能是完成“PROGRAMS”的编译链接。例子中“$(LINK.o)”为“$(CC) $(LDFLAGS)”,意思是对所有的.o文件和指定的库文件进行链接。
“$(foreach prog,$(PROGRAM),$(eval $(call PROGRAM_template,$(prog))))”展开为:
server : $(server_OBJS) –l$(server_LIBS)
client : $(client_OBJS) –l$(client_LIBS)
九、 origin函数
函数“origin”和其他函数不同,函数“origin”的动作不是操作变量(它的参数)。它只是获取和此变量(参数)相关的信息,告诉我们这个变量的出处(定义方式)。
函数语法:
$(origin VARIABLE)
函数功能:函数“origin”查询参数“VARIABLE”(通常是一个变量名)的出处。
函数说明:“VARIABLE”是一个变量名而不是一个变量的引用。因此通常它不包含“$”(当然,计算的变量名例外)。
返回值:返回“VARIABLE”的定义方式。用字符串表示。
函数的返回情况有以下几种:
1. undefined
变量“VARIABLE”没有被定义。
2. default
变量“VARIABLE”是一个默认定义(内嵌变量)。如“CC”、“MAKE”、“RM”等变量如果在Makefile中重新定义这些变量,函数返回值将相应发生变化。
3. environment
变 量 “ VARIABLE ” 是 一 个 系 统 环 境 变量 , 并 且make 没 有 使 用 命 令 行 选 项 “ -e ”(Makefile中不存在同名的变量定义,此变量没有被替代)项 一节
4. environment override
变量“VARIABLE”是一个系统环境变量,并且make使用了命令行选项“-e”。Makefile中存在一个同名的变量定义,使用“make -e”时环境变量值替代了文件中的变量定义。
5. file
变量“VARIABLE”在某一个 makefile 文件中定义。
6. command line
变量“VARIABLE”在命令行中定义。
7. override
变量“VARIABLE”在 makefile 文件中定义并使用“override”指示符声明。
8. automatic
变量“VARIABLE”是自动化变量。参考 9.5.3 自动化变量 一节
式是:我们在 bar.mk 中使用指示符“override”声明这个变量。但是它所存在的问题时,此变量不能被任何方式定义的同名变量覆盖,包括命令行定义。另外一种比较灵活的实现就是在 bar.mk中使用“origin”函数,如下:
ifdef bletch
ifeq "$(origin bletch)" "environment"
bletch = barf, gag, etc.
endif
endif
这里,如果存在环境变量“bletch”,则对它进行重定义。
ifneq "$(findstring environment,$(origin bletch))" ""
bletch = barf, gag, etc.
endif
这个例子实现了:即使环境变量中已经存在变量“bletch”,无论是否使用“make -e”来执行 Makefile,变量“bletch”的值都是“barf,gag,etc”(在 Makefile 中所定义的)。环境变量不
能替代文件中的定义。如果“$(origin bletch)”返回“environment”或“environment override”,都将对变量
“bletch”重新定义。关于函数“firststring”可参考文本处理函数。
十、shell函数
shell函数不同于除“wildcard”函数之外的其它函数。make可以使用它来和外部通信。
函数功能:函数“shell”所实现的功能和shell中的引用(``)相同。实现了命令的扩展。意味着需要一个shell 命令作为它的参数,而返回的结果是此命令在shell中的执行结果。make仅仅对它的回返结果进行处理;make将函数的返回结果中的所有换行符(“\n”)或者一对“\n\r”替换为单空格;并去掉末尾的回车符号(“\n”)或者“\n\r”。函数展开式时,它所调用的命令(它的参数)得到执行。。除了对它的引用出现在规则的命令行中和递归的变量定义引用以外,其它决大多数情况下,make在读取Makefile时函数shell就被扩展。
返回值:函数“shell”的参数在 shell 中的执行结果。
函数说明:函数本身的返回值是其参数的执行结果,没有进行任何处理。对结果的处理是由 make 进行的。当对函数的引用出现在规则的命令行中,命令行在执行时函数引用才被展开。展开过程函数参数的执行时在另外一个 shell 进程中完成的,因此对于出现在规则命令行的多级“shell”函数引用需要谨慎处理,否则会影响效率(每一级的“shell”函数的参数都会有各自的 shell 进程)。
示例 1:
contents := $(shell cat foo)
将变量“contents”赋值为文件“foo”的内容,文件中的行在变量中使用空格(而不是换行
符)分割。
示例 2:
files := $(shell echo *.c)
将变量“files”赋值为当前目录下所有.c文件的列表(文件名之间使用空格分割)。在shell中之行的命令是“echo *.c”,它会返回当前目录下的所有.c文件列表。上例的执行结果和 函数“$(wildcard *.c)”的结果相同,除非你使用的是一个奇怪的shell。
注意:通过上边的两个例子我们可以看到,在引用“shell”函数的变量定义使用直接展开式定义。这样就保证了函数的展开在make读入Makefile的过程中完成的。后续对此变量的引用就不会有展开过程。这样可以防止规则命令行中的变量引用在命令行执行时展开的情况发生(因为展开“shell”函数需要另外的shell进程完成,影响命令的执行效率)。这也是我们建议的方式。
十一、make的控制函数
make 提供了两个控制 make 运行方式的函数。通常它们用在 Makefile 中,当 make 执行过程中检测到某些错误是为用户提供消息,并且可以控制 make 过程是否继续。
1、$(error TEXT…)
函数功能:产生致命错误,并提示“TEXT…”信息给用户,之后退出 make 的执行。需要说明的是:“error”函数是在函数展开式(函数被调用时)才提示信息并结束 make 进程。
因此如果函数出现在命令中或者一个递归的变量定义中时,在读取 Makefile 时不会出现错误。而只有包含 “error”函数引用的命令被执行,或者定义中引用此函数的递归变量被展开时,才会提示致命信息“TEXT…”同时 make 退出执行。
返回值:空字符
函数说明:“error ”函数一般不出现在直接展开式的变量定义中,否则在make 读取Makefile时将会提示致命错误。
假设我们的 Makefile 中包含以下两个片断;
示例 1:
ifdef ERROR1
$(error error is $(ERROR1))
endif
make读取Makefile时,此定义之前已经定义变量“EROOR
ERR = $(error found an error!)
.PHONY: err
err: ; $(ERR)
这个例子,在 make 读取 Makefile 时不会出现致命错误。只有目标“err”被作为一个目标被执行时才会出现。
2、$(warning TEXT…)
函数功能:函数“warning”类似于函数“error”,区别在于它不会导致致命错误(make不退出),而只是提示“TEXT…”,make 的执行过程继续。
返回值:空字符
函数说明:用法和“error”类似,展开过程相同。
chinaunix网友2010-11-08 15:24:20
很好的, 收藏了 推荐一个博客,提供很多免费软件编程电子书下载: http://free-ebooks.appspot.com