Search code examples
makefilegnu-make

Why is Make not injecting this variable value in my recipe?


Consider my Makefile recipe

build:
    export TAG=main; docker build my_dir -t my-image:$(TAG)

I expected $(TAG) to be replaced with "main", but it's the blank string. I've also tried $$TAG and $(shell echo $TAG), but none of them cause Make to inject "main" as I expected.


Solution

  • Your export TAG=main sets (and unnecessarily exports) a shell variable. Your $(TAG) attempts to expand a make variable. These are not the same thing.

    There are at least two possible solutions:

    • convert TAG to a make variable
      TAG = main
      
      # ...
      
      build:
              docker build my_dir -t my-image:'$(TAG)'
      
    • or expand TAG as a shell variable
      build:
              TAG=main; docker build my_dir -t my-image:"$${TAG}"
      

    The former would be cleaner and more natural unless you have some need for TAG to be an environment variable other than what is apparent in your example.

    Notes:

    • To make, both $(variable) and ${variable} expand to the value of variable variable, including in recipes, but to the shell, those forms mean different things.

    • To pass a $ through to the shell -- to get the shell to perform a variable expansion, for example -- it needs to be escaped by doubling it.

    • make allows whitespace around the = in a variable assignment, but the shell does not.

    • You should quote shell variable expansions with double quotes. You can also quote make variable expansions in recipes with either single or double quotes, and often this is a good idea. The quotes are meaningless to make, but appropriate for protecting the expansion from further interpretation by the shell.