4

I've been learning make and am struggling to figure something out. I have some rules with this general structure.

FILE = "myfile.txt"

test :
    YOUR = $(subst my,your,$(FILE));\
    cat $(FILE) $(YOUR)

I would expect the end result to be running the command:

cat myfile.txt yourfile.txt

Instead I get the following...

YOUR = "yourfile.txt";\
    cat "myfile.txt" 
/bin/sh: YOUR: command not found
make: *** [test] Error 1

If instead of using the subst function, I just do YOUR="yourfile" in the makefile, everything looks fine. Any suggestions or have I missed something pretty fundamental? I should add that I'm using tabs and not spaces to start the lines for the commands within the rule.

Subham Tripathi
  • 2,683
  • 6
  • 41
  • 70
PD Schloss
  • 149
  • 5

3 Answers3

1

You need to distinguish between what make executes and what the shell executes. Your line with YOUR = starts with a tab and is part of the actions of a rule, so it is executed by the shell, which can't find a program YOUR to execute with some arguments.

Place the expansion outside the rule:

YOUR = $(subst my,your,$(FILE))

test:
    cat $(FILE) $(YOUR)

Note that shell assignments require no space around the equals sign, and use ${} rather than $() to reference variables: YOUR=${FILE/my/your} in Bash (and if written in a make rule, you'd need $$ in place of $ so that the shell sees a single dollar sign and make does not try the variable expansion that it doesn't understand). The shell uses $() to execute the command contained within, and the result is often captured in a variable: YOUR=$(echo "${FILE}" | sed 's/my/your/').

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • you are right, but in that case you can use it just echo "$file" – midori Dec 24 '14 at 19:37
  • @BallPython `echo "$file"` in a make recipe will not work correctly... unless you are expecting make to expand an `$f` variable and have `echo` spit out `ile`. – Etan Reisner Dec 25 '14 at 00:03
1
FILE = "myfile.txt"

test :
    $(eval YOUR = $(subst my,your,$(FILE)))
    cp $(FILE) $(YOUR)

You have to use the eval function in the recipe (Define make variable at rule execution time)

Community
  • 1
  • 1
  • Thanks - this does it. In the more complex example test would be something like $(test) and I'd need to do a subst on the $@ valiable and then pass the result to a shell script. – PD Schloss Dec 24 '14 at 20:17
0

If you only need the variable in the shell recipe and not in the make context then you don't need to bother playing with eval (which are hoisted) and can just assign to shell variables instead.

For example:

FILE = "myfile.txt"

test :
    YOUR='$(subst my,your,$(FILE))';\
    cat $(FILE) "$${YOUR}"
Etan Reisner
  • 77,877
  • 8
  • 106
  • 148