为什么 GNU make 会自动编译同名 .o 文件

环境说明

操作系统: macos 12.6.3 (intel)
make版本: GNU make 3.81

执行 make -v 返回如下:

GNU Make 3.81
Copyright (C) 2006  Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.

This program built for i386-apple-darwin11.3.0

复现方式

目录中只有2个文件: Makefile 和 abc.c , 其中 abc.c 文件是空的, 没有任何内容
Makefile内容如下:

test: abc.o
    @echo '执行test'
clean:
    $(RM) test abc.o
.PHONY: test clean

执行命令: make clean && make test, 会输出:

rm -f test abc.o
cc    -c -o abc.o abc.c
执行test

我的问题是:

  1. 为什么 make 会自动执行 cc -c -o abc.o abc.c 这句话? 我的本意是想在执行 test 的时候, 判断 abc.o 这个文件应该存在, 不存在则报错
  2. 如果删掉 abc.c 这个文件, 新建一个 abc.java 就会按我的预期报错
  3. 上述的这个自动执行 cc -c -oGNU make 默认的行为么? 有没有官方文档说这个事情? 是否有方法或者参数关闭这个默认行为呢? 我不知道这个问题用什么关键字去搜素

在 Makefile 中,指定目标文件( abc.o)时,Make 会默认尝试找到同名的源文件( abc.c)进行编译,生成目标文件。
所以当你指定 test 依赖于 abc.o 时,Make 会默认查找 abc.c 并尝试生成 abc.o。由于 abc.c 文件是空的,生成 abc.o 也是一个空的目标文件。
要在执行 test 之前检查 abc.o 是否存在,可以添加一个判断语句:

test: abc.o
    @if [ ! -f abc.o ]; then echo 'abc.o 文件不存在!' && exit 1; fi
    @echo '执行 test'

这个语句会先判断 abc.o 是否存在,如果不存在则输出错误信息并退出。如果存在,则继续执行后面的命令。
 
这里给你一些相关的官方文档。
GNU Make 中的自动变量: https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html
GNU Make 中的隐式规则: https://www.gnu.org/software/make/manual/html_node/Implicit-Rules.html
GNU Make 中的模式规则: https://www.gnu.org/software/make/manual/html_node/Pattern-Rules.html
 
如果答案对您有所帮助,望采纳。