跟我一起写Makefile文档.docx
- 文档编号:10132291
- 上传时间:2023-02-08
- 格式:DOCX
- 页数:12
- 大小:22.20KB
跟我一起写Makefile文档.docx
《跟我一起写Makefile文档.docx》由会员分享,可在线阅读,更多相关《跟我一起写Makefile文档.docx(12页珍藏版)》请在冰豆网上搜索。
跟我一起写Makefile文档
编译时,编译器需要的是语法的正确,函数与变量的声明的正确。
对于后者,通常是你需要告诉编译器头文件的所在位置(头文件中应该只是声明,而定义应该放在C/C++文件中),只要所有的语法正确,编译器就可以编译出中间目标文件。
一般来说,每个源文件都应该对应于一个中间目标文件(O文件或是OBJ文件),而在链接程序时,链接器会在所有的ObjectFile中找寻函数的实现,如果找不到,那就会报链接错误码(LinkerError)。
-c生成目标文件
cc----gcc编译
-MM,即自动找寻源文件中包含的头文件,并生成一个依赖关系
make加上“-i”或是“--ignore-errors”参数,那么,Makefile中所有命令都会忽略错误
make的参数“-k”或是“--keep-going”,这个参数的意思是,如果某规则中的命令出错了,那么就终目该规则的执行,但继续执行其它规则。
make参数“-n”或“--just-print”,那么其只是显示命令,但不会执行命令,这个功能很有利于我们调试我们的Makefile。
make参数“-s”或“--slient”则是全面禁止命令的显示。
命令行一定以一个Tab键开头。
make参数“-w”或是“--print-directory”会在make的过程中输出一些信息,让你看到目前的工作目录。
make指定了“-e”参数,那么系统环境变量将覆盖Makefile中定义的变量
Make的工作原理:
在默认的方式下,也就是我们只输入make命令。
那么,
1、make会在当前目录下找名字叫“Makefile”或“makefile”的文件。
2、如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到“edit”这个文件,并把这个文件作为最终的目标文件。
3、如果edit文件不存在,或是edit所依赖的后面的.o文件的文件修改时间要比edit这个文件新,那么,他就会执行后面所定义的命令来生成edit这个文件。
4、如果edit所依赖的.o文件也存在,那么make会在当前文件中找目标为.o文件的依赖性,如果找到则再根据那一个规则生成.o文件。
(这有点像一个堆栈的过程)
5、当然,你的C文件和H文件是存在的啦,于是make会生成.o文件,然后再用.o文件生命make的终极任务,也就是执行文件edit了。
定义变量的第一种方式,也就是简单的使用“=”号,在“=”左侧是变量,右侧是变量的值,右侧变量的值可以定义在文件的任何一处,也就是说,右侧中的变量不一定非要是已定义好的值,其也可以使用后面定义的值。
例如:
foo=$(bar)bar=$(ugh)ugh=Huh?
。
第二种方法使用的是“:
=”操作符,这种方法,前面的变量不能使用后面的变量,只能使用前面已定义好了的变量。
变量一般都是字符串,使用变量时要在变量名前加上字符$。
定义其值为空格的变量:
nullstring:
=
space:
=$(nullstring)#endoftheline
注意注释符的特性:
dir:
=/foo/bar#directorytoputthefrobsindir这个变量的值是“/foo/bar”,后面还跟了4个空格,如果我们这样使用这样变量来指定别的目录——“$(dir)/file”那么就完蛋了。
还有一个比较有用的操作符是“?
=”,先看示例:
FOO?
=bar
其含义是,如果FOO没有被定义过,那么变量FOO的值就是“bar”,如果FOO先前被定义过,那么这条语句将什么也不做。
只要make看到一个[.o]文件,它就会自动的把[.c]文件加在依赖关系中,如果make找到一个whatever.o,那么whatever.c,就会是whatever.o的依赖文件。
并且cc-cwhatever.c也会被推导出来。
每个Makefile中都应该写一个清空目标文件(.o和执行文件)的规则,这不仅便于重编译,也很利于保持文件的清洁。
一般的风格都是:
clean:
rmedit$(objects)
更为稳健的做法是:
.PHONY:
clean
clean:
-rmedit$(objects)
.PHONY意思表示clean是一个“伪目标”,而在rm命令前面加了一个小减号的意思就是,也许某些文件出现问题,但不要管,继续做后面的事。
当然,clean的规则不要放在文件的开头,不然,这就会变成make的默认目标。
clean从来都是放在文件的最后。
Makefile里主要包含了五个东西:
显式规则、隐晦规则、变量定义、文件指示和注释。
1、显式规则。
显式规则说明了,如何生成一个或多的的目标文件。
这是由Makefile的书写者明显指出,要生成的文件,文件的依赖文件,生成的命令。
2、隐晦规则。
由于我们的make有自动推导的功能,所以隐晦的规则可以让我们比较粗糙地简略地书写Makefile,这是由make所支持的。
3、变量的定义。
在Makefile中我们要定义一系列的变量,变量一般都是字符串,这个有点你C语言中的宏,当Makefile被执行时,其中的变量都会被扩展到相应的引用位置上。
4、文件指示。
其包括了三个部分,一个是在一个Makefile中引用另一个Makefile,就像C语言中的include一样;另一个是指根据某些情况指定Makefile中的有效部分,就像C语言中的预编译#if一样;还有就是定义一个多行的命令。
5、注释。
Makefile中只有行注释,和UNIX的Shell脚本一样,其注释是用“#”字符,这个就像C/C++中的“//”一样。
如果你要在你的Makefile中使用“#”字符,可以用反斜框进行转义,如:
“\#”。
最后,还值得一提的是,在Makefile中的命令,必须要以[Tab]键开始。
默认的情况下,make命令会在当前目录下按顺序找寻文件名为“GNUmakefile”、“makefile”、“Makefile”的文件,找到了解释这个文件。
当然,你可以使用别的文件名来书写Makefile,比如:
“Make.Linux”,“Make.Solaris”,“Make.AIX”等,如果要指定特定的Makefile,你可以使用make的“-f”和“--file”参数,如:
make-fMake.Linux或make--fileMake.AIX。
在Makefile使用include关键字可以把别的Makefile包含进来,这很像C语言的#include,被包含的文件会原模原样的放在当前文件的包含位置。
include的语法是:
include
filename可以保含路径和通配符。
在include前面可以有一些空字符,但是绝不能是[Tab]键开始。
include和
make命令开始时,会找寻include所指出的其它Makefile,并把其内容安置在当前的位置。
就好像C/C++的#include指令一样。
如果文件都没有指定绝对路径或是相对路径的话,make会在当前目录下首先寻找,如果当前目录下没有找到,那么,make还会在下面的几个目录下找:
1、如果make执行时,有“-I”或“--include-dir”参数,那么make就会在这个参数所指定的目录下去寻找。
(Make–IDIRECTORY)
2、如果目录
/usr/local/bin或/usr/include)存在的话,make也会去找。
如果有文件没有找到的话,make会生成一条警告信息,但不会马上出现致命错误。
它会继续载入其它的文件,一旦完成makefile的读取,make会再重试这些没有找到,或是不能读取的文件,如果还是不行,make才会出现一条致命信息。
如果你想让make不理那些无法读取的文件,而继续执行,你可以在include前加一个减号“-”。
如:
-include
在Makefile中,规则的顺序是很重要的,因为,Makefile中只应该有一个最终目标,其它的目标都是被这个目标所连带出来的,所以一定要让make知道你的最终目标是什么。
一般来说,定义在Makefile中的目标可能会有很多,但是第一条规则中的目标将被确立为最终的目标。
如果第一条规则中的目标有很多个,那么,第一个目标会成为最终的目标。
make所完成的也就是这个目标。
规则的语法:
targets:
prerequisites
command
或是这样:
targets:
prerequisites;command\
command
...
targets是文件名,以空格分开,可以使用通配符。
一般来说,我们的目标基本上是一个文件,但也有可能是多个文件。
command是命令行,如果其不与“target:
prerequisites”在一行,那么,必须以[Tab键]开头,如果和prerequisites在一行,那么可以用分号做为分隔。
当make需要去找寻文件的依赖关系时,你可以在文件前加上路径,但最好的方法是把一个路径告诉make,让make自动去找。
Makefile文件中的特殊变量“VPATH”就是完成这个功能的,如果没有指明这个变量,make只会在当前的目录中去找寻依赖文件和目标文件。
如果定义了这个变量,那么,make就会在当前目录找不到的情况下,到所指定的目录中去找寻文件了。
VPATH=src:
../headers
上面的的定义指定两个目录,“src”和“../headers”,make会按照这个顺序进行搜索。
目录由“冒号”分隔。
(当然,当前目录永远是最高优先搜索的地方)。
为了避免和文件重名的这种情况,我们可以使用一个特殊的标记“.PHONY”来显示地指明一个目标是“伪目标”,向make说明,不管是否有这个文件,这个目标就是“伪目标”。
伪目标一般没有依赖的文件。
但是,我们也可以为伪目标指定所依赖的文件。
伪目标同样可以作为“默认目标”,只要将其放在第一个。
一个示例就是,如果你的Makefile需要一口气生成若干个可执行文件,但你只想简单地敲一个make完事,并且,所有的目标文件都写在一个Makefile中,那么你可以使用“伪目标”这个特性:
.PHONY:
all
all:
prog1prog2prog3
prog1:
prog1.outils.o
cc-oprog1prog1.outils.o
prog2:
prog2.o
cc-oprog2prog2.o
prog3:
prog3.osort.outils.o
cc-oprog3prog3.osort.outils.o
我们知道,Makefile中的第一个目标会被作为其默认目标。
我们声明了一个“all”的伪目标,其依赖于其它三个目标。
由于伪目标的特性是,总是被执行的,所以其依赖的那三个目标就总是不如“all”这个目标新。
所以,其它三个目标的规则总是会被决议。
伪目标同样也可成为依赖。
看下面的例子:
.PHONY:
cleanallcleanobjcleandiff
cleanall:
cleanobjcleandiff
rmprogram
cleanobj:
rm*.o
cleandiff:
rm*.diff
“makecleanall”将清除所有要被清除的文件。
“cleanobj”和“cleandiff”这两个伪目标有点像“子程序”的意思。
我们可以输入“makecleanall”和“makecleanobj”和“makecleandiff”命令来达到清除不同种类文件的目的。
静态模式:
例子:
objects=foo.obar.o
all:
$(objects)
$(objects):
%.o:
%.c
$(CC)-c$(CFLAGS)$<-o$@
上面的例子中,指明了我们的目标从$object中获取,“%.o”表明要所有以“.o”结尾的目标,也就是“foo.obar.o”,也就是变量$object集合的模式,而依赖模式“%.c”则取模式“%.o”的“%”,也就是“foobar”,并为其加下“.c”的后缀,于是,我们的依赖目标就是“foo.cbar.c”。
而命令中的“$<”和“$@”则是自动化变量,“$<”表示所有的依赖目标集(也就是“foo.cbar.c”),“$@”表示目标集(也就是“foo.obar.o”)。
于是,上面的规则展开后等价于下面的规则:
foo.o:
foo.c
$(CC)-c$(CFLAGS)foo.c-ofoo.o
bar.o:
bar.c
$(CC)-c$(CFLAGS)bar.c-obar.o
再例如:
files=foo.elcbar.olose.o
$(filter%.o,$(files)):
%.o:
%.c
$(CC)-c$(CFLAGS)$<-o$@
$(filter%.elc,$(files)):
%.elc:
%.el
emacs-fbatch-byte-compile$<
$(filter%.o,$(files))表示调用Makefile的filter函数,过滤“$filter”集,只要其中模式为“%.o”的内容。
当我们用“@”字符在命令行前,那么,这个命令将不被make显示出来,如果make执行时,带入make参数“-n”或“--just-print”,那么其只是显示命令,但不会执行命令,这个功能很有利于我们调试我们的Makefile,看看我们书写的命令是执行起来是什么样子的或是什么顺序的,而make参数“-s”或“--slient”则是全面禁止命令的显示。
当依赖目标新于目标时,make会一条一条的执行其后的命令。
需要注意的是,如果你要让上一条命令的结果应用在下一条命令时,你应该使用分号分隔这两条命令。
比如你的第一条命令是cd命令,你希望第二条命令得在cd之后的基础上运行,那么你就不能把这两条命令写在两行上,而应该把这两条命令写在一行上,用分号分隔。
示例一:
exec:
cd/home/hchen
pwd
示例二:
exec:
cd/home/hchen;pwd
第一个例子中的cd没有作用,pwd会打印出当前的Makefile目录,而第二个例子中,cd就起作用了,pwd会打印出“/home/hchen”。
总控Makefile的变量可以传递到下级的Makefile中(如果你显示的声明),但是不会覆盖下层的Makefile中所定义的变量,除非指定了“-e”参数。
如果你要传递变量到下级Makefile中,那么你可以使用这样的声明:
export
unexport
例子:
exportvariable=value其等价于:
variable=value
exportvariable
变量替换:
$(var:
a=b)其意思是,把变量“var”中所有以“a”字串“结尾”的“a”替换成“b”字串,这里的“结尾”意思是“空格”或是“结束符”。
另外一种变量替换的技术是以“静态模式”(参见前面章节)定义的,如:
foo:
=a.ob.oc.o
bar:
=$(foo:
%.o=%.c)
追加变量值:
使用操作符“+=”。
如果变量之前没有定义过,那么,“+=”会自动变成“=”,如果前面有变量定义,那么“+=”会继承于前次操作的赋值符。
如果前一次的是“:
=”,那么“+=”会以“:
=”作为其赋值符,如果前次的赋值符是“=”,所以“+=”也会以“=”来做为赋值。
如:
variable:
=value
variable+=more
等价于:
variable:
=value
variable:
=$(variable)more
但如果是这种情况:
variable=value
variable+=more
等价于:
variable=value
variable=$(variable)more
define定义多行变量时,后面跟的是变量名字,重起一行来定义变量的值,以endef结束定义。
上层Makefile中定义的变量会以系统环境变量的方式传递到下层的Makefile中。
当然,默认情况下,只有通过命令行设置的变量会被传递。
而定义在文件中的变量,如果要向下层Makefile传递,则需要使用exprot关键字来声明。
目标变量:
其语法是:
当我们设置了这样一个变量,这个变量会作用到由这个目标所引发的所有的规则中去。
如:
prog:
CFLAGS=-g
prog:
prog.ofoo.obar.o
$(CC)$(CFLAGS)prog.ofoo.obar.o
prog.o:
prog.c
$(CC)$(CFLAGS)prog.c
foo.o:
foo.c
$(CC)$(CFLAGS)foo.c
bar.o:
bar.c
$(CC)$(CFLAGS)bar.c
在这个示例中,不管全局的$(CFLAGS)的值是什么,在prog目标,以及其所引发的所有规则中(prog.ofoo.obar.o的规则),$(CFLAGS)的值都是“-g”。
ifdef只是测试一个变量是否有值,其并不会把变量扩展到当前位置。
make是在读取Makefile时就计算条件表达式的值,并根据条件表达式的值来选择语句,所以,你最好不要把自动化变量(如“$@”等)放入条件表达式中,因为自动化变量是在运行时才有的。
函数调用,很像变量的使用,也是以“$”来标识的,其语法如下:
$(
函数名和参数之间以“空格”分隔,参数间以逗号“,”分隔。
字符串处理函数:
$(subst
名称:
字符串替换函数——subst。
功能:
把字串
返回:
函数返回被替换过后的字符串。
$(patsubst
名称:
模式字符串替换函数——patsubst。
功能:
查找
bar:
=$(foo:
%.o=%.c)
和“$(patsubst%.o,%.c,$(objects))”一样。
$(strip
名称:
去空格函数——strip。
功能:
去掉
返回:
返回被去掉空格的字符串值。
$(findstring
名称:
查找字符串函数——findstring。
功能:
在字串
返回:
如果找到,那么返回
$(filter
名称:
过滤函数——filter。
功能:
以
可以有多个模式。
“all”
这个伪目标是所有目标的目标,其功能一般是编译所有的目标。
“clean”
这个伪目标功能是删除所有被make创建的文件。
“install”
这个伪目标功能是安装已编译好的程序,其实就是把目标执行文件拷贝到指定的目标中去。
“print”
这个伪目标的功能是例出改变过的源文件。
“tar”
这个伪目标功能是把源程序打包备份。
也就是一个tar文件。
“dist”
这个伪目标功能是创建一个压缩文件,一般是把tar文件压成Z文件。
或是gz文件。
“TAGS”
这个伪目标功能是更新所有的目标,以备完整地重编译使用。
“check”和“test”
这两个伪目标一般用来测试makefile的流程。
模式规则中,至少在规则的目标定义中要包含"%",否则,就是一般的规则。
如果"%"定义在目标中,那么,目标中的"%"的值决定了依赖目标中的"%"的值,也就是说,目标中的模式的"%"决定了依赖目标中"%"的样子。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 一起 Makefile 文档