user2331977
user2331977

Reputation: 153

Makefile expanding variable inside define

define func1
    include $(shell pwd)/test/$(strip $1)/component.mk
    $(info :::::::${NAME} ::::::::::::::: )
endef

INCLUDES := a  b c

$(foreach dir, $(INCLUDES), $(eval $(call func1, $(dir)) ))

all : $(objs)

Contents of each makefile:

cat test/a/component.mk
    NAME := AA

cat test/b/component.mk
    NAME := BB

cat test/c/component.mk
    NAME := CC

Output is

::::::: ::::::::::::::: 
:::::::AA ::::::::::::::: 
:::::::BB ::::::::::::::: 

It looks like first time NAME is empty.

Upvotes: 2

Views: 415

Answers (1)

bobbogo
bobbogo

Reputation: 15483

Let's look at the expansion of $(foreach dir, ${INCLUDES}, $(eval $(call func1, ${dir}) )) in painful detail.

  • ${INCLUDES} is expanded, giving $(foreach dir,a b c,$(eval $(call func1,${dir})))
  • Next dir is set to a
  • $(call func1,a) is expanded
    • 1 is set to a
    • func1 is expanded:
      include $(shell pwd)/test/$(strip $1)/component.mk
      $(info :::::::${NAME} ::::::::::::::: )
      • $(shell pwd) becomes HERE, say (N.B. Use ${CURDIR} instead)
      • $(strip $1) becomes $(strip a) becomes a
      • ${NAME} expands to nothing
      • $(info ::::::: ::::::::::::::: ) expands to nothing
        • As a side effect ::::::: ::::::::::::::: appears on stdout
  • $(eval $(call func1,a)) expands to $(eval include HERE/test/a/component.mk), expands to nothing
    • As a side effect, the include is processed by make
    • Presumably HERE/test/a/component.mk exists and contains valid make syntax, and the variable NAME gets a value.

1 is set to b. Lather, rinse, repeat.

Tip

To get a hint of problems in code like this, always run make with --warn:

$ make --warn -Rr
Makefile:8: warning: undefined variable 'NAME'
::::::: :::::::::::::::
⋮

Fix

To get some insight, replace the $(eval stuff) with $(error [stuff])

$ make
::::::: :::::::::::::::
Makefile:8: *** [    include /cygdrive/c/Users/somewhere/a/component.mk
    ].  Stop.

Here we see the $(info …) has disappeared even before it has got to the eval. The naive fix is pretty horrible.

define func1
  include $(shell pwd)/test/$(strip $1)/component.mk
  $$(info :::::::$${NAME} ::::::::::::::: )
endef

Running this with the $(error …) in place gives

$ make
Makefile:8: *** [    include /cygdrive/c/Users/somewhere/a/component.mk
    $(info :::::::${NAME} ::::::::::::::: )].  Stop.

That stuff between the [ and ] is valid make syntax. Tidied up it looks like:

include /cygdrive/c/Users/somewhere/a/component.mk
$(info :::::::${NAME} ::::::::::::::: )

Job done. There are cleaner ways, but you need to understand the pain first!

Upvotes: 4

Related Questions