【Linux】自动化构建-make/Makefile
目录
一、简介
背景
什么是make/makefile
二、make/makefile的使用
三、推导过程
扩展语法
合集传送门:Linux_uyeonashi的博客-CSDN博客
一、简介
背景
• 会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力
• 一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作
• makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。
什么是make/makefile
• make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,makefile都成为了一种在工程方面的编译方法。
• make是一条命令,makefile是一个文件,两个搭配使用,完成项目自动化构建。
二、make/makefile的使用
示例代码:
#include <stdio.h>
int main()
{
printf("hello Makefile!\n");
return 0;
}
Makefile:
myproc:myproc.c
gcc -o myproc myproc.c
.PHONY:clean
clean:
rm -f myproc
依赖关系:上⾯的⽂件myproc,它依赖myproc.c
依赖方法:gcc -o myproc myproc.c ,就是与之对应的依赖关系
.PHONY:clean
• 工程是需要被清理的
• 像clean这种,没有被第一个目标文件直接或间接关联,那么它后面所定义的命令将不会被自动行,不过,我们可以显示要make执行。即命令——“make clean”,以此来清除所有的目标文件,以便重编译。
• 但是一般我们这种clean的目标文件,我们将它设置为伪目标,用 .PHONY 修饰,伪目标的特性是,总是被执行的。
什么叫做总是被执行?
$ stat XXX
File: ‘XXX’
Size: 987 Blocks: 8 IO Block: 4096 regular file
Device: fd01h/64769d Inode: 1321125 Links: 1
Access: (0664/-rw-rw-r--) Uid: ( 1000/ whb) Gid: ( 1000/ whb)
Access: 2024-10-25 17:05:30.430619002 +0800
Modify: 2024-10-25 17:05:25.940595116 +0800
Change: 2024-10-25 17:05:25.940595116 +0800
文件 = 内容 + 属性
Modify: 内容变更,时间更新
Change:属性变更,时间更新
Access:常指的是文件最近一次被访问的时间。在Linux的早期版本中,每当文件被访问时,其atime
都会更新。但这种机制会导致大量的IO操作。具体更新原则,不做过多解释。
查看状态, 我们可以看到以下三个时间。
文件 = 内容 + 属性
以下简称acm时间, a表示最近一次访问的时间, M表示内容最近被修改的时间, C表示最近一个属性被修改的时间。
例如 :
cat proc.c就是访问文件(但是访问频繁影响效率, 现在的操作系统已经这一块已经发生了变化。)
chmod o-r proc.c 就是改变属性
vim proc.c 就是修改内容
但是内容被修改可能发生属性的联动, 因为文件的大小变了。
不管是源文件, 还是可执行程序, 都是文件, 程序可不可总是被执行就是看mtime的时间, 如果没有修改proc.c的m时间,只修改了proc.exe的时间, 那么表示exe比.c更新,编译器就认为没有必要再重新编译了, 相反如果.c的mtime时间更新,那么就可以重新编译生成新的可执行程序
三、推导过程
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
gcc -E myproc.c -o myproc.i
gcc -S myproc.i -o myproc.s
gcc -c myproc.s -o myproc.o
gcc myproc.o -o myproc
make是如何工作的,在默认的方式下,也就是我们只输入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只管文件的依赖性,即,如果在我找了依赖关系之后,冒号后面的文件还是不在,那么对不起,我就不工作啦。
扩展语法
% 是makefile中的通配符
例如: %.c: 当前目录下所有.c文件, 展开到依赖项中。
依赖关系:右侧的依赖文件, 一个一个的交给gcc -c选项, 形成同名的.o文件。
$@表示目标文件, $^表示所有依赖文件的文件列表
默认情况下, makefile执行到了一个目标文件之后就会停下来, 比如下图, 只会生成一个proc文件
如果想进行多个文件同时编译,则可以添加目标all,但是不给执行方法, 为了形成目标all,makefile就会像下面搜索依赖项,形成proc和code。
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)
本篇完,下篇见!