gnu makefile builds pre-requisites but doesn't run the recipe until make is re-run
23:56 06 Jun 2026

I am building a project and running make fails with a file not found: src/cross-tile.o, but re-running make again will continue and be able to build it.

doing make ../src/cross-tile.o in the src directory will generate tile.c (a pre-requisite of src/cross-tile.o) but not build cross-tile.o. Running make after tile.c is already generated will now create cross-tile.o.

I am unable to make a small reproduction of it unfortunately and the project is quite huge, but here is the repo: https://github.com/JodiJodington/NetHack-Android (master is commit cf74402d8ec3803d659c2be593b3e85568a06062 as of right now) and here is a failing action log: https://github.com/JodiJodington/NetHack-Android/actions/runs/27067875504/job/79891814329

you can reproduce this by cloneing it, doing sh sys/android/setup.sh (take a look at it, all it does is copy the Makefiles) and then going into src and running make TARGET_CC=cc ../src/cross-tile.o and observing that the first time all that is built is tilemap, then tilemap is run to generate tile.c but then tile.c is never compiled into cross-tile.o. running the same command again, you will see that cross-tile.o is finally created.

Why does asking to build the cross-tile.o target build all of the pre-requisites but not run the recipe for the target itself?

here's some observations:

(TARGETPFX is just set to ../src/cross-)

cross-tile.o is built implicitly with this rule in sys/android/Makefile.src:

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

changing it to an explicit recipe like so fixes the problem, but I want to understand why it is necessary:

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