
Makefile是一种自动化构建工具,make是一条指令,Makefile是一个文件,当我们创建名为Makefile的文件后在Makefile中按照一定的规则制定一些命令。然后我们在命令行输入make命令后会自动执行Makefile文件中的指令。
首先在我们的项目下创建一个名为Makefile或名为makefile的文件,然后使用vim打开进行编辑。
假如我们有一个code.c文件,现在需要编译生成名为code的可执行文件,我们可以在Makefile中这样写:
code:code.c
gcc code.c -o code
依赖关系:就是所要生成的这个目标文件所依赖的文件是哪些。
依赖关系:就是所要生成的这个目标文件所依赖的方法是哪些。
注意:在依赖方法的前面需要加一个Tab制表符,使用4个空格不合法。
在Makefile写完以上指令后我们回到命令行,输入make命令则会有以下效果:

我们使用make指令后它会自动显示出gcc code.c -o code,如果不想让它显示可以在依赖方法前面加@如:
code:code.c
@gcc code.c -o code伪目标文件也就是说它并不会在自己的目录下真生成一个目标文件,它更像是一条指令,用了就没了但是可以多次使用,只要给目标文件用.PHONY修饰那么它就成为伪目标了,如下:
.PHONY:clean
clean:
rm -f code因为生成clean这个目标不需要依赖任何文件所以就不用写。
在命令行执行.PHONY修饰的文件我们需要使用make+伪目标名,比如这里我们可以在命令行输入
make clean在某些时候我们为了方便后期修改通常会用变量来代替各种文件或指令,而在使用时需要用$符号加()可以理解为把它解包装,如把以上的命令全部改为变量的形式:
BIN=code
SRC=code.c
CC=gcc
FLAGS=-o
$(BIN):$(SRC)
$(CC) $(SRC) $(FLAGS) $(BIN)%.o表示所有以.o为结尾的文件,同理%.c表示所有以.c结尾的文件。
$@:所有目标文件
$^:所有依赖的文件
(shell ls *.c)或(wildcard *.c): 在该目录里的所有以.c结尾的文件
$(SRC: .c = .o):SRC变量名表示的文件的.c变成.o生成新的文件名。
那么我们可以做出以下操作:
BIN=code
CC=gcc
#SRC=$(shell ls *.c)
SRC=$(wildcard *.c)
OBJ=$(SRC:.c=.o)
LFLAGS=-o
FLAGS=-c
RM=rm -f
$(BIN):$(OBJ)
@$(CC) $(LFLAGS) $@ $^
@echo "linking ... $^ to $@"
%.o:%.c
@$(CC) $(FLAGS) $<
@echo "compling ... $< to $@"
.PHONY:clean
clean:
$(RM) $(OBJ) $(BIN) 注:
比如我们写这样一段指令:

上面的指令是能正常运行的,但我们发现在执行第一个语块的时候并没有code.o这个依赖文件,code.o需要在下一个语块中才能生成。其实makefile的执行逻辑是这样的,它在执行到一个文件不完整的语块的时候,会类似的先把它放在一个栈结构中然后往后去执行,直到后面的指令执行完需要它出栈的时候才执行,此时如果该语块依旧文件不完整则会报错。
一个目标文件被.PHONY修饰后变成伪目标是可以总是被执行的。而一个普通的目标文件只能被执行一次。这也是一种提高编译效率的方式,因为同样的内容已经生成了一份就没必要多次生成。
而当涉及的依赖文件的内容被修改时make指令才能再次被执行。但是Makefile如何知道某个文件被修改过呢?其实是通过文件的时间属性来判断的,我们可以通过stat+文件名来查看,如:

可以巧记为“ACM”时间。makefile通过比较目标文件与依赖文件的Modify时间,如果依赖文件的Modify时间比目标文件的Modify时间要新,则可以通过make指令再次生成目标文件。
非常感谢您能耐心读完这篇文章。倘若您从中有所收获,还望多多支持呀!