15

I want to use the bash timing variables in my makefile for example in my terminal I can do this and it works

 MY_TIME=$SECONDS 
 echo $MY_TIME

but when I write this on my makefile it does not work

how can I use these two lines in my make file?

this is what I'm doing

.PHONY: myProg
myProg:
      MY_TIME=$SECONDS 
      echo $MY_TIME

After Etan Reisner' answer

This is what I have now

.PHONY: myProg
 myProg:
        MY_TIME= date; echo $MY_TIME

but the result of my echo is an empty line, it does not look like it is storing the date

Lily
  • 816
  • 7
  • 18
  • 38
  • Where are you putting that in your makefile? That's obviously not a valid make variable. It will likely work in a recipe if you set make up to use `bash` as the shell (as opposed to the default of `/bin/sh`). – Etan Reisner Apr 07 '15 at 20:13
  • Each line runs in a separate shell, so no. – that other guy Apr 07 '15 at 20:17
  • @EtanReisner How do I do that? I updated my question. – Lily Apr 07 '15 at 20:17
  • 1
    `MY_TIME= date` is running the `date` command with an environment variable named `MY_TIME` that contains an empty string. You need `MY_TIME=$(date)` to capture the output from `date` in the `MY_TIME` variable. – Etan Reisner Apr 07 '15 at 21:58

3 Answers3

20

the dollar sign ($MY_TIME) refers to make variables, which are not the same as bash variables.

To access a bash variable you must escape the dollar using the double dollar notation ($$MY_TIME).

.PHONY: myProg
myProg:
  MY_TIME=$$SECONDS ; echo $$MY_TIME

As already mentioned in Etan answer you can't split the code into multiple lines (unless you are using the backslash) since each command executes in a different subshell, making variables inaccessible to other lines.

In the following example the value of SECONDS will be always 0, since it get reset by the spawn of the shell for the second line.

.PHONY: myProg
myProg:      # WRONG
  MY_TIME=$$SECONDS
  echo $$MY_TIME
Cavaz
  • 2,996
  • 24
  • 38
6

By default make uses /bin/sh as the shell which executes recipe lines.

Presumably /bin/sh doesn't support the SECONDS variable.

You can tell make to use a different shell by assigning a value to the SHELL variable (i.e. SHELL := /bin/bash).

Doing that will make SECONDS available but will still not allow you to carry a variable value between recipe lines as each recipe line is run in its own shell.

So to do what you want you would need to write both of those lines on one line or continue the line over the newline.

.PHONY: myProg
myProg:
      MY_TIME=$SECONDS; echo $MY_TIME

or

.PHONY: myProg
myProg:
      MY_TIME=$SECONDS; \
      echo $MY_TIME

That being said you would almost certainly be better off not doing this and instead using something like date invoked at the start/end of the recipe or time invoked on the command to be timed directly instead.

.PHONY: myProg
myProg:
      date
      # Do something
      date

or

.PHONY: myProg
myProg:
      time some_command
Etan Reisner
  • 77,877
  • 8
  • 106
  • 148
  • 2
    Is there a way to store the output of date in a variable to use it later? – Lily Apr 07 '15 at 21:17
  • Only with the line-continuation version of things. Or if you have a new enough version of make and choose to use [.ONESHELL](http://www.gnu.org/software/make/manual/make.html#index-_002eONESHELL). – Etan Reisner Apr 07 '15 at 21:20
  • You can apparently also set a `make` variable with `$(eval LOL := $(shell echo $$RANDOM))` (SECONDS is pointless since it's always 0 on startup). On the next line, you can then `echo $(LOL)` to write out the value. – that other guy Apr 07 '15 at 21:24
  • @thatotherguy No need for `$(eval ...)` on that if that's in a normal make context. You'd need that in macros and on recipe lines though. And yes, `SECONDS` is going to be near-to-useless in any non-continuation scenario. – Etan Reisner Apr 07 '15 at 21:29
  • @EtanReisner I updated the result that I'm getting, it is still not storing the date – Lily Apr 07 '15 at 21:33
  • @EtanReisner It's needed to set it during processing of a make rule (instead of top level), which I think was the point. – that other guy Apr 07 '15 at 21:42
  • Thanks @EtanReisner, i found an easier solution which using time. But as you said I needed to set up the make to use the bash. Thanks! – Lily Apr 09 '15 at 01:01
  • 3
    Your first example doesn't work for me. ```$ make whatever-stag MYVAR=stag; echo YVAR YVAR ``` – holms Sep 11 '18 at 13:23
  • Check this to see how to set SHELL at global level in makefile or target specific: https://stackoverflow.com/a/589300/1097444 – Hem Aug 31 '22 at 14:27
-2
PROGRAM_NAME = myLittleProgram

...

$(PROGRAM_NAME) : myLittleProgram.o

I know the above works, as it is in my own makefile (program names and object names changed to protect the innocent).


"Variable references can be used in any context: targets, dependencies, commands, most directives, and new variable values. Here is an example of a common case, where a variable holds the names of all the object files in a program:"

objects = program.o foo.o utils.o
program : $(objects)
    cc -o program $(objects)

$(objects) : defs.h

http://web.mit.edu/gnu/doc/html/make_6.html

mrflash818
  • 930
  • 13
  • 24