Defining local variable in Makefile target

Viewed 3695

How to define local variable in Makefile target?

I would like to avoid repeating filename like:

zsh:
    FILENAME := "text.txt"
    @echo "Copying ${FILENAME}...";
    scp "${FILENAME}" "user@host:/home/user/${FILENAME}"

But I am getting an error:

FILENAME := "text.txt"
/bin/sh: FILENAME: command not found

Same with $(FILENAME)

Trying

zsh:
    export FILENAME="text.txt"
    @echo "Copying ${FILENAME} to $(EC2)";

Gives me an empty value:

Copying ...
2 Answers

You can't define a make variable inside a recipe. Recipes are run in the shell and must use shell syntax.

If you want to define a make variable, define it outside of a recipe, like this:

FILENAME := text.txt
zsh:
        @echo "Copying ${FILENAME}...";
        scp "${FILENAME}" "user@host:/home/user/${FILENAME}"

Note, it's virtually never correct to add quotes around a value when assigning it to a make variable. Make doesn't care about quotes (in variable values or expansion) and doesn't treat them specially in any way.

The rules for a target are executed by the shell, so you can set a variable using shell syntax:

zsh:
    @FILENAME="text.txt"; \
    echo "Copying $${FILENAME}..."; \
    scp "$${FILENAME}" "user@host:/home/user/$${FILENAME}"

Notice that:

  • I'm escaping end-of-line using \ so that everything executes in the same shell
  • I'm escaping the $ in shell variables by writing $$ (otherwise make will attempt to interpret them as make variables).

For this rule, which apparently depends on a file named text.txt, you could alternatively declare text.txt as an explicit dependency and then write:

zsh: text.txt
    @echo "Copying $<..."; \
    scp "$<" "user@host:/home/user/$<"
Related