What's wrong with the following GNU make shell variable expansion?
Asked Answered
S

1

9

On this line:

GCCVER:=$(shell a=`mktemp` && echo $'#include <stdio.h>\nmain() {printf("%u.%u\\n", __GNUC__, __GNUC_MINOR__);}' | gcc -o "$a" -xc -; "$a"; rm "$a")

I get:

*** unterminated call to function `shell': missing `)'.  Stop.

What's wrong with my stupidly circuitous variable?

Update0

$ make --version
GNU Make 3.81
$ bash --version
GNU bash, version 4.2.8(1)-release (x86_64-pc-linux-gnu)
$ uname -a
Linux 2.6.38-10-generic #46-Ubuntu SMP x86_64 GNU/Linux
$ gcc --version
gcc (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2
Saddler answered 12/8, 2011 at 6:24 Comment(2)
BTW, what's wrong with $(shell gcc -v 2>&1 | tail -1 | awk '{print $$3}') ?Tartrazine
@reinierpost: Nothing except that I wasn't aware of it.Saddler
J
13

when using $ for Bash inside a Makefile, you need to double them: $$a for example. I'm not familiar with the notation $' but I'll have to assume you know what you're doing with that. unless it's a Makefile construct, you need to double the dollar sign on that one too.

also, the hash sign # is terminating the shell expansion in Make's evaluation, which is why it never sees the right paren. escaping it helps, but I don't have it working quite right yet.

I'm debugging it by having two steps: first is setting GCCVER to be the list of commands without the enclosing $(shell), then in the 2nd step setting GCCVER := $(shell $(GCCVER)). you might want to try that too, commenting out the $(shell) step when it doesn't work, using export, and making a "set" recipe:

GCCVER := some commands here
#GCCVER := $(shell $(GCCVER))  # expand the commands, commented out now
export  # all variables available to shell
set:
        set  # make sure this is prefixed by a tab, not spaces

Then:

make set | grep GCCVER

[update] this works:

GCCVER := a=`mktemp` && echo -e '\#include <stdio.h>\nmain() {printf("%u.%u\\n", __GNUC__, __GNUC_MINOR__);}' | gcc -o "$$a" -xc -; "$$a"; rm "$$a"
GCCVER := $(shell $(GCCVER))
export
default:
    set

jcomeau@intrepid:/tmp$ make | grep GCCVER
GCCVER=4.6

And full circle, having gotten rid of the extra step:

jcomeau@intrepid:/tmp$ make | grep GCCVER; cat Makefile 
GCCVER=4.6
GCCVER := $(shell a=`mktemp` && echo -e '\#include <stdio.h>\nmain() {printf("%u.%u\\n", __GNUC__, __GNUC_MINOR__);}' | gcc -o "$$a" -xc -; "$$a"; rm "$$a")
export
default:
    set

Using the $' Bash construct:

jcomeau@intrepid:/tmp$ make | grep GCCVER; cat Makefile 
GCCVER=4.6
GCCVER := $(shell a=`mktemp` && echo $$'\#include <stdio.h>\nmain() {printf("%u.%u\\n", __GNUC__, __GNUC_MINOR__);}' | gcc -o "$$a" -xc -; "$$a"; rm "$$a")
export
default:
    set

Since your system doesn't work the same as mine, I'm going to cop out and say either use reinierpost's suggestion or, alternatively:

GCCVER := $(shell gcc -dumpversion | cut -d. -f1,2)
Jaimiejain answered 12/8, 2011 at 6:33 Comment(10)
still testing... that's not the whole of your problem.Jaimiejain
the -e option to echo was necessary for the \n to be interpolated.Jaimiejain
The $'' evaluates the contents like a C string.Saddler
OK, I'll take your word for it! But as you can see it works without it.Jaimiejain
Great effort, but I'm getting <stdin>:1:1: error: stray ‘#’ in program.Saddler
what does GCCVER look like when you don't wrap $(shell) around it?Jaimiejain
I can't seem to duplicate your error. What OS are you running? Mine is Debian stable.Jaimiejain
I've added relevant version info to the question, here's the output of the "$" version, preshell as per your paragraph earlier on how to dump its contents: GCCVER='a=`mktemp` && echo $'"'"'#include <stdio.h>\nmain() {printf("%u.%u\\n", __GNUC__, __GNUC_MINOR__);}'"'"' | gcc -o "$a" -xc -; "$a"; rm "$a"'Saddler
@Jaimiejain let us continue this discussion in chatSaddler
Thanks for the comment about #. That saved me some time.Tribunate

© 2022 - 2024 — McMap. All rights reserved.