【Day9】make/makeFile如何让项目构建自动化起飞

发布于:2025-03-06 ⋅ 阅读:(18) ⋅ 点赞:(0)

在Linux中,项目自动化构建是指使用一系列工具和脚本来自动执行软件项目的编译、测试、打包和部署等过程。

make和makefile是linux中常用的项目自动化构建工具。make是一条命令,makefile/Makefile是一个文件。两个搭配使⽤,完成项目自动化构建。

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

在makefile中写好构建步骤,再用make命令启动makefile,整个工程完全“自动化编译”,能极大提高软件开发的效率。

使用make命令

makefile文件的位置:和源文件在同一目录下。

总结make的用法:
make 目标文件:在当前目录下找makefile文件,扫描makefile,并执行目标文件。

make:make命令中如果没有指定目标文件,make命令默认从上往下依次扫描makefile中的内容,默认扫描到的第一个目标文件作为本次要执行的目标文件。

编写makefile文件

依赖管理

一个项目中的源文件之间可能存在各种依赖关系,例如一个源文件可能依赖于其他源文件或头文件,Makefile 明确地定义这些依赖关系(目标(target)、依赖(prerequisites)和规则(rules)),确保在编译时按照正确的顺序进行处理,避免因依赖关系错误导致的编译错误。
例如:
在下面这个makefile文件中,
第一行是依赖关系,第二行是依赖方法。根据依赖关系执行依赖方法
在这里插入图片描述在依赖关系中,目标文件依赖的源文件可以不写明。
用.PHONY修饰的目标文件,表示这个目标文件是一个伪目标。伪目标的特点是伪目标对应的依赖关系和依赖方法总是被执行。也就是,只要makefile中有下面3、4、5行内容,只要make,目标文件对应的依赖方法被执行的同时,3、4、5行内容是一定会执行的。
3、4、5行的意思是清除所有生成的目标文件。
在这里插入图片描述

增量构建

全量构建:在目标文件和对应的所有依赖文件中,哪怕只有一个文件被修改过,再次make目标文件的时候,对应的所有依赖文件都要重新编译然后链接。
增量构建:再次make目标文件的时候,Makefile 会检查文件的修改时间,如果依赖文件比目标文件更新,就重新编译这个依赖文件。
在这里插入图片描述

伪目标对应的依赖关系和依赖方法总是被执行,总是被执行即忽略对比modify时间。

例如:
在这里插入图片描述
在这里插入图片描述
自己的程序不建议使用.PHONY修饰。
什么叫做不被执行?
场景:假设一个可执行程序依赖了100个源文件,但如果此时我们对其中一个源文件做出了修改,我们并不需要重新编译所有源文件。
只有make伪目标文件的时候,伪目标对应的依赖关系和依赖方法才总是被执行。
该可执行程序不是伪目标文件,所以gcc在重新编译时,老代码没被修改过且是不被执行的,不会被重新编译,gcc只会把修改过的代码重新编译下。

make命令怎么知道:二进制文件(依赖文件被编译成.o文件)和源文件(目标文件的依赖文件)哪个修改时间更新呢?
通过文件的Modify属性判断。Modify属性是文件/目录的内容最后一次被修改的时间。可以使用stat命令查看文件/目录的详细信息。

makefile注释:#

在这里插入图片描述

makefile其他语法

Makefile 支持变量、条件判断、函数和外部脚本调用,可以灵活扩展构建逻辑。

例如:

BIN=proc.exe  # 定义变量
CC=g++ 
SRC=myproc.c 
OBJ=myproc.c
LFLAGS=-o
FLAGS=-c

.PHONY:test 
test: 
	@echo $(SRC) # 命令前面加@,表示make的时候只显示结果,不回显命令
	echo $(CC) # $(CC):最开始我们定义了变量CC,此时$(CC)等价gcc。$()的意思是把此处内容替换成括号里的

$(BIN):$(SRC)
	@$(CC) $(LFLAGS) $@ $^ # $@:代表⽬标⽂件名,此时相当于$(BIN)。 $^: 代表依赖⽂件列表,此时相当于$(SRC)
	@echo "linking ... $^ to $@"

# 依赖文件不止一个时可以像下面这样写:
%.o:%.c              #  %相当于makefile中的通配符
	$(CC) $(FLAGS) $<  #  $<的意思是对匹配到的.c文件,依次交给gcc
	@echo "compling ... $^ to $@"

SRC1=$(shell ls *.c)   # 在makefile中可以直接使用linux命令,方法是`shell 命令`。所以这句的意思是显示所有.c文件,并把它们放到SRC1中。

SRC2=$(wildcard *.c) # makefile内部也有函数,其中函数wildcard的功能是获取符合特定模式的文件名列表。所以`wildcard *.c`的意思是获取当前所有后缀是.c的⽂件。

SRC3=$(SRC:.c=.o)  # 将SRC的所有同名.c 替换 成为.o 形成⽬标⽂件列表 

make/makefile递归式工作过程

目录中存在myproc.c文件。
以下面内容为例展示makefile的工作过程:

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命令执行makefile后,(默认只输⼊make命令),则:

  1. make会在当前⽬录下找名字叫“Makefile”或“makefile”的⽂件。
  2. 如果找到,它会找⽂件中的第⼀个⽬标⽂件(target),在上⾯的例⼦中,他会找到 myproc 这个⽂件,并把这个⽂件作为最终的⽬标⽂件。
  3. 如果 myproc ⽂件不存在,或是 myproc 所依赖的后⾯的 myproc.o ⽂件的⽂件修改时间要⽐ myproc 这个⽂件新,那么,他就会执⾏后⾯所定义的命令来⽣成
    myproc 这个⽂件。
  4. 如果 myproc 所依赖的 myproc.o ⽂件不存在,那么 make 会在当前⽂件中找⽬标为
    myproc.o ⽂件的依赖性,如果找到则再根据那⼀个规则⽣成 myproc.o ⽂件。makefile工作时会维护一个类似于栈的东西
  5. 依次类推(相当于进栈过程)。
  6. 当前目录下存在myproc.c文件,经过编译后make 会⽣成myproc.i ⽂件(相当于出栈过程)。最终,make 会⽣成myproc.o ⽂件,然后myproc.o ⽂件编译后,形成最终的目标文件myproc。
  7. 这就是整个make的依赖性,make会⼀层⼜⼀层地去找⽂件的依赖关系,直到最终编译出第⼀个⽬标⽂件。
  8. 在找寻的过程中,如果出现错误,⽐如最后被依赖的⽂件找不到,那么make就会直接退出,并报错。make只管⽂件的依赖性,即,如果在我找了依赖关系之后,冒号后⾯的⽂件还是不在,那么对不起,我就不⼯作啦。对于其他错误,make根本不理。

在这里插入图片描述


下次见~

在这里插入图片描述