2

Is there a way to force a target-rule to run as part of setting a something in a variable?

For example let's say we have a target and rule:

all_mp3s:
    find / -name "*.mp3" > all_mp3s

And then a variable:

MP3S := $(file < all_mp3s)

Is there a way to make sure all_mp3s file is getting created before evaluating the MP3S variable?

  • Your question is not entirely clear to me. Are you looking for the [`shell` function](https://www.gnu.org/software/make/manual/html_node/Shell-Function.html#Shell-Function)? You could do something like `MP3S := $(shell find / -name "*.mp3")` – Reinier Torenbeek Oct 16 '18 at 03:12
  • Instead of seeking a convoluted solution to an x-y-problem, what is your *actual* goal? – Jens Oct 16 '18 at 05:59

1 Answers1

0

There is no simple straightforward way to force a rule to be evaluated before a variable gets assigned. There are more complex ways. The following is for GNU make.

Let's first assume that you want to run the (slow) find command only if the file all_mp3s does not exist, else use its content. You can use GNU make conditionals:

ifeq ($(wildcard all_mp3s),all_mp3s)

MP3S := $(shell cat all_mp3s)

else

MP3S := $(shell $(MAKE) all_mp3s ; cat all_mp3s)

endif

all_mp3s:
    find / -name "*.mp3" > $@

But I if your Makefile is more complex than this, uses MP3S several times, and what you really want is:

  • avoid running your super-slow find several times,
  • run it only if needed (and only once),
  • get the result in a file (all_mp3s) plus a make variable (MP3S),

MadScientist has a wonderful GNU make trick that can be used here:

MP3S = $(eval MP3S := $$(shell find / -name "*.mp3"))$(MP3S)

all_mp3s:
    printf '%s\n' '$(MP3S)' > all_mp3s

.PHONY: help clean

help:
    printf 'MP3 finder\n'

clean:
    rm -f all_mp3s

If the MP3S recursively expanded make variable is expanded because some part of your Makefile is evaluated and needs its value (e.g. if you run make all_mp3s while all_mp3s does not exist), the find command will be run, its result stored in the variable... and the variable will be turned into a simply expanded make variable, which further expansions, if any, will reuse the same, already computed, value.

Else, if your invocation of make (e.g. make cleanor make help) does not need MP3S value, the find command will not even be run.

The all_mp3s file is generated from the value of MP3S (instead of the opposite in the other solution).

However, there is another important thing to decide: do you want to declare all_mp3s as a phony target:

.PHONY: all_mp3s

or not?

  • If you declare it as phony, the find command will be run once and only once each time you invoke make all_mp3s (or another goal that depends on all_mp3s). But targets depending on all_mp3s will always be rebuilt too, which is not necessarily what you want.

  • If you don't declare it as phony, and the file exists already, the find command will not be run at all (unless the value of MP3S is needed elsewhere in your Makefile), and the content of all_mp3s will not be updated, which is not necessarily what you want.

As you do not give enough information in your question to decide, it is up to you.

Renaud Pacalet
  • 25,260
  • 3
  • 34
  • 51