非递归 make:在循环中包含 makefile 段

Non-recursive make: include makefile segment in a loop

我有一个非递归 makefile,它定义了可用于构建库等的辅助函数

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

每个 library/binary 都在一个名为 module.mk 的单独 makefile 段中定义,该段调用这些辅助函数

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

makefile 在源代码树中搜索 makefile 段,并包含它们

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

问题:

我在 makefile 的顶部定义了一组默认的 CPPFLAGS

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

它们根据构建变体等有选择地更新:

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

它们在需要的每个目标中使用:

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

我遇到的问题是有时我想覆盖模块中的 CPPFLAGS

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

但是,这会更新 global CPPFLAGS,因此每个模块都会获得更新的标志。

解决方案:

我的想法是迭代 $(modules),并在包含每个之前,将 CPPFLAGS 重置为默认集。当前模块中的任何更改都将在下一个模块中重置。

大致如下:

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

问题:

以上语法不正确,但应该能说明我正在努力实现的目标 - 关于如何最好地完成我所描述的事情的任何想法?

选择:

或者,也许每个 module.mk 可以定义一个可以传递给 make-library 调用的 LOCAL_FLAGS 变量?

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

如果在配方时使用它们,则不能有每个 makefile 变量。食谱最终执行 assignments/etc。已完成。

如果您使用文件局部变量或在解析时强制扩展全局变量,您可以这样做。

您可以保存、设置、使用和重置每个 module.mk 文件中的值。

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

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

FOO:=$(oFOO)

或者,更像您最初的尝试,您可以在循环期间强制将它们评估回某个默认值。

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

但这里重要的是变量在解析时是 expanded/used。它们不能在配方时使用,除非它们保存在其他变量中(如上面示例中的特定于目标的变量)。

在我的 prorab 构建系统中,我将参数从 this_* 变量而不是全局 CFLAGS 传递给编译器,尽管 CFLAGS 也被传递给编译器。 然后,在我定义构建规则后,我可以像这样清除所有 this_* 变量:

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

我为此创建了一个定义

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

而且还可以这样使用

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