【问题标题】:Why does this incredibly simple Makefile produce so much debug logging?为什么这个极其简单的 Makefile 会产生如此多的调试日志?
【发布时间】:2025-11-26 20:30:01
【问题描述】:

我正在学习 Makefile 并决定编写我的第一个练习。我有一个包含两个文件的目录:

Makefile  makefile.cpp  

这里是 makefile.cpp(惊喜!):

#include <iostream>

int main() {
  std::cout << "Hello World!\n";
  return 0;
}

这里是 Makefile:

CC = g++
FILES = makefile.cpp
OUT_EXE = makefileout

build: $(FILES)
    $(CC) -o $(OUT_EXE) $(FILES)

然后我运行 make -d 并得到一个很长的日志:

$ 使-d GNU Make 3.81 版权所有 (C) 2006 Free Software Foundation, Inc. 这是免费软件;查看复制条件的来源。 没有保修;甚至不适合适销性或适合性 特殊用途。 这个程序是为 x86_64-pc-linux-gnu 构建的 读取makefile... 正在读取 makefile `Makefile'... 更新生成文件.... 考虑目标文件“Makefile”。 寻找“Makefile”的隐含规则。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.o”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.c”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.cc”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.C”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.cpp”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.p”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.f”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.F”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.r”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.s”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.S”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.mod”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.sh”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile,v”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“RCS/Makefile,v”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“RCS/Makefile”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件`s.Makefile'。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“SCCS/s.Makefile”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.o”。 寻找带有中间文件“Makefile.o”的规则。 避免隐式规则递归。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.c”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.cc”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.C”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.cpp”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.p”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.f”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.F”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.r”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.s”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.S”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.mod”。 尝试使用词干“Makefile.o”的模式规则。 尝试隐式先决条件“Makefile.o,v”。 尝试使用词干“Makefile.o”的模式规则。 尝试隐式先决条件“RCS/Makefile.o,v”。 尝试使用词干“Makefile.o”的模式规则。 尝试隐式先决条件“RCS/Makefile.o”。 尝试使用词干“Makefile.o”的模式规则。 尝试隐式先决条件`s.Makefile.o'。 尝试使用词干“Makefile.o”的模式规则。 尝试隐式先决条件“SCCS/s.Makefile.o”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.c”。 寻找带有中间文件“Makefile.c”的规则。 避免隐式规则递归。 避免隐式规则递归。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.y”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.l”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.w”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.w”。 尝试使用词干“Makefile.c”的模式规则。 尝试隐式先决条件“Makefile.c,v”。 尝试使用词干“Makefile.c”的模式规则。 尝试隐式先决条件“RCS/Makefile.c,v”。 尝试使用词干“Makefile.c”的模式规则。 尝试隐式先决条件“RCS/Makefile.c”。 尝试使用词干“Makefile.c”的模式规则。 尝试隐式先决条件`s.Makefile.c'。 尝试使用词干“Makefile.c”的模式规则。 尝试隐式先决条件“SCCS/s.Makefile.c”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.y”。 寻找带有中间文件“Makefile.y”的规则。 避免隐式规则递归。 避免隐式规则递归。 避免隐式规则递归。 尝试使用词干“Makefile.y”的模式规则。 尝试隐式先决条件“Makefile.y,v”。 尝试使用词干“Makefile.y”的模式规则。 尝试隐式先决条件“RCS/Makefile.y,v”。 尝试使用词干“Makefile.y”的模式规则。 尝试隐式先决条件“RCS/Makefile.y”。 尝试使用词干“Makefile.y”的模式规则。 尝试隐式先决条件`s.Makefile.y'。 尝试使用词干“Makefile.y”的模式规则。 尝试隐式先决条件“SCCS/s.Makefile.y”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.l”。 寻找带有中间文件“Makefile.l”的规则。 避免隐式规则递归。 避免隐式规则递归。 避免隐式规则递归。 尝试使用词干“Makefile.l”的模式规则。 尝试隐式先决条件“Makefile.l,v”。 尝试使用词干“Makefile.l”的模式规则。 尝试隐式先决条件“RCS/Makefile.l,v”。 尝试使用词干“Makefile.l”的模式规则。 尝试隐式先决条件“RCS/Makefile.l”。 尝试使用词干“Makefile.l”的模式规则。 尝试隐式先决条件`s.Makefile.l'。 尝试使用词干“Makefile.l”的模式规则。 尝试隐式先决条件“SCCS/s.Makefile.l”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.w”。 寻找带有中间文件“Makefile.w”的规则。 避免隐式规则递归。 避免隐式规则递归。 避免隐式规则递归。 尝试使用词干“Makefile.w”的模式规则。 尝试隐式先决条件“Makefile.w,v”。 尝试使用词干“Makefile.w”的模式规则。 尝试隐式先决条件“RCS/Makefile.w,v”。 尝试使用词干“Makefile.w”的模式规则。 尝试隐式先决条件“RCS/Makefile.w”。 尝试使用词干“Makefile.w”的模式规则。 尝试隐式先决条件`s.Makefile.w'。 尝试使用词干“Makefile.w”的模式规则。 尝试隐式先决条件“SCCS/s.Makefile.w”。 尝试使用词干“Makefile”的模式规则。 拒绝不可能的隐式先决条件“Makefile.w”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.cc”。 寻找带有中间文件“Makefile.cc”的规则。 避免隐式规则递归。 避免隐式规则递归。 尝试使用词干“Makefile.cc”的模式规则。 尝试隐式先决条件“Makefile.cc,v”。 尝试使用词干“Makefile.cc”的模式规则。 尝试隐式先决条件“RCS/Makefile.cc,v”。 尝试使用词干“Makefile.cc”的模式规则。 尝试隐式先决条件“RCS/Makefile.cc”。 尝试使用词干“Makefile.cc”的模式规则。 尝试隐式先决条件`s.Makefile.cc'。 尝试使用词干“Makefile.cc”的模式规则。 尝试隐式先决条件“SCCS/s.Makefile.cc”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.C”。 寻找带有中间文件“Makefile.C”的规则。 避免隐式规则递归。 避免隐式规则递归。 尝试使用词干“Makefile.C”的模式规则。 尝试隐式先决条件“Makefile.C,v”。 尝试使用词干“Makefile.C”的模式规则。 尝试隐式先决条件“RCS/Makefile.C,v”。 尝试使用词干“Makefile.C”的模式规则。 尝试隐式先决条件“RCS/Makefile.C”。 尝试使用词干“Makefile.C”的模式规则。 尝试隐式先决条件`s.Makefile.C'。 尝试使用词干“Makefile.C”的模式规则。 尝试隐式先决条件“SCCS/s.Makefile.C”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.cpp”。 寻找带有中间文件“Makefile.cpp”的规则。 避免隐式规则递归。 避免隐式规则递归。 尝试使用词干“Makefile.cpp”的模式规则。 尝试隐式先决条件“Makefile.cpp,v”。 尝试使用词干“Makefile.cpp”的模式规则。 尝试隐式先决条件“RCS/Makefile.cpp,v”。 尝试使用词干“Makefile.cpp”的模式规则。 尝试隐式先决条件“RCS/Makefile.cpp”。 尝试使用词干“Makefile.cpp”的模式规则。 尝试隐式先决条件`s.Makefile.cpp'。 尝试使用词干“Makefile.cpp”的模式规则。 尝试隐式先决条件“SCCS/s.Makefile.cpp”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.p”。 寻找带有中间文件“Makefile.p”的规则。 避免隐式规则递归。 避免隐式规则递归。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.web”。 尝试使用词干“Makefile.p”的模式规则。 尝试隐式先决条件“Makefile.p,v”。 尝试使用词干“Makefile.p”的模式规则。 尝试隐式先决条件“RCS/Makefile.p,v”。 尝试使用词干“Makefile.p”的模式规则。 尝试隐式先决条件“RCS/Makefile.p”。 尝试使用词干“Makefile.p”的模式规则。 尝试隐式先决条件`s.Makefile.p'。 尝试使用词干“Makefile.p”的模式规则。 尝试隐式先决条件“SCCS/s.Makefile.p”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.web”。 寻找带有中间文件“Makefile.web”的规则。 避免隐式规则递归。 避免隐式规则递归。 避免隐式规则递归。 尝试使用词干“Makefile.web”的模式规则。 尝试隐式先决条件“Makefile.web,v”。 尝试使用词干“Makefile.web”的模式规则。 尝试隐式先决条件“RCS/Makefile.web,v”。 尝试使用词干“Makefile.web”的模式规则。 尝试隐式先决条件“RCS/Makefile.web”。 尝试使用词干“Makefile.web”的模式规则。 尝试隐式先决条件`s.Makefile.web'。 尝试使用词干“Makefile.web”的模式规则。 尝试隐式先决条件“SCCS/s.Makefile.web”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.f”。 寻找带有中间文件“Makefile.f”的规则。 避免隐式规则递归。 避免隐式规则递归。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.F”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.r”。 尝试使用词干“Makefile.f”的模式规则。 尝试隐式先决条件“Makefile.f,v”。 尝试使用词干“Makefile.f”的模式规则。 尝试隐式先决条件“RCS/Makefile.f,v”。 尝试使用词干“Makefile.f”的模式规则。 尝试隐式先决条件“RCS/Makefile.f”。 尝试使用词干“Makefile.f”的模式规则。 尝试隐式先决条件`s.Makefile.f'。 尝试使用词干“Makefile.f”的模式规则。 尝试隐式先决条件“SCCS/s.Makefile.f”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.F”。 寻找带有中间文件“Makefile.F”的规则。 避免隐式规则递归。 避免隐式规则递归。 避免隐式规则递归。 尝试使用词干“Makefile.F”的模式规则。 尝试隐式先决条件“Makefile.F,v”。 尝试使用词干“Makefile.F”的模式规则。 尝试隐式先决条件 `RCS/Makefile.F,v'。 尝试使用词干“Makefile.F”的模式规则。 尝试隐式先决条件“RCS/Makefile.F”。 尝试使用词干“Makefile.F”的模式规则。 尝试隐式先决条件`s.Makefile.F'。 尝试使用词干“Makefile.F”的模式规则。 尝试隐式先决条件“SCCS/s.Makefile.F”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.r”。 寻找带有中间文件“Makefile.r”的规则。 避免隐式规则递归。 避免隐式规则递归。 避免隐式规则递归。 尝试使用词干“Makefile”的模式规则。 拒绝不可能的隐含先决条件“Makefile.l”。 尝试使用词干“Makefile.r”的模式规则。 尝试隐式先决条件“Makefile.r,v”。 尝试使用词干“Makefile.r”的模式规则。 尝试隐式先决条件“RCS/Makefile.r,v”。 尝试使用词干“Makefile.r”的模式规则。 尝试隐式先决条件“RCS/Makefile.r”。 尝试使用词干“Makefile.r”的模式规则。 尝试隐式先决条件`s.Makefile.r'。 尝试使用词干“Makefile.r”的模式规则。 尝试隐式先决条件“SCCS/s.Makefile.r”。 尝试使用词干“Makefile”的模式规则。 拒绝不可能的隐式先决条件“Makefile.F”。 尝试使用词干“Makefile”的模式规则。 拒绝不可能的隐式先决条件“Makefile.r”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.s”。 寻找带有中间文件“Makefile.s”的规则。 避免隐式规则递归。 避免隐式规则递归。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.S”。 尝试使用词干“Makefile.s”的模式规则。 尝试隐式先决条件“Makefile.s,v”。 尝试使用词干“Makefile.s”的模式规则。 尝试隐式先决条件“RCS/Makefile.s,v”。 尝试使用词干“Makefile.s”的模式规则。 尝试隐式先决条件“RCS/Makefile.s”。 尝试使用词干“Makefile.s”的模式规则。 尝试隐式先决条件`s.Makefile.s'。 尝试使用词干“Makefile.s”的模式规则。 尝试隐式先决条件“SCCS/s.Makefile.s”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.S”。 寻找带有中间文件“Makefile.S”的规则。 避免隐式规则递归。 避免隐式规则递归。 避免隐式规则递归。 尝试使用词干“Makefile.S”的模式规则。 尝试隐式先决条件“Makefile.S,v”。 尝试使用词干“Makefile.S”的模式规则。 尝试隐式先决条件 `RCS/Makefile.S,v'。 尝试使用词干“Makefile.S”的模式规则。 尝试隐式先决条件“RCS/Makefile.S”。 尝试使用词干“Makefile.S”的模式规则。 尝试隐式先决条件`s.Makefile.S'。 尝试使用词干“Makefile.S”的模式规则。 尝试隐式先决条件“SCCS/s.Makefile.S”。 尝试使用词干“Makefile”的模式规则。 拒绝不可能的隐式先决条件“Makefile.S”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.mod”。 寻找带有中间文件“Makefile.mod”的规则。 避免隐式规则递归。 避免隐式规则递归。 尝试使用词干“Makefile.mod”的模式规则。 尝试隐式先决条件“Makefile.mod,v”。 尝试使用词干“Makefile.mod”的模式规则。 尝试隐式先决条件“RCS/Makefile.mod,v”。 尝试使用词干“Makefile.mod”的模式规则。 尝试隐式先决条件“RCS/Makefile.mod”。 尝试使用词干“Makefile.mod”的模式规则。 尝试隐式先决条件`s.Makefile.mod'。 尝试使用词干“Makefile.mod”的模式规则。 尝试隐式先决条件“SCCS/s.Makefile.mod”。 尝试使用词干“Makefile”的模式规则。 拒绝不可能的隐含先决条件“Makefile.c”。 尝试使用词干“Makefile”的模式规则。 拒绝不可能的隐含先决条件“Makefile.cc”。 尝试使用词干“Makefile”的模式规则。 拒绝不可能的隐式先决条件“Makefile.C”。 尝试使用词干“Makefile”的模式规则。 拒绝不可能的隐式先决条件“Makefile.cpp”。 尝试使用词干“Makefile”的模式规则。 拒绝不可能的隐式先决条件“Makefile.p”。 尝试使用词干“Makefile”的模式规则。 拒绝不可能的隐式先决条件“Makefile.f”。 尝试使用词干“Makefile”的模式规则。 拒绝不可能的隐式先决条件“Makefile.F”。 尝试使用词干“Makefile”的模式规则。 拒绝不可能的隐式先决条件“Makefile.r”。 尝试使用词干“Makefile”的模式规则。 拒绝不可能的隐式先决条件“Makefile.s”。 尝试使用词干“Makefile”的模式规则。 拒绝不可能的隐式先决条件“Makefile.S”。 尝试使用词干“Makefile”的模式规则。 拒绝不可能的隐式先决条件“Makefile.mod”。 尝试使用词干“Makefile”的模式规则。 尝试隐式先决条件“Makefile.sh”。 寻找带有中间文件“Makefile.sh”的规则。 避免隐式规则递归。 尝试使用词干“Makefile.sh”的模式规则。 尝试隐式先决条件“Makefile.sh,v”。 尝试使用词干“Makefile.sh”的模式规则。 尝试隐式先决条件“RCS/Makefile.sh,v”。 尝试使用词干“Makefile.sh”的模式规则。 尝试隐式先决条件“RCS/Makefile.sh”。 尝试使用词干“Makefile.sh”的模式规则。 尝试隐式先决条件`s.Makefile.sh'。 尝试使用词干“Makefile.sh”的模式规则。 尝试隐式先决条件“SCCS/s.Makefile.sh”。 找不到“Makefile”的隐含规则。 完成目标文件“Makefile”的先决条件。 无需重新制作目标“Makefile”。 更新目标目标.... 考虑目标文件“构建”。 文件“构建”不存在。 考虑目标文件“makefile.cpp”。 寻找“makefile.cpp”的隐含规则。 尝试使用词干“makefile.cpp”的模式规则。 尝试隐式先决条件“makefile.cpp,v”。 尝试使用词干“makefile.cpp”的模式规则。 尝试隐式先决条件“RCS/makefile.cpp,v”。 尝试使用词干“makefile.cpp”的模式规则。 尝试隐式先决条件“RCS/makefile.cpp”。 尝试使用词干“makefile.cpp”的模式规则。 尝试隐式先决条件`s.makefile.cpp'。 尝试使用词干“makefile.cpp”的模式规则。 尝试隐式先决条件“SCCS/s.makefile.cpp”。 找不到“makefile.cpp”的隐含规则。 完成目标文件“makefile.cpp”的先决条件。 无需重新制作目标“makefile.cpp”。 完成目标文件“build”的先决条件。 必须重新制作目标“构建”。 g++ -o makefileout makefile.cpp 将子 0x01a6de60(构建)PID 6157 放在链上。 活子 0x01a6de60(构建)PID 6157 收获获奖孩子 0x01a6de60 PID 6157 从链中删除子 0x01a6de60 PID 6157。 成功地重新制作了目标文件“build”。

我的问题是:我做错了什么吗?为什么这么简单的例子会产生如此多的日志记录?

另外,我的 Makefile 似乎总是重新编译目标代码,即使源代码比最新的 make 旧。换句话说,我从来没有见过这样的消息,“没什么可做的。”

【问题讨论】:

    标签: c++ makefile


    【解决方案1】:

    好吧,您已经要求使用-d 选项进行调试。你说对了。如果您问为什么 GNU make 有如此多的隐含规则,每次 make 处理 Makefile 时都会检查这些规则——这主要是出于历史原因。有些构建系统(例如Ninja)没有这么长的开发历史,因此内部的东西更少。

    【讨论】:

      【解决方案2】:

      因为您将“-d”传递给“make”。 “-d”参数是产生所有噪音的原因。

      -d   Print debugging information in addition to normal processing.  The
           debugging information says which files are  being  considered  for
           remaking,  which  file-times  are  being  compared  and  with what
           results, which files actually need to be  remade,  which  implicit
           rules  are considered and which are applied---everything interest‐
           ing about how make decides what to do.
      

      所以不要再传递-d 了,你会得到你可能期望的输出。

      【讨论】:

        【解决方案3】:

        默认情况下,make 有很多关于通过编译构建应用程序的预定义规则。见https://www.gnu.org/software/make/manual/make.html#Implicit-Rules

        您可以通过将.SUFFIXES: 添加到您的makefile 来大大减少make 的工作量。因此,这可能会削弱您的成就,因为许多规则现在将不再存在。

        我发现即使我使用.SUFFIXES:,由于 Makefile 位于 git checkout 中,我仍然会得到隐含的规则。我的项目与编译应用程序无关。

        另一种减少工作量的方法是从命令行禁用后缀。使用 -r--no-builtin-rules 标志会导致默认后缀列表为空。

        【讨论】:

          【解决方案4】:

          我将解决编辑问题:

          我的 Makefile 似乎总是重新编译目标代码,即使 源代码比最新版本旧

          在这个答案中。

          考虑你的 Makefile:

          CC = g++
          FILES = makefile.cpp
          OUT_EXE = makefileout
          
          build: $(FILES)
              $(CC) -o $(OUT_EXE) $(FILES)
          

          这里唯一的目标是build,这是从未构造过的东西(这就是为什么您每次都会看到编译发生的原因)。最简单的解决方法应该是:

          CC = g++
          FILES = makefile.cpp
          OUT_EXE = makefileout
          
          ${OUT_EXE}: $(FILES)
              $(CC) -o $(OUT_EXE) $(FILES)
          

          使用新规则make 将检查makefileout 而不是build,从而提供预期的行为。

          如果您想进行更多实验,可以使用 Makefile 发出以下命令:

          rm -f makefileout
          touch build
          make
          

          您会发现,即使可执行文件不存在,make 也不会编译它。我把为什么作为(一个简单的)练习的问题留给你。

          【讨论】:

          • the target is build, which is something that is NEVER constructed:我认为这是错误的。在没有调用任何目标的情况下,make 构建文件中的第一个目标。
          • @kebs Humm,这里唯一的目标是build,所以我不明白你的担忧。无论如何,编辑答案以使其更清晰。
          • make 为目标build 运行定义的命令,但是这里的Makefile 中的步骤实际上并没有创建目标文件build。引用文档,“如果您编写一个规则,其配方不会创建目标文件,则每次目标出现重新制作时都会执行该配方。” gnu.org/software/make/manual/html_node/Phony-Targets.html
          • 使用:.PHONY: build。告诉使build 不是要构建的“东西”。
          【解决方案5】:

          传递-d flag 具有打印附加信息的效果,这有时有助于调试问题。

          【讨论】:

            最近更新 更多