0

I'm working on a gitlab pipeline with a makefile. In the yaml file, there are environment variables defined as $VAR = 'var' (for example), but in the makefile they're referenced as $(VAR).

I tried to print to the command line via echo in the pipeline to see if they were the same. When I did, $VAR printed 'var' as expected, but $(VAR) printed VAR: Command not found.

Is there a difference between the two? Or are they actually the same in the yaml and makefiles but I misused echo?

Thank you!

  • the later is called variable targeting. It's a syntax to target variables. You're targeting VAR variable defined in the yaml file. On executing the later ``$(VAR)`` will be substituted with the value as: ``var``. I hope I'm not wrong. – OMi Shah Aug 22 '23 at 15:44
  • you are completely wrong @OMiShah – UpAndAdam Aug 22 '23 at 17:52
  • YAML itself has no sense at all of variables, whether internal or from the environment. It's just a structured data format, much like JSON and in the same general category as XML. Whatever you're looking at in the YAML file is characteristic of a particular application's usage of YAML. – John Bollinger Aug 22 '23 at 21:04
  • @UpAndAdam completely wrong, my bad, that's sad. Please explain the difference then. – OMi Shah Aug 22 '23 at 21:25
  • i did below @OMiShah – UpAndAdam Aug 23 '23 at 13:55
  • @UpAndAdam, yes I noticed later. Thank you :) – OMi Shah Aug 23 '23 at 16:06

2 Answers2

1

As mentioned above the expansion of a variable depends on where it is being expanded.

Makefile:

$(VAR) and ${VAR} will expand to the value stored in VAR (which will be var)

$VAR will expand to the value stored in V followed by AR (so, unless you specified a variable named V, it will expand to the literal AR -- just mentioning it here as this is a common mistake people make)

$${VAR} or $$VAR will expand to the literals ${VAR} and $VAR respectively. This can be used to defer the expansion of the variable until bash is running (see below for an example)

bash or sh (or within a makefile recipe line):

$VAR or ${VAR} will expand to the value stored in the bash variable VAR

$(VAR) will run the command VAR

Example:

Makefile:

VAR1 := var1

foo:
    echo var1=$(VAR1)
    VAR2=var2; echo $$VAR2
    VAR3="echo running var3";  echo $$($$VAR3)

when foo is run, the first recipe line will be expanded to echo var1=var1 by make, and this will be passed to the shell, and the shell will output var1=var1

The second recipe line will run, and make will pass VAR2=var2; echo var2=$VAR2 to the shell, and the shell will output var2=var2. Note that you have to access a bash variable from the same recipe line as it was set in -- the value will not persist to the next recipe line.

The last recipe line will pass VAR3="echo running var3"; echo $($VAR3) to the shell. From the shell, $VAR3 is expanded to echo running var3, and then $(echo running var3) is run as a command, outputting running var3, which is then echoed again.

LW001
  • 2,452
  • 6
  • 27
  • 36
HardcoreHenry
  • 5,909
  • 2
  • 19
  • 44
  • Thank you so much! That's super helpful. Just to clarify, if I want to move a bash command from the makefile to yaml and the makefile uses $(VAR), when I move the line do I keep it as $(VAR) then? Thanks again! – livsruss Aug 23 '23 at 18:40
0

You are misusing echo. $(..) is one the syntaxes for applying macros ( variables ) in Makefile rules (targets and prerequisites), but in the recipes (the command line (bash)) $(...) is command expansion and will evaluate the contents unless it is escaped properly. That's occurring if you are trying to echo $(VAR) from within a recipe because VAR is not a command. However if you used echo "$(VAR)" it would work properly because the quotes around it say that should perform variable expansion before echoing. To avoid confusion I tend to always use the '${}' syntax for variables so I don't encounter a problem of context in my recipes.

UpAndAdam
  • 4,515
  • 3
  • 28
  • 46