Linux学习makefile笔记

发布时间 : 星期日 文章Linux学习makefile笔记更新完毕开始阅读

以根据你的习惯来进行设置。还有一个要提一下的make的参数的是―-k‖或是―--keep-going‖,这个参数的意思是,如果某规则中的命令出错了,那么就终止该规则的执行,但继续执行其它规则。

4.2.4嵌套执行make

在一些大的工程中,我们会把我们不同模块或是不同功能的源文件放在不同的目录中,我们可以在每个目录中都书写一个该目录的Makefile,这有利于让我们的Makefile变得更加地简洁,而不至于把所有的东西全部写在一个Makefile中,这样会很难维护我们的Makefile,这个技术对于我们模块编译和分段编译有着非常大的好处。

例如,我们有一个子目录叫subdir,这个目录下有个Makefile文件,来指明了这个目录下文件的编译规则。那么我们总控的Makefile可以这样书写:

subsystem:

cd subdir && $(MAKE) 其等价于: subsystem: $(MAKE) -C subdir

定义$(MAKE)宏变量的意思是,也许我们的make需要一些参数,所以定义成一个变量比较利于维护。这两个例子的意思都是先进入―subdir‖目录,然后执行make命令。我们把这个Makefile叫做―总控Makefile‖,总控Makefile的变量可以传递到下级的Makefile中(如果你显示的声明),但是不会覆盖下层的Makefile中所定义的变量,除非指定了“-e”参数。

如果你要传递变量到下级Makefile中,那么你可以使用这样的声明: export

如果你不想让某些变量传递到下级Makefile中,那么你可以这样声明: unexport 示例一:

export variable = value 其等价于: variable = value export variable 其等价于:

export variable: = value 其等价于: variable := value export variable

示例二:

export variable += value 其等价于: variable += value export variable

如果你要传递所有的变量,那么,只要一个export就行了。后面什么也不用跟,表示传递所有的变量。

需要注意的是,有两个变量,一个是SHELL,一个是MAKEFLAGS,这两个变量不管你是否export,其总是要传递到下层Makefile中,特别是MAKEFILES变量,其中包含了make的参数信息,如果我们执行―总控Makefile‖时有make参数或是在上层Makefile中定义了这个变量,那么MAKEFILES变量将会是这些参数,并会传递到下层Makefile中,这是一个系统级的环境变量。

但是make命令中的有几个参数并不往下传递,它们是―-C‖,―-f‖,―-h‖―-o‖和―-W‖(有关Makefile参数的细节将在后面说明),如果你不想往下层传递参数,那么,你可以这样来:

subsystem:

cd subdir && $(MAKE) MAKEFLAGS=

如果你定义了环境变量MAKEFLAGS,那么你得确信其中的选项是大家都会用到的,如果其中有―-t‖,―-n‖,和―-q‖参数,那么将会有让你意想不到的结果,或许会让你异常地恐慌。还有一个在―嵌套执行‖中比较有用的参数,―-w‖或是―--print-directory‖会在make的过程中输出一些信息,让你看到目前的工作目录。比如,如果我们的下级make目录是―/home/hchen/gnu/make‖,如果我们使用―make -w‖来执行,那么当进入该目录时,我们会看到:

make: Entering directory `/home/hchen/gnu/make'. 而在完成下层make后离开目录时,我们会看到:

make: Leaving directory `/home/hchen/gnu/make'

当你使用―-C‖参数来指定make下层Makefile时,―-w‖会被自动打开的。如果参数中有―-s‖(―--slient‖)或是―--no-print-directory‖,那么,―-w‖总是失效的。

4.2.5定义命令包

如果Makefile中出现一些相同命令序列,那么我们可以为这些相同的命令序列定义一个变量。定义这种命令序列的语法以―define‖开始,以―endef‖结束,如:

define run-yacc yacc $(firstword $^) mv y.tab.c $@

endef

