Search code examples
makefile

Trouble using eval function in makefile


I'm trying to write a makefile function, which adds sources from directory to a variable and recalculates object variable.

rwildcard = $(wildcard $(addprefix $1,$2)) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2))

define __add_sources
    SOURCES += $(call rwildcard,$(realpath $1)/,*.c *.S) 
    _SOURCES = $$(SOURCES:  %= %)
    OBJECTS = $$(addprefix $(OBJDIR)/,$$(addsuffix .o,$$(subst $(realpath $1)/,$2,$$(call rwildcard,$$(_SOURCES)))))
endef

when I call

add_sources = $(info $(call __add_sources,$1,$2))
_ = $(call add_sources,src,)

it does output (sorry, had to omit some paths output for privacy, hope that does not matter)

    SOURCES +=  <path>/<file>.S   <path>/<file>.c <path>/<file>.c <path>/<file>.S         <path>/<file>.c   <path>/<file>.c <path>/<file>.c           <path>/<file>.c   <path>/<file>.c <path>/<file>.c          
    _SOURCES = $(SOURCES:  %= %)
    OBJECTS = $(addprefix <objpath>/objects/,$(addsuffix .o,$(subst <srcpath>,,$(call rwildcard,$(_SOURCES)))))

which seems fine and looks like the thing I need, but, when I replace info with eval in add_sources, expecting, that Makefile will evaluate the literal and process the assignment, but on output I see nothing assigned to SOURCES nor OBJECTS.


Solution

  • Wow this is a crazy accumulation of coincidences to get the results you are seeing.

    I don't really understand why you have so many levels of indirection. But the underlying problem is that you are not actually INVOKING any of these functions. You have this:

    rwildcard = $(wildcard $(addprefix $1,$2)) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2))
    
    define __add_sources
        SOURCES += $(call rwildcard,$(realpath $1)/,*.c *.S) 
        _SOURCES = $$(SOURCES:  %= %)
        OBJECTS = $$(addprefix $(OBJDIR)/,$$(addsuffix .o,$$(subst $(realpath $1)/,$2,$$(call rwildcard,$$(_SOURCES)))))
    endef
    
    add_sources = $(info $(call __add_sources,$1,$2))
    _ = $(call add_sources,src,)
    

    As a result of this code you have defined four make variables: rwildcard, __add_sources, add_sources, and _.

    But you have never actually USED any of these variables, so they are not expanded, and they have no effect. You need to ensure they are expanded. For example you can add a line like this:

    $(_)
    

    all by itself, which will force the _ variable to be expanded. Then you will see the results of your eval.

    So, you may ask, why do you see the output when you use info, if the variable is not expanded? That's the next coincidence.

    The reason is that you're using a variable named _ and that variable is special to the shell, and so it will be added to the environment that your shell starts make with. Make will re-expand any variable that it received via the environment, when it starts a shell script.

    Since the _ variable was received from the environment when make first invokes a recipe line it will expand that value automatically, and that's where the output of the info is seen. However, any changes that were made to any variables like SOURCES will not be preserved since we are expanding variables to be added to the sub-shell's environment, not for make.

    If you rename that "temporary" variable from _ to something else, like dummy or similar, which is not a variable inherited from the environment, then you'll see that nothing about the makefile you show above will print out any output because that variable is never expanded.