视频:https://www.bilibili.com/video/BV1dW411n7vk?from=search&seid=13869936161616988114
可以试想一下,有一个上百个文件的代码构成的项目,如果其中只有一个或几个文件进行修改,需要从头到尾将每一个文件都重新编译是一个比较繁琐的过程。 为此,引入了Make工程管理器的概念,工程管理器指管理较多文件,自动根据文件时间自动发现更新过的文件而减少编译的工作量,同时通过读入Makefile文件来执行大量的编译工作。
规则:用于说明如何生成一个或多个目标文件
makefile文件里面可以有很多规则,但是第一个规则是最终生成的文件规则。
规则格式:
target: dependency_files // 目标项:依赖项 <tab>command // 必须以tab开头,command编译命令规则就是为了生成某一个文件的。 目标项:这个就是你要生成的文件名 依赖项:要生成目标项需要的文件 编译命令:如果有依赖项生成目标项;必须以TAB开头
在mekefile中,规则的顺序是很重要的。因为,Makefile中只应该有一个最终目标,其他的目标都是被这个目标所连带出来的,所以一定要让make知道你的最终目标是什么。一般来说,定义在Makefile中的目标可能会有很多,但是第一条规则中的目标将被确立为最终的目标
归结:
目标文件不存在,执行命令文件已经更新了,执行命令Makefile的第一条规则为最终的目标。写成makefile如下
创建名称为makefile或者Makefile的文档在文档中输入相应的内容test:test.c gcc -o test test.c 运行makefile文件 命令行输入make如果马上再执行make命令 这是因为,make命令会对比源文件的修改时间,如果早于目标文件,说明源文件没有修改,就不会帮你再次编译了。
test.c
#include <stdio.h> extern void sort(int *arr, int len); extern void show(int *arr, int len); int main(int argc, int **argv) { int arr[] = {3, 2, 1, 5, 9, 8, 7}; int len = sizeof(arr) / sizeof(arr[0]); sort(arr, len); show(arr, len); return 0; } void show(int *arr, int len) { for (int i = 0; i < len; i++) { printf("%d ", arr[i]); } printf("\n"); }sequence.c
void sort(int *arr, int len) { for (int i = 0; i < len; i++) { for (int j = i; j < len; j++) { if (arr[i] > arr[j]) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } } } }makefile
test:test.o sequence.o gcc -o test test.o sequence.o test.o:test.c gcc -o test.o -c test.c sequence.o:sequence.c gcc -o sequence.o -c sequence.c.PHONY是makefile文件中的关键字,表示它后面列表中的目标均为伪目标。
如:
.PHONY:b b: echo 'b' # 通常用@echo "hello"伪目标通常用在清理文件、强制重新编译等情况下。一般伪目标没有时间的检查,一旦指明了就会执行。 如:
.PHONY:clean //".PHONY"将"clean"目标声明为伪目标 clean: rm -f hello main.c func1.o func2.o继续例子2
修改Makefile文件
test:test.o sequence.o gcc -o test test.o sequence.o test.o:test.c gcc -o test.o -c test.c sequence.o:sequence.c gcc -o sequence.o -c sequence.c .PHONY:clean rebuild clean: rm -f test.o sequence.o test rebuild:clean test
注意文件创建时间
随着软件项目的变大、变复杂,源文件也越来越多,如果采用前面的方式写makefile文件,将会使makefile也变得复杂而难于维护。 通过make支持的变量定义、规则和内置函数,可以写出通用性较强的makefile文件,使得同一个makefile文件能够适应不同的项目。
变量:用来代替一个文本字符串 定义变量的2种方法: 变量名=变量值 递归变量展开(几个变量共享一个值) // 不常用 变量名:=变量值 简单变量展开(类似与C++的赋值) // 通常采用这种形式 使用变量的一般方法: $(变量名)=??? // 赋值 ???=$(变量名) // 引用变量分为:用户自定义变量、自动变量、预定义变量、环境变量
如:
OBJS:=test.o add.o EXE:=test.exe $(EXE):$(OBJS) gcc -o $(EXE) $(OBJS) test.o:test.c gccc -c test.c add.o:add.c gcc -c add.c .PHONY:rebuild clean rebuild:clean $(EXE) clean: rm -rf $(EXE) $(OBJS)上面的例子就是用户自定义变量。
值在使用的时候,自动用特定的值替换。 如:
OBJS:=test.o add.o EXE:=test.exe $(EXE):$(OBJS) gcc -o $@ $^ test.o:test.c gcc -c $^ add.o:add.c gcc -c $^ .PHONY:rebuild clean rebuild:clean $(EXE) clean: rm -rf $(EXE) $(OBJS)内部事先定义好的变量,但是它的值是固定的,并且有些值是为空的。
根据内部变量,可以将makefile改写为:TEST_file3文件夹。
OBJS:=test.o add. EXE:=test.exe $(EXE):$(OBJS) $(CC) -o $@ $^ test.o:test.c $(CC) -c $^ add.o:add.c $(CC) -c $^ .PHONY:rebuild clean rebuild:clean $(EXE) clean: $(RM) $(EXE) $(OBJS)普通规则即基本语法规则
另外
makefile里面的注释使用#命令如果不想显示到终端,加@例如:*.o文件自动依赖*.c或*.cc文件,所以可以忽略main.o:main.c等
OBJS:=test.o add.o EXE:=test.exe $(EXE):$(OBJS) $(CC) -o $@ $^ .PHONY:rebuild clean rebuild:clean $(EXE) clean: $(RM) $(EXE) $(OBJS)省略了
通过匹配模式找字符串,%匹配1或多个任意字符串。 %.o:%.cpp表示任何目标文件的依赖文件是与目标文件同名的并且扩展名为.cpp的文件
OBJS:=main.o fun.o main.exe:$(OBJS) gcc $^ -o $@ %.o:%.cpp gcc -o $@ -c $^另外还可以指定将*.o、*.exe、*.a、*.so等编译到指定目录中
DIR:=./Debug/ EXE:=main.exe OBJS:=main.o $(DIR)$(EXE):$(DIR)$(OBJS) gcc -o $@ $< -L ./ -1func $(DIR)main.o:main.c gcc -o $@ -c $^ .PHONY:rebuild clean rebuild:clean $(DIR)$(EXE) clean: rm -rf $(DIR)*.0 $(DIR)*.exe注意: 当OBJS里面有多项的时候,此时$(DIR)$(OBJS)只能影响到OBJS第一个,后面的全部无效,因此需要全部列出来
搜索当前目录下文件名,展开成一列所有符合由其参数描述的文件名,文件间以空格隔开
SOURCES=$(wildcard *.cpp) // 把当前目录下所有.cpp文件存入变量SOURCES里格式:$(patsubst 要查找的子串, 替换后的目标子串, 源字符串) 将源字符串(以空格分隔)中的所有要查找的子串替换成目标子串 如:
OBJS=$(patsubst %.cvpp,%.o,$(SOURCES))把SOURCES中.cpp替换为.o然后把替换后的字符串存入变量OBJS中
格式:$(addprefix 前缀, 源字符串) 该函数把第二个参数列表里的每一项前缀加上第一个参数值。
《GNU make 中文手册.pdf》
DIR:=./build/ OBJS=tt.o ConfigFile.o DEPENDENCES:=$(addprefix $(DIR), $(OBJS)) EXE:=main RM:=rm -rf $(EXE):$(DEPENDENCES) gcc -o $(EXE) $(DEPENDENCES) $(DIR)%.o:%.c gcc -o $@ -g -c $^ .PHONY:rebuild clean rebuild:clean $(EXE) clean: $(RM) $(DIR)* $(EXE)