22
votes

Like the title says, I would like to make a dependency only if a certain file does not exist, NOT every time it updates.

I have a root directory (the one with the makefile) and in it a sub-directory called "example". In my root directory are four .h files (functions.h, parser.h, node.h, and exception.h) which I would like to copy to the "example" sub-directory if those .h files do not already exist in "examples".

Unfortunately I can not just make a standard dependency to check for the header files in "example" because each time I copy the header files from root to "example", the header files in "example" will be considered updated and will trigger that dependency each time I run make. I would like for a way to have my makefile copy the header files from the root directory to "example" only if they do not exist in "example".

2
The manual is very, very clear that automatic variables (such as $@) are valid only within the recipe. You cannot use them in targets, in prerequisites, or in make conditional statements (because those are expanded while the makefile is read in). In those cases, $@ expands to the empty string. - MadScientist
I see, but because I append "example/" there's something for the ifeq() to still evaluate to false. Thanks for clearing that up. I've edited my post to focus on the remaining issue. - Daniel

2 Answers

30
votes

This is what order-only prerequisites/dependencies are for:

Occasionally, however, you have a situation where you want to impose a specific ordering on the rules to be invoked without forcing the target to be updated if one of those rules is executed. In that case, you want to define order-only prerequisites. Order-only prerequisites can be specified by placing a pipe symbol (|) in the prerequisites list: any prerequisites to the left of the pipe symbol are normal; any prerequisites to the right are order-only.

In your case:

examples/%.h : | %.h
    cp $| $@

See also: Order-only prerequisites do not show up in $^ or $+.

4
votes

You must express the dependencies in terms of relative file age.

A commonly used workaround is to use a dummy ("sentinel") file that flags the operation's completion:

examples/%.h.hasbeencopied: %.h
    if [ -f example/[email protected] ] || cp -p $< examples/[email protected]; \
    then touch $@; \
    else rm -f $@; \
    fi

and make whatever rule depends on example/foo.h also depend on example/foo.h.hasbeencopied.