这里,―run-yacc‖是这个命令包的名字,其不要和Makefile中的变量重名。在―define‖和―endef‖中的两行就是命令序列。这个命令包中的第一个命令是运行Yacc程序,因为Yacc程序总是生成―y.tab.c‖的文件,所以第二行的命令就是把这个文件改改名字。还是把这个命令包放到一个示例中来看看吧。 foo.c : foo.y $(run-yacc)

我们可以看见,要使用这个命令包,我们就好像使用变量一样。在这个命令包的使用中,命令包―run-yacc‖中的―$^‖就是―foo.y‖,―$@‖就是―foo.c‖(有关这种以 ―$‖开头的特殊变量,我们会在后面介绍),make在执行命令包时,命令包中的每个命令会被依次独立执行。

在 Makefile中的定义的变量,就像是C/C++语言中的宏一样,他代表了一个文本字串,在Makefile中执行的时候其会自动原模原样地展开在所使用的地方。其与C/C++所不同的是,你可以在Makefile中改变其值。在Makefile中,变量可以使用在―目标‖,―依赖目标‖,―命令‖或是 Makefile的其它部分中。

变量的命名字可以包含字符、数字,下划线(可以是数字开头),但不应该含有―:‖、―#‖、―=‖或是空字符(空格、回车等)。变量是大小写敏感的,―foo‖、―Foo‖和―FOO‖是三个不同的变量名。传统的Makefile的变量名是全大写的命名方式,但我推荐使用大小写搭配的变量名,如:MakeFlags。这样可以避免和系统的变量冲突,而发生意外的事情。有一些变量是很奇怪字串,如―$<‖、―$@‖等,这些是自动化变量,我会在后面介绍。

4.3使用变量

4.3.1变量的基础

变量在声明时需要给予初值,而在使用时,需要给在变量名前加上―$‖符号,但最好用小括号―()‖或是大括号―{}‖把变量给包括起来。如果你要使用真实的―$‖字符,那么你需要用―$$‖来表示。变量可以使用在许多地方,如规则中的―目标‖、―依赖‖、―命令‖以及新的变量中。先看一个例子: objects = program.o foo.o utils.o program : $(objects) cc -o program $(objects) $(objects) : defs.h

变量会在使用它的地方精确地展开,就像C/C++中的宏一样,例如: foo = c

prog.o : prog.$(foo)

$(foo)$(foo) -$(foo) prog.$(foo)

展开后得到: prog.o : prog.c cc -c prog.c

当然,千万不要在你的Makefile中这样干,这里只是举个例子来表明Makefile中的变量在使用处展开的真实样子。可见其就是一个―替代‖的原理。另外,给变量加上括号完全是为了更加安全地使用这个变量,在上面的例子中,如果你不想给变量加上括号,那也可以,但我还是强烈建议你给变量加上括号。

4.3.2变量中的变量

在定义变量的值时,我们可以使用其它变量来构造变量的值,在Makefile中有两种方式来在用变量定义变量的值。先看第一种方式,也就是简单的使用―=‖号,在―=‖左侧是变量,右侧是变量的值,右侧变量的值可以定义在文件的任何一处,也就是说,右侧中的变量不一定非要是已定义好的值,其也可以使用后面定义的值。如: foo = $(bar) bar = $(ugh) ugh = Huh? all:

echo $(foo)

注:命令行以table键开头,@echo $(foo)直接输出变量foo的值,而echo $(foo)先输出echo Huh?,再换行输出Huh?。

由此可见,变量是可以使用后面的变量来定义的。这个功能有好的地方,也有不好的地方,好的地方是,我们可以把变量的真实值推到后面来定义,如: CFLAGS = $(include_dirs) –O include_dirs = -Ifoo –Ibar

当―CFLAGS‖在命令中被展开时,会是―-Ifoo -Ibar -O‖。但这种形式也有不好的地方,那就是递归定义,如: CFLAGS = $(CFLAGS) –O 或: A = $(B) B = $(A)

这会让make陷入无限的变量展开过程中去,当然,我们的make是有能力检测

联系合同范文客服:xxxxx#qq.com(#替换为@)