Steve Lorimer Steve Lorimer - 3 months ago 20
C++ Question

Non-recursive make: include makefile segment in a loop

I have a non recursive makefile which defines helper functions which can be used to build libraries etc

define make-library
# build lib from *.cpp in current dir...
endef


Each library/binary is defined in a separate makefile segment called
module.mk
which calls these helper functions

$(eval $(call make-library, my_lib))


The makefile searches the source tree for makefile segments, and includes them

modules := $(shell find . -name module.mk | xargs echo)
include $(modules)


Problem:



I define a default set of
CPPFLAGS
at the top of the makefile:

CPPFLAGS += -m64 -std=c++11 -Wall -Wextra -Werror -Wno-system-headers


They are selectively updated depending on build variant etc:

ifeq "$(BUILD)" "debug"
CPPFLAGS += $(DEBUG_FLAGS)
endif


they are used in each target where required:

$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
@$(CXX) $(CPPFLAGS) -I$(BASE_DIR) -I. -o $@ -c $(filter %.cpp,$^)


The problem I have is that sometimes I want to override
CPPFLAGS
in a module:

CPPFLAGS += -Wno-unused-but-set-variable
$(eval $(call make-library, my_lib))


However, this updates the global
CPPFLAGS
, so every module gets the updated flags.

Solution:



My idea is to iterate over
$(modules)
, and before including each one, reset
CPPFLAGS
to a default set. Any changes in the current module will be reset for the next.

Something along the lines of:

$(foreach module,$(modules),$(eval \
CPPFLAGS := DEFAULT_CPPFLAGS \
include $module))


Question:



The above syntax is incorrect, but should hopefully illustrate what I'm trying to achieve - any ideas on how best to do what I've described?

Alternative:



Alternately, perhaps each
module.mk
could define a
LOCAL_FLAGS
variable which could be passed to the
make-library
call?

LOCAL_FLAGS := -Wno-unused-but-set-variable
$(eval $(call make-library, my_lib, $(LOCAL_FLAGS)))

Answer

You can't have per-makefile variables if they are used at recipe time. Recipes execute after all assignments/etc. have been done.

If you use file-local variables or force the global variables expansion at parse time you can do this though.

You can save, set, use and reset the values in each module.mk file.

$ cat foo/module.mk
oCPPFLAGS:=$(CPPFLAGS)
CPPFLAGS+=something local

target: CPPFLAGS:=$(CPPFLAGS)
target:
        some_cmd $(CPPFLAGS)

FOO:=$(oFOO)

Or, more like your original attempt, you can force eval them back to some default value during the loop.

$ cat Makefile
$(foreach module,$(modules),$(eval CPPFLAGS := DEFAULT_CPPFLAGS)$(eval include $(module)))
$(eval CPPFLAGS := DEFAULT_CPPFLAGS)

$ cat foo/module.mk
target: CPPFLAGS:=$(CPPFLAGS)
target:
        some_cmd $(CPPFLAGS)

But the important thing here is the variables are expanded/used at parse time. They cannot be used at recipe time unless they are saved in some other variable (like the target-specific ones in the examples above).

Comments