尧图精选

make / Makefile

🕒 发布时间:2026/10/1 7:55:27 📁 来源:尧图网络
目录1. make/Makefile的使用2. make 与 Makefile 的关系2.1 角色分工2.2 工作流程3. Makefile 的核心4. make 的工作5. 伪目标 .PHONY6. 变量6.1. 链接规则6.2. 模式匹配规则编译.c 生成.o7. 函数8. 使用示例1. make/Makefile的使用在写 C/C 项目时如果每次改一个文件都要手敲gcc -c main.c -o main.o gcc -c utils.c -o utils.o gcc main.o utils.o -o app文件一多命令又长又重复还容易漏掉某个文件、忘记重新编译。更麻烦的是改了一个.c文件其实只需要重新编译它再链接一次就行但手敲时往往全量重编浪费时间。make就是解决这个问题的工具它是一个自动化构建工具读一个叫Makefile的脚本按照里面写的规则自动判断哪些文件需要重新编译然后执行对应命令。2. make 与 Makefile 的关系一句话概括make 是可执行程序命令工具Makefile 是给 make 读取的配置脚本文件。make 读 Makefile然后根据里面描述的规则自动执行编译、构建等工作。2.1 角色分工make程序Linux 自带的构建工具。 它本身不知道怎么编译代码只会去读取规则文件解析规则对比文件时间戳执行 shell 命令。 你在终端敲的make就是运行这个程序。Makefile文本文件文件名固定首字母大写也可以小写 makefile。 里面写好目标文件、依赖关系、要执行的命令。 它是给 make 看的 “说明书”没有 Makefile直接敲 make 会报错No makefile found。名称说明make可执行程序构建工具本身Makefile/makefile描述构建规则的文本文件make 读取它规则ruleMakefile 的基本单位一条规则 目标 依赖 命令2.2 工作流程终端输入 make ↓ make程序 寻找当前目录 Makefile / makefile ↓ make 解析Makefile读取里面的规则目标:依赖 命令 ↓ 比较【目标文件】和【依赖文件】的时间戳 - 如果依赖更新修改过源码执行命令重新生成目标 - 如果目标最新跳过不执行增量构建只编译改动文件执行时直接在项目目录敲makemake 会自动在当前目录找Makefile或makefile也可以make -f 自定义文件名。3. Makefile 的核心Makefile 最基本的结构目标(target): 依赖(prerequisites) 命令(recipe)关键点命令前面必须是一个 Tab不能用空格一个最简单的例子app: main.o utils.o gcc main.o utils.o -o app main.o: main.c gcc -c main.c -o main.o utils.o: utils.c gcc -c utils.c -o utils.o含义app依赖main.o、utils.o用gcc链接出appmain.o依赖main.c编译出main.outils.o依赖utils.c编译出utils.o4. make 的工作make 的核心逻辑其实就两条依赖关系目标依赖哪些文件要生成目标先保证依赖都就绪。时间戳判断如果目标的修改时间比任一依赖旧说明依赖更新了目标过期需要重新执行命令否则跳过。举例app依赖main.o、utils.o。第一次makeapp不存在 → 先递归生成main.o、utils.o→ 再链接app。只改了utils.c后makeutils.c比utils.o新 → 重新编译utils.omain.o没变 → 不重编utils.o比app新 → 重新链接app。这就是增量构建只做必要的重编译效率高。小实验连续敲两次make第二次会提示make: app is up to date.因为目标比依赖新。改utils.c再 make屏幕只执行两条命令5. 伪目标 .PHONY有些目标并不是真的文件比如clean、all、run。如果目录里恰好有个叫clean的文件make 会以为目标已存在而不执行命令所以要用.PHONY声.PHONY: clean all all: app clean: rm -f *.o app6. 变量手写一堆gcc、文件名容易重复用变量维护# 通常放在最顶部 TARGET app # 最终生成的可执行程序名 CC gcc # 编译器 CFLAGS -Wall -g # 编译参数开启警告 加入调试信息 SRCS main.c foo.c # 源码文件列表 OBJS $(SRCS:.c.o)# 后缀替换把 .c 全部换成 .o → main.o foo.o示例CC gcc CFLAGS -Wall -g TARGET app OBJS main.o utils.o $(TARGET): $(OBJS) $(CC) $(OBJS) -o $(TARGET) %.o: %.c $(CC) $(CFLAGS) -c $ -o $ .PHONY: clean clean: rm -f $(OBJS) $(TARGET)6.1. 链接规则$(TARGET): $(OBJS) $(CC) $(OBJS) -o $(TARGET)$(TARGET)读取变量代表最终可执行文件比如app$(OBJS)所有的目标文件main.o foo.o 含义可执行文件TARGET依赖所有.o文件。 当任意.o文件更新执行下面命令gcc main.o foo.o -o app作用链接阶段把多个.o目标文件合并生成最终程序。6.2.模式匹配规则编译.c 生成.o%.o: %.c $(CC) $(CFLAGS) -c $ -o $%Makefile 的通配符匹配任意文件名%.o: %.c代表任何 xxx.o 文件依赖同名的 xxx.c$(CC)编译器 gcc$(CFLAGS)编译选项警告、调试选项-c只编译不链接生成.o目标文件$自动变量代表规则里第一个依赖文件也就是xxx.c$自动变量代表当前规则的目标文件也就是xxx.o示例当需要main.omake 会自动匹配这条规则执行gcc -Wall -g -c main.c -o main.o6.3 伪目标 clean清理编译产物.PHONY: clean clean: rm -f $(OBJS) $(TARGET).PHONY: clean声明clean是伪目标它不是磁盘上的文件只是一个动作。如果当前目录恰好存在一个名叫clean的文件不加.PHONY时make clean会判断文件已经存在且最新不会执行删除命令。加上就可以避免这个 bug。clean:目标 执行make clean触发下面 shell 命令rm -f main.o foo.o apprm删除命令-f强制删除文件不存在时不会报错作用删除所有.o中间文件和可执行程序清空编译产物。变量总结符号含义$(TARGET)最终可执行程序自定义变量$(OBJS)所有.o 目标文件自定义变量$(CC)编译器一般 gcc$(CFLAGS)编译选项%通配符匹配任意文件名$第一个依赖文件$当前规则的目标文件7. 函数Makefile 自带一些函数最常用的几个SRCS $(wildcard *.c) # 找出所有 .c 文件 OBJS $(SRCS:.c.o) # 把 .c 后缀替换成 .o$(wildcard *.c)通配符展开$(SRCS:.c.o)后缀替换这样新加.c文件不用改 MakefileCC gcc CFLAGS -Wall -g TARGET app SRCS $(wildcard *.c) OBJS $(SRCS:.c.o) $(TARGET): $(OBJS) $(CC) $^ -o $ %.o: %.c $(CC) $(CFLAGS) -c $ -o $ .PHONY: clean clean: rm -f $(OBJS) $(TARGET)8. 使用示例BINxin.exe #SRC$(shell ls *.c) SRC$(wildcard *.c) # wildcard函数获取当前目录下的所有的原文件 OBJ$(SRC:.c.o) $(BIN):$(OBJ) gcc -o $ $^ echo linking $^ to $ ... done %.o:%.c gcc -c $ echo compiling $ to $ ... done .PHONY:clean clean: .PHONY:test test: echo Debug------- echo $(SRC); echo Debug------- echo $(OBJ); echo Debug-------
上一篇/下一篇内容由系统自动关联 返回资讯列表 →