GNU Make的 Makefile会构建依赖,但直到重新运行make时才执行规则中的命令

移动开发 2026-07-08

我正在构建一个项目,运行 make 时会出现 file not found: src/cross-tile.o 的错误,但重新运行 make 就能继续并完成构建。

在src目录中执行 make ../src/cross-tile.o 将生成 tile.csrc/cross-tile.o 的前置条件),但不会构建 cross-tile.o。在tile.c已经生成之后执行 make 现在会创建 cross-tile.o

很遗憾我无法做出一个小的重现,但项目相当庞大,不过仓库在这里:https://github.com/JodiJodington/NetHack-Android(现在的master提交为cf74402d8ec3803d659c2be593b3e85568a06062)以及这里是一个失败的Action日志:https://github.com/JodiJodington/NetHack-Android/actions/runs/27067875504/job/79891814329

你可以通过克隆它来重现,执行 sh sys/android/setup.sh(看看它,它所做的只是复制Makefiles),然后进入 src 并运行 make TARGET_CC=cc ../src/cross-tile.o,观察第一次构建时唯一构建的是 tilemap,随后执行 tilemap 生成 tile.c,但 tile.c 从未被编译进 cross-tile.o。再执行相同的命令,你将看到最终创建了 cross-tile.o

为什么请求构建 cross-tile.o 目标时会构建所有前置条件但不执行该目标本身的配方?

下面是一些观察:

TARGETPFX 只是被设置为 ../src/cross-

cross-tile.o 是通过在 sys/android/Makefile.src 中的这条规则隐式构建出来的:

$(TARGETPFX)tile.o: ../src/tile.c
// later
$(TARGETPFX)%.o: %.c
    $(TARGET_CC) -c -o $@ $<

把它改成像下面这样一个显式的配方就能修复问题,但我想理解为什么必须这样做:

$(TARGETPFX)tile.o: ../src/tile.c
    $(TARGET_CC) -c -o $(TARGETPFX)tile.o ../src/tile.c

解决方案

%.o: %.c 的意思是“从同一目录中的C 文件构建一个目标对象文件”。你需要把目录变量作为模式的一部分。

(技术上可以改用vpath,但vpath是那些后来证明并非一个好主意的东西之一。)

你也许(但不一定需要)选择使用一个“静态模式规则”(patterns: patterns: files)来确保Make实际上在针对特定文件使用你认为应该使用的模式规则。

Makefile里可能还有其他问题,但这类误解是主要原因。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章