一、基本原理Makefile 是由工具 make 使用的配置文件。make 会读取 Makefile 中的内容根据定义的规则和依赖关系来构建目标文件。make 工作方式1.查找目标文件是否存在。2.如果目标文件不存在或者其依赖文件的修改时间比目标文件更新则执行相应的命令生成目标文件。二、基本语法target: dependencies commandtarget生成的目标文件或目标名称dependencies生成目标文件所依赖的文件名称command生成目标文件的命令必须以Tab开头三、实践出真知以此目录结构下的文件做测试将逐步深入介绍。1、自定义变量使用自定义变量优先使用海象运算符:。2025.09.03更新了内容# 使用 VAR1 hello VAR2 $(VAR1) VAR1 world # 最终 VAR2 的值是 world因为 VAR1 在使用时才展开 # 使用 : VAR1 : hello VAR2 : $(VAR1) VAR1 : world # 最终 VAR2 的值是 hello因为 VAR1 在定义 VAR2 时已经展开了# 自定义变量 target main dep add.o sub.o main.o # 使用$()获取变量 $(target):$(dep) g $(dep) -o $(target) add.o: g -c add.cpp -o add.o sub.o: g -c sub.cpp -o sub.o main.o: g -c main.cpp -o main.o clean: rm $(dep) $(target)1.执行 make 时不指定目标名称默认执行第一个目标。2.当依赖文件不存在make 会根据已有规则尝试构建。make 找不到规则则执行错误。3.一般目标名称不能为空它指引着 make 的操作。4.依赖名称可以为空命令中指定着所需要的依赖文件。运行情况如下2、内置变量CXX 默认 g指定c编译器。CC 默认 cc指定c编译器。RM 默认 rm -f 删除文件命令。...使用内置变量target main dep add.o sub.o main.o $(target):$(dep) $(CXX) $(dep) -o $(target) add.o: $(CXX) -c add.cpp -o add.o sub.o: $(CXX) -c sub.cpp -o sub.o main.o: $(CXX) -c main.cpp -o main.o clean: $(RM) $(dep) $(target)如果自定义变量名与内置变量名重复优先使用自定义变量。3、自动变量$表示目标文件名称包含文件扩展名。$^依赖项中所有不重复的依赖文件。$依赖项中第一个依赖文件名称。...使用自动变量# 自定义变量 target main dep add.o sub.o main.o # 自定义变量覆盖内置变量 CXX g $(target):$(dep) $(CXX) $^ -o $ #使用自动变量 add.o: $(CXX) -c add.cpp -o add.o sub.o: $(CXX) -c sub.cpp -o sub.o main.o: $(CXX) -c main.cpp -o main.o clean: $(RM) $(dep) $(target)4、模式匹配%通配符。使用模式匹配# 自定义变量 target main dep add.o sub.o main.o # 自定义变量覆盖内置变量 CXX g $(target):$(dep) $(CXX) $^ -o $ # 使用自动变量 %.o:%.cpp # 使用模式匹配将所有.cpp文件编译为.o文件 $(CXX) -c $ -o $ clean: $(RM) $(dep) $(target)1. * 通常用于文件名匹配或 wildcard 函数中表示任意数量的字符。2. % 用于模式规则中表示一个模式中的任意字符串用于定义通用的构建规则。5、函数使用方式$(函数名 参数1参数2...)多参数使用逗号隔开。wildcard pattern...只有一个参数指定某个或多个目录下的某种类型文件多个目录使用空格隔开。返回所匹配的文件列表。patsubst pattern,replacement,text将 text 中匹配 pattern 的部分替换为replacement。...使用函数# 自定义变量 target main obj $(wildcard *.cpp) # 使用wildcard函数找到匹配的文件 dep $(patsubst %.cpp, %.o, $(obj)) # 使用patsubst函数对内容替换 # 自定义变量覆盖内置变量 CXX g $(target):$(dep) $(CXX) $^ -o $ # 使用自动变量 %.o:%.cpp # 使用模式匹配 $(CXX) -c $ -o $ clean: $(RM) $(dep) $(target)结果展示6、使用.PHONY假设在项目文件夹内有一个文件名称和 Makefile 中的目标名称一致在使用 make 构建项目时make 会认为这个目标文件已被构建完成而不继续执行命令。对于一些目标名称只是表示一些动作或任务时这并不会产生目标文件。那么这时候就会有冲突。此时我们就可以使用 .PHONY 来告诉 make 这些目标文件是虚拟的不应该被视为文件。此时我们自己创建了一个文件名为 clean 的文件可以发现当我们使用 make clean 指令时并没有按预期执行命令而是提示clean已是最新。使用 .PHONY# 自定义变量 target main obj $(wildcard *.cpp) # 使用wildcard函数找到匹配的文件 dep $(patsubst %.cpp, %.o, $(obj)) # 使用patsubst函数对内容替换 # 自定义变量覆盖内置变量 CXX g $(target):$(dep) $(CXX) $^ -o $ # 使用自动变量 %.o:%.cpp # 使用模式匹配 $(CXX) -c $ -o $ .PHONY:clean clean: $(RM) $(dep) $(target)结果展示7、Tipsmake -j4-j表示 jobs;4表示同时运行 4 个编译任务。make 会分析 Makefile 中的依赖关系若多个目标文件无相互依赖则同时编译。数字参数可依据 CPU 核心改变使得编译任务并行提高效率。四、深入Makefile1、目标名称和依赖项说明target: dependencies command我们知道真正的命令执行在于 command 部分即使目标名称 target 和 依赖项 dependencies 发生变化只要 command 正确。依旧可以正确执行。但并不能忽视target : dependencies因为目标名称和依赖项会被 make 监控一旦这两项中的文件发生改变make 会监控到并做出改变。例如当依赖文件发生改变时我们可以继续执行 make 命令编译出新文件。如果没有改变则会提示目标文件已是最新不会执行命令。再者目标名称在实际开发中我们应该保持命令中最终生成的可执行文件名称与目标名称 target 一致。这是因为如果不一致make 命令的重复执行会被允许且没有提示。因为 Makefile 监控不到目标文件认为它没有生成。2、Makefile的自动推导在之前的 Makefile文件中我们自己编写了生成.o文件的命令。但是 Makefile 也可以自动推导。这里直接指定了依赖项的.o文件它会自动推导生成。另外 clean 命令下的- 表示忽略错误因为这个命令的错误如rm无法删除不存在xxx文件这对我们没有影响所以忽略。target : file_io_test dep : file_io_test.o $(target):$(dep) gcc $(dep) -o $(target) .PHONY:clean clean: -rm $(target) $(dep)