make 不知道编什么 No rule to make target 速查
更新时间:2026-10-24。FAQ 速查页,面向手写或维护 Makefile 的同学。make 不知道编什么指敲下
make或make xxx后,make 要么说找不到目标规则直接停摆,要么编出来的东西跟你想要的完全不是一回事。它和 make: No rule to make target 速查 是近亲——那篇管「依赖的文件不存在」,本篇管「目标本身没被定义、没被选中、或被同名文件挡了路」。病根集中在三件事:默认目标的顺序约定、目标名拼写、.PHONY声明。本篇以报错原文为锚逐条定位。
本文要回答的问题
- 直接敲
make,它到底默认编哪个目标? make: *** No targets. Stop.是什么意思,Makefile 明明有规则?- 为什么目录里有个叫
clean的文件后,make clean就不干活了? make: 'all' is up to date.可我根本没编过,哪来的 up to date?- Makefile 几百行,怎么快速查 make 眼里到底有哪些目标?
一、报错原文与典型现象
典型现场一(工程路径以 /proj/demo 占位),目标名打错:
$ make bulid
make: *** No rule to make target 'bulid'. Stop.典型现场二,默认目标顺序放错——Makefile 第一个规则是工具目标,敲 make 编出了意外的东西,或者第一个目标由空变量展开直接停摆:
$ make
make: *** No targets. Stop.典型现场三,同名文件遮蔽伪目标,最坑的一种——不报错但什么都不做:
$ ls
Makefile clean src/
$ make clean
make: 'clean' is up to date.目录里有个名叫 clean 的文件,make 认为目标 clean 已存在且没有依赖需要更新,直接判定「是最新的」跳过整个配方。读懂现场抓住两件东西:make 认为的目标是什么(make -p 把内部数据库倒出来看),当前目录下有没有跟目标同名的文件(ls 一眼的事)。No rule to make target 'xxx' 里 xxx 是你敲的目标名时,是拼写或定义问题;xxx 是某个文件名时,是依赖缺失,转去 make: No rule to make target 速查。
二、病因处置速查表
| 报错现象 / 场景 | 可能原因 | 快速验证 | 处置 |
|---|---|---|---|
No rule to make target 'xxx'. Stop.(xxx 是目标名) | 目标名打错、大小写不一致、目标根本没定义 | make -p | grep "^xxx:" 查数据库 | 改对拼写;用 make help 或 Tab 补全避免手敲 |
敲 make 编出意外目标 | 默认目标是 Makefile 第一个非模式规则,顺序放错 | 看 Makefile 第一个规则是什么 | 把 all 放最前;或显式设 .DEFAULT_GOAL := all |
make: *** No targets. Stop. | 第一个目标由变量展开,而变量此时为空 | make -p | grep -A2 "DEFAULT_GOAL" | 检查变量赋值顺序;把具名目标放最前兜底 |
make: 'clean' is up to date. 什么都没干 | 目录里有同名文件 clean,且未声明 .PHONY | ls 看有无同名文件 | .PHONY: clean all 声明伪目标 |
make: 'all' is up to date. 但没编过 | 目录里存在名为 all 的文件或目录 | ls 确认 | 同上,声明 .PHONY;删掉误建的同名文件 |
| 进工程敲 make 说找不到 makefile | 跑错目录,或文件名叫 makefile/GNUmakefile 混用 | ls Makefile makefile GNUmakefile | cd 到正确目录;团队统一文件名约定 |
三、排查决策图
下面这张图按「make 眼里这个目标存不存在、有没有被同名文件挡路」分岔:红是报错入口与命中的根因,蓝是排查动作,绿是验证通过,橙是修复动作,紫是防复发沉淀。
读这张图抓一条主线:先 ls 排除同名文件这个「不报错但全错」的坑,再 make -p 看 make 内部数据库里目标到底长什么样——所有「我觉得 make 应该这么做」的困惑,答案都在那份数据库里,它记录的是 make 实际看到的规则,不是你以为你写的规则。
四、逐条排查展开
默认目标就是第一个非模式规则。 不带参数敲 make,它编的是 Makefile 里第一个出现的、目标名不以点开头、不是模式规则的目标。所以通行约定是 all 放最前,依赖挂上全部产物。顺序放错(比如把某个工具目标写在最前)的后果是敲 make 编出半成品。更稳的写法是显式声明 .DEFAULT_GOAL := all,不受物理顺序影响。
No targets. Stop. 多半死于空变量。 写成 $(TARGETS): $(OBJS) 这样的规则时,如果 TARGETS 在这条规则之前没赋值(赋值写在后面,或 include 失败),规则展开后目标为空,make 手里就没有默认目标了。排查用 make -p 看变量实际值;修法是把变量赋值挪到规则之前,或先写一个具名的 all 兜底。
同名文件遮蔽是「沉默的故障」。 make 的本质是文件依赖管理器:目标 clean 在目录里真实存在、又没有依赖比它新,make 就判定无需动作。这不是 bug,是 make 的天职——所以要告诉它「clean 不是个真文件」:.PHONY: clean all install test。经验法则是所有不产生同名文件的目标都进 .PHONY,写在每个规则正上方,团队 review 时一眼可查。顺手把误建的同名文件删掉(它往往是某次重定向或 touch 手滑的产物)。
目标名拼错的防法。 bulid/clea 这类手误,No rule to make target 报得很直白,改对即可。减少手误的手段:Makefile 里加一个 help 目标列出全部可用目标(用 grep 从注释自动生成),养成 make help 先看再敲的习惯;shell 配 make 目标补全。
make -p 是终极照妖镜。 make -p -n 不执行任何动作,只把 make 解析出的全部规则、变量、默认目标倒出来。目标在不在数据库里、.DEFAULT_GOAL 是谁、变量展开成了什么,一查便知。配合 make -d 的调试输出(make 会逐条解释「为什么认为这个目标需要/不需要重建」),任何「make 行为不符合预期」的问题都有据可查。
跑错目录与文件名。 make 默认依次找 GNUmakefile、makefile、Makefile。在子目录敲 make 报 No targets specified and no makefile found 就是没找着文件。团队约定统一用 Makefile(大写 M,排序靠前、一眼可见),子工程靠顶层 make -C subdir 进入。
五、规范做法与预防
- Makefile 开头三件套:
.DEFAULT_GOAL := all、.PHONY集中声明、第一个规则是具名all,从结构上消除默认目标歧义。 - 伪目标全量进 .PHONY:clean/all/test/install/help 一个不落地声明,写在规则上方就近处。
- 提供 help 目标:注释规范加自动生成,
make help列出全部目标与一句话说明,新人不用读全文。 - 变量先赋值后引用:目标名由变量展开时,赋值语句必须出现在规则之前;复杂工程拆
Makefile.vars统一 include 在头部。 - CI 显式带目标:流水线里写
make all/make test而不是裸make,不依赖默认目标约定,行为可复现,谁在什么时候改了目标顺序也不影响流水线。
这一篇在知识体系里的位置
本篇是 Makefile/CMake 排错速查簇的目标解析篇,管 make 选目标、认目标这一类病。依赖文件缺失型的 No rule to make target 分流到 make: No rule to make target 速查;语法层报错见 Makefile missing separator 速查 与 CMakeLists 语法错误速查;编译链接期问题见 fatal error 头文件找不到速查、undefined reference 链接错误速查、multiple definition 重复定义速查、error: cannot convert 类型不匹配速查;工具链与环境类见 CMake 找不到编译器速查、CMake 找不到依赖包速查、CMake 版本不兼容速查、CMake FetchContent 拉取失败速查;资源与行为怪异类见 make 编译内存超限速查、make 编译器内部崩溃速查、构建 Permission denied 速查、make 构建卡死无响应速查、make 构建输出乱码速查、CMakeCache 陈旧行为怪速查、并行构建偶发失败速查;同批的 make 构建磁盘写满速查 与 优化构建 gdb 看不到变量速查 分别管磁盘资源与调试信息。「make -p 查数据库」这一招对一切「make 行为不符预期」的问题通用。
一句话总结
make 不知道编什么,先分两种长相:报 No rule to make target 用 make -p 查数据库确认目标是否定义、拼写对不对;报 is up to date 却不干活,先 ls 看有没有同名文件挡路——伪目标一律进 .PHONY,all 放第一个规则并显式设 .DEFAULT_GOAL,团队配一个 make help 目标,这类入门坑就能从结构上绝根。