0

Here's my Makefile

AA = $(shell date)
a:
    @echo $(AA)
    $(shell sleep 1)
    @echo $(AA)
    $(shell sleep 1)
    @echo $(AA)

b:
    @echo $(AA)
    @sleep 1
    @echo $(AA)
    @sleep 1
    @echo $(AA)

Here's my output.

>make a
Wed Apr 26 20:24:14 PDT 2023
Wed Apr 26 20:24:15 PDT 2023
Wed Apr 26 20:24:16 PDT 2023

>make b
Wed Apr 26 20:24:18 PDT 2023
Wed Apr 26 20:24:18 PDT 2023
Wed Apr 26 20:24:18 PDT 2023

What is the difference between running sleep 1 vs $(shell sleep 1) ?

lionel319
  • 1,180
  • 2
  • 17
  • 31
  • Does this answer your question? [How to use shell commands in Makefile](https://stackoverflow.com/questions/10024279/how-to-use-shell-commands-in-makefile) – tripleee Apr 27 '23 at 04:06
  • Isn't it obvious? The `$(shell sleep 1)` gets evaluated as `make` parses the `Makefile`. This is a common beginner FAQ (or, more like, commonly misunderstood, but rarely actually asked). – tripleee Apr 27 '23 at 04:07
  • `AA` is an extraordinarily bad way to run `date` when you want its output. Besides the [useless use of `echo`](https://www.iki.fi/era/unix/award.html#echo) you are also complicating things needlessly with the `make` variable and the `$(shell ...)` indirection. This also complicates the result - I thought you had mixed up the output from `a` and the output from `b` because of this unobvious complication. In `b` the shell function runs when the recipe is evaluated, and _then_ you sleep between the statements which print the output. – tripleee Apr 27 '23 at 04:09
  • 1
    To make it short: never use `$(shell ...)` in recipes. Recipes are already shell scripts. If you want to run `date` or `sleep` in a recipe, just run them like you do with `echo`. And if you use a make variable to easily reuse a shell command in recipes just assign it the shell command (`AA = date`). By the way, can you explain why you run the `echo` shell command as is in the recipe but think that other commands like `date` or `sleep` could need the use of `$(shell ...)`?. – Renaud Pacalet Apr 27 '23 at 06:54
  • my question is more toward, why when I used `sleep 1` the `$(AA)` is the same, whereas when i used `$(shell sleep 1)`, the `$(AA)` is 1s apart. – lionel319 Apr 27 '23 at 10:40
  • In `a`, both `date` and `sleep` are executed by the parser, therefore the date changes. In `b`, only `date` is executed by the parser, then `echo` and `sleep` are executed by the recipe. In that case, `echo` only prints precomputed result from the parser, so the date doesn't change. – sailybra Apr 27 '23 at 11:13

1 Answers1

0

What is the difference between running sleep 1 vs $(shell sleep 1) ?

Bare sleep 1 in a recipe is executed when the recipe runs. $(shell sleep 1) in a recipe is executed when make expands variable and function references in the recipe, before (any of) it runs.

This makes a difference in your example because

  • AA is a recursively expanded variable (the only kind supported by traditional make), and
  • make fully expands the recipe before executing any of it, and
  • make expands variable and function references in the recipe in the order they appear.

Therefore, when you make b, variable $(AA) is (recursively) expanded three times, one right after the other, which is very likely to produce the same result each time. Each of those results is interpolated into the recipe. Then the recipe is run, and the sleeps happen in between printing the previously-computed, likely identical timestamps.

On the other hand, when you make a, the $(shell sleep 1) expansions occur while make is expanding the recipe, between the expansions of $(AA) (which in turn runs date and captures the result). In this case, the three runs of date should be expected ordinarily to yield results that differ by the sleep time.

As @RenaudPacalet remarked in comments, you pretty much never want to use $(shell) inside a recipe. It is more than likely to confuse you, and you don't need it there, because recipes are executed by the shell already. Just write shell code.

Personally, I recommend avoiding $(shell) altogether, and most other GNU make "functions" as well, for the sake of portability. Not all makes are GNU make.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157