自动化构建-make/Makefile

58 阅读4分钟

1 背景

• 会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力

• 一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作

• makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。

• make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,makefile都成为了一种在工程方面的编译方法。

make是一条命令,makefile是一个文件,两个搭配使用,完成项目自动化构建。

2 基本使用

实例代码

#include <stdio.h>
int main()
{
printf("hello Makefile!\n");
return 0;
}

Makefile文件

code:code.c
    gcc -o code code.c
.PHONY:clean
clean:
    rm -f code

依赖关系

• 上面的文件code,它依赖code.c

依赖方法

• gcc -o code code.c ,就是与之对应的依赖方法

项目清理

• 工程是需要被清理的

• 像clean这种,没有被第一个目标文件直接或间接关联,那么它后面所定义的命令将不会被自动执行,不过,我们可以显示要make执行。即命令——“make clean”,以此来清除所有的目标文件,以便重编译。

• 但是一般我们这种clean的目标文件,我们将它设置为伪目标,用 .PHONY 修饰,伪目标的特性是,总是被执行的。

测试:

我们可以看到,make后code.c文件自动编译成为code可执行文件,make clean 后code文件被删除

什么叫做总是被执行?

当一个文件被编译好了就不需要再次被编译了,这样做可以节省计算机资源,但是make/makefile又怎么知道该文件是否需要被编译呢?

这就需要查看文件的状态了

3 make是如何工作的

myproc:myproc.o
    gcc myproc.o -o myproc
myproc.o:myproc.s
    gcc -c myproc.s -o myproc.o
myproc.s:myproc.i
    gcc -S myproc.i -o myproc.s
myproc.i:myproc.c
    gcc -E myproc.c -o myproc.i
.PHONY:clean
clean:
    rm -f *.i *.s *.o myproc

在默认的方式下,也就是我们只输入make命令。那么:

  1. make会在当前目录下找名字叫“Makefile”或“makefile”的文件。

  2. 如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到myproc 这个文件,并把这个文件作为最终的目标文件。

  3. 如果myproc 文件不存在,或是myproc 所依赖的后面的myproc.o 文件的文件修改时间要比 myproc 这个文件新(可以用 touch 测试),那么,他就会执行后面所定义的命令来生成myproc 这个文件。

  4. 如果myproc 所依赖的myproc.o 文件不存在,那么make 会在当前文件中找目标为myproc.o 文件的依赖性,如果找到则再根据那一个规则生成myproc.o 文件。(这有点像一个堆栈的过程)

  5. 当然,你的C文件和H文件是存在的啦,于是make 会生成 myproc.o 文件,然后再用myproc.o 文件声明make 的终极任务,也就是执行文件hello 了。

  6. 这就是整个make的依赖性,make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。

  7. 在找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么make就会直接退出,并报错,而对于所定义的命令的错误,或是编译不成功,make根本不理。

  8. make只管文件的依赖性,即,如果在我找了依赖关系之后,冒号后面的文件还是不在,那么对不起,我就不工作啦。

4 适度扩展语法

BIN=proc.exe 	# 定义变量
CC=gcc
                    #SRC=$(shell ls *.c) 	# 采用shell命令行方式,获取当前所有.c文件名
SRC=$(wildcard *.c) 	# 或者使用 wildcard 函数,获取当前所有.c文件名
OBJ=$(SRC:.c=.o) 	# 将SRC的所有同名.c 替换 成为.o 形成目标文件列表
LFLAGS=-o 	# 链接选项
FLAGS=-c 	# 编译选项
RM=rm -f 	# 引入命令
                                	# @:不回显命令
$(BIN):$(OBJ)
    @$(CC) $(LFLAGS) $@ $^ 		# $@:代表目标文件名。 $^: 代表依赖文件列表
    @echo "linking ... $^ to $@"
%.o:%.c 			# %.c 展开当前目录下所有的.c。 %.o: 同时展开同名.o
@$(CC) $(FLAGS) $< 		# %<: 对展开的依赖.c文件,一个一个的交给gcc。
@echo "compling ... $< to $@" 
.PHONY:clean
clean:
    $(RM) $(OBJ) $(BIN) 	# $(RM): 替换,用变量内容替换它
.PHONY:test
test:
    @echo $(SRC)
    @echo $(OBJ)

测试:

到此,自动化构建-make/Makefile就讲完了,怎么样,是不是感觉大脑里面多了很多新知识。

如果觉得博主讲的还可以的话,就请大家多多支持博主,收藏加关注,追更不迷路

如果觉得博主哪里讲的不到位或是有疏漏,还请大家多多指出,博主一定会加以改正

博语小屋将持续为您推出文章