make命令内置了很多智能的机制,除此还提供一个Makefile文件,来告诉它处理流程,文件由一组依赖关系和规则组成,而每个依赖关系由一个目标和该目标的一些依赖组成,规则描述了这些依赖如何创建目标;make命令会先读取Makefile文件内容,确定目标文件,然后会创建一些中间目标,最终根据Makefile确定目标文件创建过程以及调用顺序
make命令一般有三个选项
-k:make执行时如果出错仍然继续执行,不会因为第一个出错而停止,通过这个选项执行可以一次性知道所有没编译通过的源文件
-n:让make命令输出操作步骤,而不是执行这些操作
-f:这个选项指定真正要使用的Makefile文件名
1:依赖关系
Makefile语法规则先写目标名,然后冒号,接着空格或者tab,最后各个源文件中用空格或者tab隔开
lihui: main.o 1.o 2.o main.o: main.c a.h 1.o: a.h b.h 1.c 2.o: b.h c.h 2.c
目标文件lihui依赖于main.o,a.o和b.o;main.o依赖于main.c和a.h
如果想一次性创建多个文件,可以通过伪目标all,如果没有指定一个all目标,那么make命令只会创建Makefile里指定的第一个目标
假如应用程序由可执行程序lihui和用户手册lihui.1组成,那么Makefile里可以这么写:
all: lihui lihui.1
2:规则
上面每行都指明了依赖关系,但是具体实施得需要一些规则,也就是目标的具体创建方式,也就是上面一些库文件和可执行程序的生成方式,比如想生成1.o,只需要执行gcc –c 1.c就行了,但其实make内置了很多默认规则,如果复杂一点,需要指定头文件目录,或者为了调试需要设置符号信息选项等,都必须在Makefile里明确定义一些规则
Makefile的语法有些要注意,空格和tab是有区别的,规则每行的开头,必须是制表符tab而不能用空格,不管你tab设置的是多少空格,你用空格代替都是不行的,在vim里可以根据颜色判断对错,而且Makefile里某行如果以空格结尾,也有可能导致执行失败
根据上面的例子,构造一些规则,源文件就随便写下,而头文件就无所谓了,直接touch几个空头文件即可:
$ touch a.h $ touch b.h $ touch c.h $ cat main.c #include <stdio.h> #include "a.h" int main(){ fun1("From function 1!"); fun2("From function 2!"); return 0; } $ cat 1.c #include <stdio.h> #include "a.h" #include "b.h" int fun1(char *str){ printf("%s\n", str); return 0; } $ cat 2.c #include <stdio.h> #include "b.h" #include "c.h" int fun2(char *str){ printf("%s\n", str); return 0; }
根据source code可以看到依赖关系,根据上面目标文件以及库的依赖关系,可以写出下面的Makefile:
lihui: main.o 1.o 2.o gcc -o lihui main.o 1.o 2.o main.o: main.c a.h gcc -c main.c 1.o: a.h b.h 1.c gcc -c 1.c 2.o: b.h c.h 2.c gcc -c 2.c
上面是依赖关系,下面抬头Tab之后就是执行规则,十分清晰
在执行make的时候,如果不加-f选项,会默认执行Makefile,而不是其它Makefile文件,我这里用的是cygwin,所以可执行程序lihui后面会加一个后缀exe
$ make gcc -c main.c gcc -c 1.c gcc -c 2.c gcc -o lihui main.o 1.o 2.o $ ./lihui.exe From function 1! From function 2!
这样make就执行正常,可执行程序也运行正常
假如将中间库2.o给删除,make还是会采取正确的步骤,并以最少的命令和顺序操作
$ rm -f 2.o $ make gcc -c 2.c gcc -o lihui main.o 1.o 2.o