make

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

发表回复