0

I am trying to write a Makefile for GNU make. I can't figure out what the problem is here:

foo := this|works
bar := "I lost my 'single quotes'"
baz := 'make|will|not|accept|this|with|the|single|quotes'

whatIWant := "A string with its 'single|quoted|regex|alternatives'"

this-almost-works:  #But the single quotes are lost.
        @printf '%s ' "$(whatIWant)"

this-fails-horribly:
        @printf '$(whatIWant)'

I get the following error message

/bin/sh: 1: quoted: not found
/bin/sh: 1: /bin/sh: 1: regex: not foundalternatives": not found

blah blah Error 127
  1. Why is it trying to run parts of this string in the shell?

  2. How can I define a variable to contain exactly the contents of whatIWant?

Jim Vargo
  • 362
  • 1
  • 8
  • 1
    Escape your pipes with '\', if I recall correctly pipes are special characters in makefiles – mascoj Mar 03 '17 at 23:16
  • Cool. That helps avoid the error message. Though I don't really see why foo works and baz does not work. I still need those single quotes preserved. For some reason they disappear. – Jim Vargo Mar 03 '17 at 23:23
  • 2
    Make doesn't interpret quotes, they are in the string. So really what you are doing here is : ````@printf '%s ' ""A string with its 'single|quoted|regex|alternatives'"" ```` which is interpreted with quotes so ````'single|quoted|regex|alternatives'```` loses its quotes because it is a quoted string. Does that make sense? – mascoj Mar 03 '17 at 23:33
  • See: http://stackoverflow.com/questions/23330243/gnu-makefile-how-to-and-when-to-quote-strings – mascoj Mar 03 '17 at 23:34
  • Yes I see now. Thanks! – Jim Vargo Mar 03 '17 at 23:51
  • 2
    Pipes are _not_ special characters in makefiles, except in GNU make prerequisite lists where they separate normal prerequisites from order-only prerequisites. They are special to the shell, but not inside quotes (of either type). – MadScientist Mar 04 '17 at 06:14
  • I see. What was happening was a quoting problem. Instead of sending quoted pipes to the shell, the quotes were being cancelled and the shell saw the pipes – Jim Vargo Mar 05 '17 at 00:35

1 Answers1

1

Might be worth looking in detail at the expansion.

When defining variables, just about the only character that has an effect is $. Everything else is taken literally. It's worth nothing that white space around the assignment operator (= or :=) is ignored.

foo  :=     this|works

foo is assigned the literal text this|works. Similarly,

baz := 'make|will|not|accept|this|with|the|single|quotes'

assigns the literal text 'make|will|not|accept|this|with|the|single|quotes' to baz. Fine and dandy.

Now, when make decides to build this-fails-horribly (possibly because you said to the shell make this-fails-horribly) it expands the block of commands before doing anything. Not unreasonably, $(whatIWant) is replaced by "A string with its 'single|quoted|regex|alternatives'". Again, fine and dandy. What is left is passed verbatim, one line at a time, to the shell. The shell sees

printf '"A string with its 'single|quoted|regex|alternatives'"'

(which make would have helpfully echoed to you if you had left off the @ prefix). Now we are in the land of shell quoting.

  • The printf command is passed one parameter: "A string with its single:
    • '"A string with its ' is a single quoted string. The shell strips the 's and is left with the text "A string with its.
    • single has no metacharacters in it, so the shell leaves this alone.
  • The output is piped to the quoted command
  • The output is piped to the regex command
  • The output is piped to the alternatives" command
    • The shell sees the single quoted string '=', strips the quotes leaving you with a literal = which it appends to the word alternatives

No syntax error. When the shell attempts to set up the pipeline it looks for the alternatives" command. It doesn't find one in the directories it its $PATH, so it stops with the message /bin/sh: 1: /bin/sh: 1: regex: not foundalternatives": not found.

One possible encoding:

.PHONY: this-workes-nicely
this-workes-nicely:
    echo $(whatIWant)

though you'll probably find it's cleaner to leave the quotes outside the variable definition in the first place.

bobbogo
  • 14,989
  • 3
  • 48
  • 57
  • Thanks for explaining it all out. The whole point of the printf was for debugging purposes, so I especially appreciate the comment that the '@' was suppressing the exact message I was trying to get at. – Jim Vargo Mar 06 '17 at 20:12