makefile的运⾏
这⾥写⽬录标题
⼀般来说,最简单的就是直接在命令⾏下输⼊ make 命令,make 命令会当前⽬录的makefile 来执⾏,⼀切都是⾃动的。但也有时你也许只想让 make 重编译某些⽂件,⽽不是整个⼯程,⽽⼜有的时候你有⼏套编译规则,你想在不同的时候使⽤不同的编译规则,等等。
⼀、 make 的退出码
make 命令执⾏后有三个退出码:
0 - 表⽰成功执⾏。
1 - 如果 make 运⾏时出现任何错误,其返回 1。
2 - 如果你使⽤了 make 的“-q”选项,并且 make 使得⼀些⽬标不需要更新,那么返回 2。
⼆、指定 Makefile
前⾯我们说过,GNU make 寻默认的 Makefile 的规则是在当前⽬录下依次三个⽂件“GNUmakefile”
、
“makefile”和“Makefile”。其按顺序这三个⽂件,⼀旦到,就开始读取这个⽂件并执⾏。当前,我们也可以给 make 命令指定⼀个特殊名字的 Makefile。要达到这个功能,我们要使⽤ make 的“-f”或是“–file”参数(“–makefile”参数也⾏)。
例如,我们有个makefile 的名字是“hchen.mk”,那么,我们可以这样来让 make 来执⾏这个⽂件:make –f hchen.mk。如果在 make 的命令⾏中, 你不只⼀次地使⽤了“-f”参数,那么, 所有指定的makefile将会被连在⼀起传递给 make 执⾏。
三、指定⽬标
⼀般来说,make 的最终⽬标是 makefile 中的第⼀个⽬标,⽽其它⽬标⼀般是由这个⽬标连带出来的。这是 make 的默认⾏为。当然,⼀般来说,你的 makefile 中的第⼀个⽬标是由许多个⽬标组成,你可以指⽰ make,让其完成你所指定的⽬标。要达到这⼀⽬的很简单,需在 make 命令后直接跟⽬标的名字就可以完成(如前⾯提到的“make clean”形式)。
任何在 makefile 中的⽬标都可以被指定成终极⽬标,但是除了以“-”打头,或是包含了“=”的⽬标,因为有这些字符的⽬标,会被解析成命令⾏参数或是变量。甚⾄没有被我们明确写出来的⽬标也可以成为
make 的终极⽬标,也就是说,只要 make 可以到其隐含规则推导规则,那么这个隐含⽬标同样可以被指定成终极⽬标。有⼀个 make 的环境变量叫MAKECMDGOALS,这个变量中会存放你所指定的终极⽬标的列表,如果在命令⾏上,你没有指定⽬标,那么,这个变量是空值。这个变量可以让你使⽤在⼀些⽐较特殊的情形下。⽐如下⾯的例⼦:
sources = foo.c bar.c
ifneq ($(MAKECMDGOALS),clean)
include $(sources:.c=.d)
endif
基于上⾯的这个例⼦,只要我们输⼊的命令不是“make clean”,那么 makefile 会⾃动包含“foo.d”和“bar.d”这两个 makefile。使⽤指定终极⽬标的⽅法可以很⽅便地让我们编译我们的程序,例如下⾯这个例⼦:
.PHONY: all
all: prog1 prog2 prog3 prog4
从这个例⼦中,我们可以看到, 这个 makefile 中有四个需要编译的程序——“prog1”,“prog2”, “prog3”和 “prog4”,我们可以使⽤“make all”命令来编译所有的⽬标(如果把 all 置成第⼀个⽬标,那么只需执⾏“make”),我们也可以使⽤“make
prog2”来单独编译标“prog2”。
即然 make 可以指定所有 makefile 中的⽬标,那么也包括“伪⽬标”,于是我们可以根据这种性质来让我们的 makefile 根据指定的不同的⽬标来完成不同的事。在 Unix 世界中,软件发布时,特别是 GNU 这种开源软件的发布时,其 makefile 都包含了编译、安装、打包等功能。我们可以参照这种规则来书写我们的 makefile 中的⽬标。
⽬标名字含义
“all”这个伪⽬标是所有⽬标的⽬标,其功能⼀般是编译所有的⽬标。
“clean”这个伪⽬标功能是删除所有被 make 创建的⽂件。
“install”这个伪⽬标功能是安装已编译好的程序,其实就是把⽬标执⾏⽂件拷贝到指定的⽬标中去。
“print”这个伪⽬标的功能是例出改变过的源⽂件。
“tar”这个伪⽬标功能是把源程序打包备份。也就是⼀个 tar ⽂件。
“dist”这个伪⽬标功能是创建⼀个压缩⽂件,⼀般是把 tar ⽂件压成 Z ⽂件。或是 gz ⽂件。
“TAGS”这个伪⽬标功能是更新所有的⽬标,以备完整地重编译使⽤。
“check”和“test”这两个伪⽬标⼀般⽤来测试 makefile 的流程。
当然⼀个项⽬的 makefile 中也不⼀定要书写这样的⽬标,这些东西都是 GNU 的东西,但是我想,GNU 搞出这些东西⼀定有其可取之处(等你的 UNIX 下的程序⽂件⼀多时你就会发现这些功能很有⽤了),这⾥只不过是说明了,如果你要书写这种功能,最好使⽤这种名
字命名你的⽬标,这样规范⼀些,规范的好处就是——不⽤解释,⼤家都明⽩。⽽且如果你的 makefile 中有这些功能,⼀是很实⽤,⼆是可以显得你的 makefile 很专业。
四、检查规则
有时候,我们不想让我们的 makefile 中的规则执⾏起来,我们只想检查⼀下我们的命令,或是执⾏的序列。于是我们可以使⽤ make 命令的下述参数:
“-n”
“--just-print”
“--dry-run”
“--recon”
不执⾏参数,这些参数只是打印命令,不管⽬标是否更新,把规则和连带规则下的命令打印出来,但不执⾏,这些参数对于我们调试makefile 很有⽤处。
“-t”
“--touch”
这个参数的意思就是把⽬标⽂件的时间更新,但不更改⽬标⽂件。也就是说,make 假装编译⽬标,但不是真正的编译⽬标,只是把⽬标变成已编译过的状态。
“-q”
“--question”
这个参数的⾏为是⽬标的意思,也就是说,如果⽬标存在,那么其什么也不会输出,当然也不会执
⾏编译,如果⽬标不存在,其会打印出⼀条出错信息。
“-W <file>”
“--what-if=<file>”
“--assume-new=<file>”
“--new-file=<file>”
这个参数需要指定⼀个⽂件。⼀般是是源⽂件(或依赖⽂件),Make 会根据规则推导来运⾏依赖于这个⽂件的命令,⼀般来说,可以
和“-n”参数⼀同使⽤,来查看这个依赖⽂件所发⽣的规则命令。另外⼀个很有意思的⽤法是结合“-p”和“-v”来输出 makefile 被执⾏时的信息。
五、 make 的参数
下⾯列举了所有 GNU make 3.80 版的参数定义。其它版本和产商的 make ⼤同⼩异,不过其它产商的 make 的具体参数还是请参考各⾃的产品⽂档。
“-b”
“-m”
这两个参数的作⽤是忽略和其它版本 make 的兼容性。
“-B”
“--always-make”
认为所有的⽬标都需要更新(重编译)。
“-C <dir>”
“--directory=<dir>”
指定读取 makefile 的⽬录。如果有多个“-C”参数,make 的解释是后⾯的路径以前⾯的作为相对路径,并以最后的⽬录作为被指定⽬录。如:“make –C ~hchen/test –C prog”等价于“make –C ~hchen/test/prog”。
“—debug[=<options>]”
输出 make 的调试信息。它有⼏种不同的级别可供选择,如果没有参数,那就是输出最简单的调试信息。
下⾯是<options>的取值:
a —— 也就是 all,输出所有的调试信息。(会⾮常的多)
b —— 也就是 basic,只输出简单的调试信息。即输出不需要重编译的⽬标。
v —— 也就是 verbose,在 b 选项的级别之上。输出的信息包括哪个 makefile 被解析,不需要被重编译的依赖⽂件(或是依赖⽬标)等。
i —— 也就是 implicit,输出所以的隐含规则。
j —— 也就是 jobs,输出执⾏规则中命令的详细信息,如命令的 PID、返回码等。
m —— 也就是 makefile,输出make读取 makefile,更新 makefile,执⾏ makefile 的信息。
“-d”相当于“--debug=a”。
“-e”
“--environment-overrides”
指明环境变量的值覆盖 makefile 中定义的变量的值。
“-f=<file>”
“--file=<file>”
“--makefile=<file>”
指定需要执⾏的 makefile。
“-h”
“--help”
显⽰帮助信息。
“-i”
“--ignore-errors”
在执⾏时忽略所有的错误。
“-I <dir>”
“--include-dir=<dir>”
指定⼀个被包含 makefile 的搜索⽬标。可以使⽤多个“-I”参数来指定多个⽬录。
“-j [<jobsnum>]”
“--jobs[=<jobsnum>]”
指同时运⾏命令的个数。如果没有这个参数,make 运⾏命令时能运⾏多少就运⾏多少。如果有⼀个以上的“-j”参数,那么仅最后⼀个“-j”才是有效的。(注意这个参数在 MS-DOS中是⽆⽤的)
“-k”
“--keep-going”
出错也不停⽌运⾏。如果⽣成⼀个⽬标失败了,那么依赖于其上的⽬标就不会被执⾏了。
“-l <load>”
“--load-average[=<load]”
“—max-load[=<load>]”
指定 make 运⾏命令的负载。
“-n”
“--just-print”
“--dry-run”
“--recon”
仅输出执⾏过程中的命令序列,但并不执⾏。
“-o <file>”
“--old-file=<file>”
“--assume-old=<file>”
不重新⽣成的指定的<file>,即使这个⽬标的依赖⽂件新于它。
“-p”
“--print-data-base”
输出 makefile 中的所有数据,包括所有的规则和变量。这个参数会让⼀个简单的 makefile都会输出⼀堆信息。如果你只是想输出信息⽽不想执⾏ makefile,你可以使⽤“make -qp”命令。如果你想查看执⾏ makefile 前的预设变量和规则,你可以使⽤make –p –f/dev/null。这个参数输出的信息会包含着你的 makefile ⽂件的⽂件名和⾏号,所以,⽤这个参数来调试你的 makefile 会是很有⽤的,特别是当你的环境变量很复杂的时候。
“-q”
“--question”
不运⾏命令,也不输出。仅仅是检查所指定的⽬标是否需要更新。如果是 0 则说明要更新,如果是 2 则说明有错误发⽣。
“-r”
“--no-builtin-rules”
禁⽌ make 使⽤任何隐含规则。
“-R”
“--no-builtin-variabes”
禁⽌ make 使⽤任何作⽤于变量上的隐含规则。
“-s”
“--silent”
“--quiet”
在命令运⾏时不输出命令的输出。
“-S”
“--no-keep-going”
“--stop”
取消“-k”选项的作⽤。因为有些时候,make 的选项是从环境变量“MAKEFLAGS”中继承下来的。所以你可以在命令⾏中使⽤这个参数来让环境变量中的“-k”选项失效。
“-t”
“--touch”
相当于 UNIX 的 touch 命令,只是把⽬标的修改⽇期变成最新的,也就是阻⽌⽣成⽬标的命令运⾏。
makefile phony“-v”
“--version”
输出 make 程序的版本、版权等关于 make 的信息。
“-w”
“--print-directory”
输出运⾏ makefile 之前和之后的信息。这个参数对于跟踪嵌套式调⽤ make 时很有⽤。
“--no-print-directory”
禁⽌“-w”选项。
“-W <file>”
“--what-if=<file>”
“--new-file=<file>”
“--assume-file=<file>”
假定⽬标<file>需要更新,如果和“-n”选项使⽤,那么这个参数会输出该⽬标更新时的运⾏动作。如果没有“-n”那么就像运⾏ UNIX 的“touch”命令⼀样,使得<file>的修改时间为当前时间。
“--warn-undefined-variables”
只要 make 发现有未定义的变量,那么就输出警告信息。
若想了解关于makefile的更多知识,请参考我的下⼀篇博客
⽂章内容来⾃陈皓的《跟我⼀起写makefile》,转载请注明出处。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论