Mark Smith
Mark Smith

Reputation: 909

Makefile rule only works if file exists before make is invoked

Consider the following (MCVE of a) Makefile:

my_target: prepare test.bin

prepare:
    echo >test.dat

%.bin: %.dat
    cp $? $@

If you run make in a clean directory, it fails:

echo >test.dat
make: *** No rule to make target 'test.bin', needed by 'my_target'. Stop.

Run it again and it succeeds:

echo >test.dat
cp test.dat test.bin

What seems to happen is that the rule to make *.bin from *.dat only recognises that it knows how to make test.bin if test.dat exists before anything is executed, even though according to the output it has already created test.dat before it tries to create test.bin.

This is inconvenient for me as I have to prepare a few files first (import them from a different, earlier part of the build).

Is there a solution? Perhaps some way to allow the rules to be (re)evaluated in the light of the files which are now present?

Upvotes: 3

Views: 2264

Answers (3)

ensc
ensc

Reputation: 6994

you have to write

test.dat:  prepare

or (when when you want to stay with wildcards)

%.dat: prepare
    @:

Usually, you might want to create and use .stamp files instead of a prepare target.

Upvotes: 0

MadScientist
MadScientist

Reputation: 101111

There are a number of issues with your makefile. However based on your comments I'm inclined to assume that the MCVE here is just a little too "M" and it's been reduced so much that it has a number of basic problems. So I won't discuss them, unless you want me to.

The issue here is that you're creating important files without indicating to make that that's what you're doing. Make keeps internally a cache of the contents of directories that it's worked with, for performance reasons, and that cache is only updated when make invokes a rule that it understands will modify it.

Here your target is prepare but the recipe actually creates a completely different file, test.dat. So, make doesn't modify its internal cache of the directory contents and when it checks the cache to see if the file test.dat exists, it doesn't.

You need to be sure that your makefile is written such that it doesn't trick make: if a recipe creates a file foo then the target name should be foo, not bar.

Upvotes: 3

Alex Cohn
Alex Cohn

Reputation: 57203

This happens for wildcard targets, like %.bin. They get evaluated at the first pass. You could add an explicit target of test.bin. Or, follow the advice of tkausl and have test.dat depend on prepare (a phony target). In this case, you don't need the double dependency anymore:

my_target: test.bin

Upvotes: 0

Related Questions