28

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".

Daniel
  • 1,920
  • 4
  • 17
  • 35
  • 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 Feb 13 '14 at 05:19
  • 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 Feb 13 '14 at 05:29
  • Another solution to your problem can be `cp -p --update`: _copy only when the SOURCE file is newer than the destination file or when the destination file is missing_. – Maxim Egorushkin Feb 20 '22 at 19:47

2 Answers2

35

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 $+.

kenorb
  • 155,785
  • 88
  • 678
  • 743
Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
  • 1
    If you are using GNU make (and you probably are), this is a great answer. – reinierpost Feb 13 '14 at 14:12
  • 1
    @reinierpost I am not sure why would one use any other make. – Maxim Egorushkin Feb 13 '14 at 14:17
  • In the past, I've been stuck with other `make`s but indeed, that was a long time ago. – reinierpost Feb 13 '14 at 14:24
  • 1
    Thanks, this example worked but I'm not sure I understand it. I thought order-only means that if the dependency "%.h" doesn't exist or is updated it would NOT trigger the target "examples/%.h". Furthermore, "examples/%.h" is a dependency of its own that should be triggered any time files from "root" are copied to "examples" since it updates the files "examples/%.h". This however is not the behavior meaning it does what I want it to, but not what I expect. Could you elaborate on what's happening in your solution? – Daniel Feb 13 '14 at 16:01
  • @Daniel `make` does not check the timestamp of order-only dependencies. Which means that it creates `examples/%.h` but does not update it when its prerequisite `%.h` changes. – Maxim Egorushkin Feb 13 '14 at 16:05
  • So if %.h is executed not necessarily the rule examples/%.h will be executed. Just when examples/%.h is executed, %.h is checked and if newer than, is executed. – David Kennedy Feb 11 '17 at 16:57
  • @DavidKennedy `%.h` timestamp is never checked, your summary doesn't sound right. – Maxim Egorushkin Feb 22 '22 at 01:20
  • Sorry, @MaximEgorushkin. The main difference using order-only is that it ignores updates but keeps looking at the file existence, right? – David Kennedy Feb 23 '22 at 04:55
0

I could not get the suggested answer to work for some reason, and so my search led me to other answers that us @test -f myfile or variations thereof.

But if you (like me) don't like the usability of printing a big make: *** [...] Error 1 simply because a condition is fulfilled, then there exists an alternative solution:

conditional_buid:
ifeq (,$(wildcard path/to/file))
    gcc ...
endif

If the file exists, nothing will happen. If the file does not exist, it will simply build. This probably also enables us to chain commands because make will not exit prematurely.

The command may be extended/modified by ifneq, else, etc.

alexpanter
  • 1,222
  • 10
  • 25