Search code examples
makefilevariable-expansion

Variable expansion in Makefiles


Make seems to be expanding variables only after a rule is active.

make ok displays the resolved NAME (ie. "test")

make bad claims to depend on "grep" (rather than "test")

How can I get make to expand NAME before it checks the dependencies of the "bad" rule?

CMakeLists.txt:

add_executable(test testA.c testB.c)  # compiler (output input input ...)

Makefile (full):

#========================================
# Shell cannot handle parentheses:
#    *** unterminated call to function 'shell': missing ')'.  Stop.
# Have also tried putting {"(", ")", "\(", "\)"} in variables
#   ...but it just created a different problem
#
#NAME := $(shell grep "add_executable(" CMakeLists.txt | sed 's/[^(]*( *\([^ ]*\) .*/\1/')
  
#========================================
# Curious results (same with or without the colon)
#
NAME := `grep "add_executable(" CMakeLists.txt | sed 's/[^(]*( *\([^ ]*\) .*/\1/'`
    
#========================================
# As expected, displays:
#    NAME=¦test¦"
#
PHONY: ok
ok:
    @echo "NAME=¦${NAME}¦"
 
#========================================
# Dies with:
#    *** No rule to make target '`grep', needed by 'bad'.  Stop."
#
.PHONY: bad
bad: ${NAME}
    @echo "NAME=¦${NAME}¦"

Makefile (same, but condensed):

NAME := `grep "add_executable(" CMakeLists.txt | sed 's/[^(]*( *\([^ ]*\) .*/\1/'`
ok:
    @echo "NAME=¦${NAME}¦"
bad: ${NAME}
    @echo "NAME=¦${NAME}¦"

Solution

  • Instead of backquotes, use the shell function:

    NAME := ${shell sed -n '/add_executable/{s/add_executable( *//;s/ .*//;p;}' CMakeLists.txt}
    

    (This use of curly braces instead of parentheses around the shell command is a kludge to allow a parenthesis in the sed command, which I don't know how to escape elegantly.)