Non-recursive make: include makefile segment in a

2019-05-03 10:29发布

问题:

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)))

回答1:

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).



回答2:

In my prorab build system I pass arguments to compiler from this_* variables instead of global CFLAGS, though CFLAGS is passed to compiler also. Then, after I defined the build rules I can clear all the this_* variables like this:

$(foreach var,$(filter this_%,$(.VARIABLES)),$(eval $(var) := ))

And I created a definition for this

prorab-clear-this-vars = $(foreach var,$(filter this_%,$(.VARIABLES)),$(eval $(var) := ))

And it can be used like this

$(eval $(prorab-clear-this-vars))