Chinaunix首页 | 论坛 | 博客
  • 博客访问: 181151
  • 博文数量: 37
  • 博客积分: 1110
  • 博客等级: 少尉
  • 技术积分: 395
  • 用 户 组: 普通用户
  • 注册时间: 2010-06-29 22:01
文章分类

全部博文(37)

文章存档

2013年(10)

2011年(2)

2010年(25)

我的朋友

分类: 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是一个默认定义(内嵌变量)。如CCMAKERM等变量如果在Makefile中重新定义这些变量,函数返回值将相应发生变化。

3.  environment

变 量VARIABLE 是 一 个 系 统 环 境 变量 , 并 且make 没 有 使 用 命 令 行 选 项-e Makefile中不存在同名的变量定义,此变量没有被替代)  一节

4.  environment override

变量VARIABLE是一个系统环境变量,并且make使用了命令行选项-eMakefile中存在一个同名的变量定义,使用make -e时环境变量值替代了文件中的变量定义。

5.  file

变量VARIABLE在某一个 makefile 文件中定义。

6.  command line

变量VARIABLE在命令行中定义。

7.  override

变量VARIABLEmakefile 文件中定义并使用override指示符声明。

8.  automatic

变量VARIABLE是自动化变量。参考   9.5.3 自动化变量  一节

 

 函数origin返回的关于变量的信息对我们书写 Makefile 是相当有用的,可以使我们在使用一个变量之前对它的值的合法性进行判断。假设在 Makefile 其包了另外一个名为 bar.mk  makefile 文件。我们需要在 bar.mk 中定义变量bletch(无论它是否是一个环境变量),保证make –f bar.mk能够正确执行。另外一种情况,当 Makefile 包含 bar.mk,在 Makefile bar.mk 之前有同样的变量定义,但是我们不希望覆盖 bar.mk 中的bletch的定义。一种方

式是:我们在 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)返回environmentenvironment 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时,此定义之前已经定义变量EROOR1,那么make将会提示致命错误信息$(ERROR1)并退出。示例 2

 

 

ERR = $(error found an error!)

 

.PHONY: err

err: ; $(ERR)

 

这个例子,在 make 读取 Makefile 时不会出现致命错误。只有目标err被作为一个目标被执行时才会出现。

 

2$(warning TEXT…)

 

函数功能:函数warning类似于函数error,区别在于它不会导致致命错误(make不退出),而只是提示TEXT…make 的执行过程继续。

  返回值:空字符

  函数说明:用法和error类似,展开过程相同。

 

阅读(861) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2010-11-08 15:24:20

很好的, 收藏了 推荐一个博客,提供很多免费软件编程电子书下载: http://free-ebooks.appspot.com