文章目录
Linux项目自动化构建工具-make/Makefile语法规则make/Makefile工作原理目标文件生成规则终极目标ACM时间 变量赋值直接赋值立即赋值条件赋值追加赋值使用环境变量 特殊变量使用变量伪目标 .PHONY嵌套执行Makefile
Linux项目自动化构建工具-make/Makefile
学会使用Makefile可以极大的提高了软件开发的效率,makefile的特色“自动化编译”,使得我们一旦写好makefile,只需要一个make命令,整个工程完全自动编译。同时是否会写makefile,也从一个侧面说明了一个人是否具备完成大型工程的能力。
通过make命令,与makefile文件,两个搭配使用,完成项目自动化构建。
讲是这么讲,makefile到底怎么就提高了我们软件开发的效率呢?
先来看一看如果没有makefile我们编写程序到底会多麻烦
我们有两个简单的文件,其实现如下图所示
现在我们要制作一个属于自己的MyMath库,并将其发布,如果没有makefile我们要怎么做?
gcc -c my_add.c my_sub.c //生成可重定位二进制文件 ar -rc libMyMath.a my_add.o my_sub.o //生成库文件 mkdir -p mylib/include //创建目录结构 mkdir -p mylib/lib //创建目录结构 cp -rf *.h mylib/include/ //拷贝文件到对应目录 cp -rf *.a mylib/lib/ //拷贝文件到对应目录 tar czf mylib.tgz mylib //打包
最终结果如下:
现在我们有了makefile就可以大大提高工作效率
我们在命令行运行makefile生成目标文件,make output发布我们自己的库,make clean清理文件。
现在知道为什么说makefile可以极大提高开发效率了吧。
现在我们就来正式学习如何使用makefile吧。
语法规则
目标文件:依赖文件列表 依赖方法 #注意依赖方法前面要有一个TAB键
1.目标文件:我们要生成的文件。
2.依赖文件列表:简单来讲就是目标文件需要哪些文件用来生成目标文件。
3.依赖方法:就是目标文件如何用依赖文件列表中的文件来生成目标文件。
make/Makefile工作原理
make是如何工作的,在默认的方式下,也就是我们只输入make命令。那么:
make会在当前目录下找名字叫“Makefile”或“makefile”的文件。如果找到,它会找文件中的第一个目标文件(target),并把这个文件识别为 终极目标根据目标文件是否存在以及目标文件所依赖文件ACM时间来决定是否会生成目标文件。如果目标文件的依赖文件同时也依赖其他文件生成,make就会解决目标文件依赖文件的依赖关系,这就是整个make的依赖性,make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。在找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么make就会直接退出,并报错,而对于所定义的命令的错误,或是编译不成功,make根本不理。make只管文件的依赖性即,如果在我找了依赖关系之后,冒号后面的文件还是不在,那么对不起,我就挂掉了。目标文件生成规则
终极目标
对于我们的makefile可能其目的是要生成多个目标文件,但是makefile会默认从上向下扫描文件,并且把识别到的第一个文件识别为终极目标文件,且只会生成这个终极目标文件。
如下:
在此文件中有两个目标文件,我们运行make
MAKE:
如我们所预料,只生成了一个目标文件,如何生成所有目标文件呢,接着往下看
我们可以通过all 指定所需要生成的目标文件
MAKE:
如上图所示,存在回显问题,如果想要取消回显,可在makefile文件中在指令前面加@
MAKE:
ACM时间
对于我们多次运行make生成目标文件,会发生什么?
它会告知我们目标文件已经存在。
如果我们touch更新目标文件时间呢?
文件重新生成。
结论:当我们已经存在该目标文件时,make后目标文件是否会重新生成取决于该目标文件所依赖文件的ACM时间(严格来讲是M时间)
那到底什么是ACM时间呢?
1.A(access时间):即文件最后一次访问时间,对于我们频繁访问某一文件,并不是每一次访问都会更新该文件的A时间,在我们访问该文件后短时间内再次访问并不会更新A时间。
2.C(change时间):即文件最后一次属性修改时间(一个文件由内容与属性所构成)
3.M(modify时间):即文件最后一次内容修改时间。(修改文件内容必定引起AC时间改变)
我们可以通过stat指令查看文件的ACM时间。
变量赋值
以下用A B C代指某些文件例如main.c文件或指令例如gcc main.c
直接赋值
直接赋值是最简单的方式,只需要使用 = 符号。这种方式定义的变量被称为递归扩展变量,其值为整个Makefile中最后被指定的值。
VARIABLE_A=AVARIABLE_B=$(VARIABLE_A) B #$(VARIABLE_A)表示取VARIABLE_A值VARIABLE_A=AA
最后VARIABLE_B的值为AA B
立即赋值
使用 := 符号进行赋值会立即扩展变量的值,这种方式定义的变量被称为简单扩展变量.
SIMPLE_VARIABLE := $(ANOTHER_VARIABLE)
在这个例子中,SIMPLE_VARIABLE 会立即被赋值为 ANOTHER_VARIABLE 的值。如果 ANOTHER_VARIABLE 在后面被改变,SIMPLE_VARIABLE 的值不会受到影响。
条件赋值
你可以使用条件语句来为变量赋值,例如:
ifeq ($(DEBUG),1) #ifeq 是条件指令,用于比较两个参数是否相等 DEBUG_FLAGS = Aelse DEBUG_FLAGS = Bendif
在这个例子中,DEBUG_FLAGS 会根据 DEBUG 变量的值被赋予不同的值。
?=赋值
MY_VARIABLE?=default_value
在这个例子中,如果 MY_VARIABLE 在这个 Makefile 或任何包含它的 Makefile 中之前没有被设置过值,那么它就会被设置为 default_value。但是,如果 MY_VARIABLE 在这之前已经被设置过了,那么它就不会被 default_value 覆盖。
追加赋值
使用 += 符号可以将值追加到变量的现有值上。
OBJECTS = A B OBJECTS += C
在这个例子中,OBJECTS 变量最初包含 A 和B,然后C被追加到它的值上。
使用环境变量
Makefile 中的变量也可以从环境变量中继承。如果你想在 Makefile 中使用环境变量的值,你可以直接引用它。
CC = $(CC_ENV)
在这个例子中,如果环境变量 CC_ENV 存在,它将被赋值给 CC 变量。
特殊变量
$@ #表示目标文件$^ #表示依赖文件列表&< #表示依次取依赖文件列表文件生成对应目标文件
使用变量
$符号表示取变量的值,当变量名多于一个字符时,使用"( )"
伪目标 .PHONY
伪目标是一个特殊的目标,它不代表一个真实的文件。形象的来讲它只是一个标签,用于执行与该目标关联的命令。因为伪目标不代表任何文件,所以make工具不会检查文件系统来确定该目标是否已经是最新的。这意味着,无论何时你尝试构建这个伪目标,与其关联的命令都会被执行。
假设当前目录下存在一个名为clean的文件和一个Makefile文件,Makefile文件内容如下:
clean:rm temp
当我们执行make clean命令后,目标clean并不会被执行,因为make会首先查找名为clean的文件,而不是将clean作为目标来执行,又因为我们不会生成新的clean文件,所以使得clean文件的ACM时间一直被判定为最新时间,导致不会执行clean,为了解决这个问题,可以在Makefile文件中将clean声明为伪目标,修改后的Makefile文件内容如下:
.PHONY: cleanclean:rm temp
再次执行make clean命令后,伪目标clean就会被执行,从而删除temp文件或目录(如果存在的话)。
伪目标用途:伪目标在Makefile中的作用主要是用来定义一些不代表实际文件的目标,这些目标通常用于执行一些额外的操作,比如清理临时文件、生成文档、运行测试等。使用伪目标可以将这些操作集中到一个目标中,方便管理。同时,伪目标还可以用来定义一些常用的操作,比如编译、运行、安装等,以及定义依赖关系,确保目标的正确顺序。
嵌套执行Makefile
嵌套 Makefile 是指在一个 Makefile 中包含另一个 Makefile。这种技术常用于大型项目中,将项目划分为多个子目录或子模块,每个子目录或子模块都有自己的 Makefile,然后在主 Makefile 中包含这些子 Makefile。
现在有以下结构:
主makefile文件内容如下:
嵌套执行makefile语法规则:
在主makefile中,执行
make -C 路径
两个子makefile文件内容如下(两个子makefile内容相同):
MAKE:
MAKE CLEAN:
本章到此结束,感谢阅读!