Author:Once day date:2022年7月28日
推荐参考文档:makefile隐含规则_csdn博客_陈皓
make命令执行后有三个退出码:
0,表示成功执行
1,如果make运行时出现任何错误,其返回1
2,如果你使用了make的“-q”选项,并且make使得一些目标不需要更新,那么返回2。
默认的情况下一般采用“Makefile”和“makefile”的默认文件名。
可以使用-f
或--file
参数来指定文件:
make -f onceday.mk
一般makefile的最终目标是makefile中的第一个目标,其他的目标一般是由这个目标连带出来。
可以通过以下语句来制定目标:
make label
有一个make的环境变量叫“MAKECMDGOALS”,会存放所指定的终极目标的列表,如果命令行上,没有指定目标,那么这个变量是空值。
配合使用终极目标和伪目标:
.PHONY: all
all: once day
当执行make all
便会同时完成once
和day
两个目标。
GNU常用的伪目标名称有以下这些(具体功能需要自己实现):
“all”,编译所有的目标
“clean”,删除所有被make创建的文件
“install”,安装已编译好的程序 ,本质是把目标执行文件拷贝到指定目标中
“print”,列出改变过的源文件
“tar”, 把源程序打包备份,生成tar文件
“dist”,创建一个压缩文件, 一般是把tar文件压成Z文件 ,或者gz文件。
“TAGS”,更新所有的目标,以备完整地
”check“和”test“,用来测试makefile的流程
不让makefile中的规则执行起来,只想检查一下我们的命令,或是执行的序列。
"-n"
"--just-print"
"--dry-run"
"--recon"
不执行参数,这些参数只是打印命令,不管目标是否更新,把规则和连带规则下的命令打印出来,但不执行。
"-t"
"--touch"
这个参数的意思就是把目标文件的时间更新,但不更改目标文件。也就是说,make假装编译目标,但不是真正的编译目标,只是把目标变成已编译过的状态。
"-q"
"--question"
这个参数的行为是找目标的意思,也就是说,如果目标存在,那么其什么也不会输出,当然也不会执行编译,如果目标不存在,其会打印出一条出错信息。
"-W "
"--what-if="
"--assume-new="
"--new-file="
这个参数需要指定一个文件。一般是是源文件(或依赖文件),Make会根据规则推导来运行依赖于这个文件的命令,一般来说,可以和“-n”参数一同使用,来查看这个依赖文件所发生的规则命令。
"-b"
"-m"
"-B"
"--always-make"
"-C "
"--directory="
make -C once/once -C day
make -C once/once/day #这两条语句等价
如果有多个“-C”参数,make的解释是后面的路径以前面的作为相对路径,并以最后的目录作为被指定目录。
"-d"
"--debug[=options]"
--debug
输出最简单的调试信息,-d
输出所有的调式信息。
以下是可选的几个级别:
a:all,输出所有的调试信息
b:basic,只输出简单的调试信息,即不需要重编译的目标
v:verbose,输出的信息包括哪个makefile被解析,不需要被重编译的依赖文件(或是依赖目标)等
i:implicit,输出所有的隐含规则
j:jobs:输出执行规则中命令的详细信息,如命令的PID,返回码等
m:makefile,输出make读取makefile,更新makefile,执行makefile的信息
"-e"
"--environment-overrides"
"-f="
"--file="
"--makefile="
"-i"
"--ignore-errors"
"-I "
"--include-dir="
可以使用多个“-I”参数来指定多个目录
"-j []"
"--jobs[=]"
如果没有这个参数,make运行命令时能运行多少就运行多少。
"-k"
"--keep-going"
如果生成一个目标失败了,那么依赖于其上的目标就不会被执行了
"-l "
"--load-average[=]"
"--max-load[=]"
"-o "
"--old-file="
"--assume-old="
"-p"
"--print-data-base"
输出makefile中的所有数据,包括所有的规则和变量。
只想输出信息而不想执行makefile,可以使用make -qp
。
查看执行makefile前的预设变量和规则,可以使用make -p -f /dev/null
"-q"
"--question"
不运行命令,也不输出。仅仅是检查所指定的目标是否需要更新。如果是0则说明要更新,如果是2则说明有错误发生。
"-r"
"--no-builtin-rules"
"-R"
"--no-builtin-variables"
"-s"
"--silent"
"--quiet"
-k
的作用"-S"
"--no-keep-going"
"--stop"
"-w"
"--print-directory"
#以下命令禁止“-w”选项
"--no-print-directory"
"--warn-undefined-variables"
只要make发现有未定义的变量,那么就输出警告信息。
make会有一些默认的规则,如根据[.o]文件反推出[.c]文件。
没有必要使用隐含规则,因此这里省略。
一般使用以下几个变量:
CC,默认gcc
CXX,默认g++
CFLAGS,C语言编译器参数
CXXFLAGS,C++语言编译器参数
"%“的展开发生在变量和函数的展开之后,变量和函数的展开发生在make载入Makefile时,而模式规则中的”%"则发生在运行时。
一个模式规则就好像一个一般的规则,只是在规则中,目标的定义需要有"%“字符。”%“的意思是表示一个或多个任意字符。在依赖目标中同样可以使用”%“,只是依赖目标中的”%"的取值,取决于其目标。
示例:
%.o :%.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
可以把所有的[.c]文件都编译成[.o]文件。
所谓自动化变量,就是这种变量会把模式中所定义的一系列的文件自动地挨个取出,直至所有的符合模式的文件都取完了。这种自动化变量只应出现在规则的命令中。
$@
,表示规则中的目标文件集。在模式规则中,如果有多个目标,那么,"$@"就是匹配于目标中模式定义的集合。
$%
,仅当目标是函数库文件中,表示规则中的目标成员名,例如,如果一个目标是"foo.a (bar.o)“,那么,”
%"就是"bar.o","
@“就是"foo.a”。如果不是,则其值为空。
$<
,依赖目标中的第一个目标名字。如果依赖目标是以模式(即"%“)定义的,那么”$<"将是符合模式的一系列的文件集。注意,其是一个一个取出来的。
$?
,所有比目标新的依赖目标的集合。以空格分隔。
$^
,所有的依赖目标的集合。以空格分隔。如果在依赖目标中有多个重复的,那个这个变量会去除重复的依赖目标,只保留一份。
$+
,所有依赖目标的集合,但是不去除重复的依赖目标。
$*
,表示目标模式中"%“及其之前的部分,如果目标是"dir/a.foo.b”,并且目标的模式是"a.%.b",那么,"$*“的值就是"dir/a.foo”。
模式匹配的茎有以下两种:
%.c #1245.c
src/1%5.c #src/1245.c
对于%.c
其茎为:1245
,对于src/a%c.c
,其茎为:src/24
。这些将被传递到这个模式的其他目标中。如%.o
,则两个对应的是1245.o
和src/24.c
可以像以下这样重载内建隐含规则:
%.o :%.c
$(CC) -c $(CPPFLAGS) $(CFLAGS) -D$(date)
如果命令处空白,则等价于取消内建的隐含规则。
make会对内建的后缀规则(如.o,.c)自动使用模式匹配,如果其对应的隐含规则所需的依赖文件存在,那么就会采纳该隐藏规则!
可以取消隐藏规则,来加快处理速度,以及避免未知错误。
函数库文件也就是对Object文件(程序编译的中间文件)的打包文件。在Unix下,一般是由命令"ar"来完成打包工作。
一个函数库文件由多个文件组成,以如下格式指定函数库文件及其组成:archive(member)
foolib(once.o day.o)
foolib(*.o)
括号类的成员会被当前目标来搜索,因此,它依赖于隐藏规则来工作。
可借助后缀规则和隐含规则来生成函数库打包文件。
(%.o) : %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $*.o
$(AR) r $@ $*.o
$(RM) $*.o