0

I have issues assigning the same variable multiple times in Makefile. I am making a kind of modular makefile where I only deal with components instead of every source file and include directory. This first solution works fine

MainRootDir = Components/Main
include               $(RootDir)/$(MainRootDir)/Main.mak
Debug_Includes +=    $(addprefix $(MainRootDir)/,$(Main_Includes))
Debug_ASM_Sources += $(addprefix $(MainRootDir)/,$(Main_ASM_Static))
Debug_CC_Sources +=  $(addprefix $(MainRootDir)/,$(Main_CC_Static))
Debug_ASM_Sources += $(addprefix $(CfgDir)/,     $(Main_ASM_Config))
Debug_CC_Sources +=  $(addprefix $(CfgDir)/,     $(Main_CC_Config))

AdderRootDir = Components/Adder
include               $(RootDir)/$(AdderRootDir)/Adder.mak
Debug_Includes +=    $(addprefix $(AdderRootDir)/,$(Adder_Includes))
Debug_ASM_Sources += $(addprefix $(AdderRootDir)/,$(Adder_ASM_Static))
Debug_CC_Sources +=  $(addprefix $(AdderRootDir)/,$(Adder_CC_Static))
Debug_ASM_Sources += $(addprefix $(CfgDir)/,      $(Adder_ASM_Config))
Debug_CC_Sources +=  $(addprefix $(CfgDir)/,      $(Adder_CC_Config))

However, if I try to standardize the block by defining variables and Re-Assigning new value before adding the software component each time, it stops working:

SwcName = Main
SwcRootDir = Components/$(SwcName)
include               $(RootDir)/$(SwcRootDir)/$(SwcName).mak
Debug_Includes +=    $(addprefix $(SwcRootDir)/,$($(SwcName)_Includes))
Debug_ASM_Sources += $(addprefix $(SwcRootDir)/,$($(SwcName)_ASM_Static))
Debug_CC_Sources +=  $(addprefix $(SwcRootDir)/,$($(SwcName)_CC_Static))
Debug_ASM_Sources += $(addprefix $(CfgDir)/,    $($(SwcName)_ASM_Config))
Debug_CC_Sources +=  $(addprefix $(CfgDir)/,    $($(SwcName)_CC_Config))
 
SwcName = Adder
SwcRootDir = Components/$(SwcName)
include               $(RootDir)/$(SwcRootDir)/$(SwcName).mak
Debug_Includes +=    $(addprefix $(SwcRootDir)/,$($(SwcName)_Includes))
Debug_ASM_Sources += $(addprefix $(SwcRootDir)/,$($(SwcName)_ASM_Static))
Debug_CC_Sources +=  $(addprefix $(SwcRootDir)/,$($(SwcName)_CC_Static))
Debug_ASM_Sources += $(addprefix $(CfgDir)/,    $($(SwcName)_ASM_Config))
Debug_CC_Sources +=  $(addprefix $(CfgDir)/,    $($(SwcName)_CC_Config))

The issue is that the source files of component Main are defined multiple times. As if the Adder block is also expanding SwcName with the value Main.

Any idea how to prevent this?

3
  • If you are using GNU make you could use the define keyword to declare a parametrized function which you can then call with the arguments Main and Adder. gnu.org/software/make/manual/html_node/… Commented Apr 19, 2021 at 13:15
  • You mean create a macro for each assignment? e.g. Debug_ASM_Sources += $(call addStatic, $(SwcName)) Commented Apr 19, 2021 at 13:43
  • Yeah, I would have posted an answer to that effect if your question had mentioned that you are using GNU make and not the much simpler traditional tool. Commented Apr 19, 2021 at 15:18

2 Answers 2

1

You are using recursively expanded variables (var = ...), which is the default. So make defers the evaluation of the right hand side of your assignments until the variable's value is really needed. Example:

a = 1
b += $(a)
a = 2
b += $(a)

.PHONY: all
all:
    @echo $(b)

will print 2 2 instead of the 1 2 you expect because what make actually stored in variable b was $(a) $(a), which it evaluated only before passing the recipe of all to the shell. And at that time a has only one single value: the last one it has been assigned, that is, 2.

You could use simply expanded variables (var := ...), instead:

b :=
a := 1
b += $(a)
a := 2
b += $(a)

.PHONY: all
all:
    @echo $(b)

which will print 1 2. Do not forget the apparently useless b :=: it tells make that b is not a recursively expanded variable but a simply expanded one. Different from the default form, the value assigned to a simply expanded variable is evaluated when it is defined, its expansion is not deferred until the variable's value is needed.

But repeating large portions of code as in what you show is not optimal. Indeed, repeating things is frequently needed with humans but almost never optimal with computers. If you are using GNU make, as suggested by tripleee, you could use a kind of user-defined function:

Debug_Includes :=
Debug_ASM_Sources :=
...

# $(1) is the current SwcName
define MY_FUNC
SwcRootDir := Components/$(1)
include $$(RootDir)/$$(SwcRootDir)/$$(1).mak
Debug_Includes += $$(addprefix $$(SwcRootDir)/,$$($(1)_Includes))
Debug_ASM_Sources += $$(addprefix $$(SwcRootDir)/,$$($$(1)_ASM_Static))
...
endef

and then:

$(foreach SwcName,Main Adder,$(eval $(call MY_FUNC,$(SwcName))))

Do not forget the $$ in the macro definition. They are needed. See the GNU make manual for the full explanation.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you very much for the explanation. As @HardcoreHenry guessed and suggested, I flagged all the target variables with an empty assignment in the beginning. Eg.g. Debug_... := . Worked like a charm.
0

This is a matter of recursive vs simply expanded variables. I'm going to guess that Debug_Includes is not initialized with a := earlier on, which means it defaults to be a recursively expanded variable. Therefore it is set to $(RootDir)/$(SwcRootDir)/$(SwcName).mak, and the internal variables are only expanded when it is referenced (at which point SwcRootDir will be Components/$(SwcName)).

Try initializing your variables with := at the top of your file to make them simple. Then they will be assigned values right away, and the internal variables will be set to what they were at the time of the definition.

1 Comment

Thank you very much. You were right. I hat to initialize all the Debug_.. variables with := at the beginning.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.