为何Makefile的依赖项可为命令式目标而非仅文件名?
Makefile中命令式目标作为依赖的原因
先看你提供的顶层Makefile:
#MAKE=make SHELL=/bin/sh all lib progs check test _test install uninstall dep depend: _config $(MAKE) $@ clean mostlyclean distclean maintainer-clean TAGS: _config $(MAKE) $@ _config: sh configure .PHONY: all lib progs test install uninstall dep depend clean mostlyclean \ distclean maintainer-clean _config
你的疑问是:依赖项通常是文件名,但这里_config是执行sh configure的命令式目标,为什么可以这么用?
核心原因:Make的依赖项不局限于文件名
Make里的依赖项本质是目标,而目标分为两种:
- 文件目标:对应实际存在的文件,比如基础示例里的
main.o依赖main.c,Make会通过文件修改时间判断是否需要重新构建。 - 伪目标:不对应任何实际文件,专门用来执行特定命令,通过
.PHONY声明告诉Make不要把它当成文件处理。
你的_config就是一个伪目标(已经在.PHONY列表里),它的作用是强制执行配置步骤:
- 当你执行
make all、make install这类核心目标时,Make会先处理依赖的_config。因为是伪目标,不管有没有同名文件,都会触发它的命令sh configure,确保配置脚本先运行,生成适配当前系统的实际构建文件(比如真正的Makefile、配置头文件等)。 - 这种写法是Autotools(configure脚本所属的工具链)项目的标准套路:顶层Makefile只是个“入口”,真正的构建逻辑在configure生成的文件里,所以所有核心目标都依赖
_config,保证配置优先完成。
和基础示例的区别
你找到的基础示例:
main.o : main.c defs.h cc -c main.c kbd.o : kbd.c defs.h command.h cc -c kbd.c command.o : command.c defs.h command.h cc -c command.c display.o : display.c defs.h buffer.h cc -c display.c insert.o : insert.c defs.h buffer.h cc -c insert.c search.o : search.c defs.h buffer.h cc -c search.c files.o : files.c defs.h buffer.h command.h cc -c files.c utils.o : utils.c defs.h cc -c utils.c clean : rm edit main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o
这里的依赖都是文件目标,Make通过检查源文件(.c、.h)和目标文件(.o)的修改时间来决定是否重新编译。而你的_config是伪目标,它的目的不是生成文件,而是触发配置命令,所以每次执行都会运行。
补充:.PHONY的作用
.PHONY声明的意义是告诉Make:“这些目标不是文件,不管当前目录有没有同名文件,都要执行它们的命令”。如果没有声明_config为.PHONY,万一目录里恰好有个叫_config的文件,Make会认为依赖已经满足,不会再执行sh configure,这就会导致配置步骤被跳过,引发构建错误。
内容的提问来源于stack exchange,提问作者tosotta12 a
相关产品推荐
相关产品推荐

