不要重新评估依赖变量



我有一个用来构建几个不同程序的Makefile。我的SOURCESOBJECTS取决于PRODUCT,它应该是正在构建的产品。目前,我在列出每个规则对OBJECTS的依赖之前设置了PRODUCT:

CORE_LIB    := libcore
SCANNER     := scanner
FLETCHER    := fletcher
PRODUCT     := $(SCANNER)
SOURCE_DIR  := ./src
BUILD_DIR   := ./build
OBJECTS_DIR := $(BUILD_DIR)/intermediate
PRODUCT_DIR := $(BUILD_DIR)/product

SOURCES     = $(wildcard $(SOURCE_DIR)/$(PRODUCT)/*.c) $(wildcard $(SOURCE_DIR)/$(PRODUCT)/*/*.c)
OBJECTS     = $(SOURCES:$(SOURCE_DIR)/%.c=$(OBJECTS_DIR)/%.o)
# change PRODUCT based on rule being ran
$(SCANNER): PRODUCT := $(SCANNER)
$(SCANNER): $(OBJECTS)
    # link stuff
$(CORE_LIB): PRODUCT := $(CORE_LIB)
$(CORE_LIB): $(OBJECTS)
    # link stuff

PRODUCT设置之前,OBJECTS一直被求值,并且不会根据规则改变。我错过什么了吗?

你不能那样做。GNU make手册声明,关于目标特定的变量:

与自动变量一样,这些值仅在目标配方的上下文中可用(以及在其他特定于目标的赋值中)。

这意味着您不能在扩展先决条件(如$(OBJECTS))期间使用特定于目标的变量值。或者更确切地说,您可以在那里使用任何变量,但是特定于目标的值不可用。由于您将全局PRODUCT的值设置为$(SCANNER),即scanner,因此该值将在所有先决条件中使用。

你有多种选择。你可以定义多个变量,像这样:

$(SCANNER)_SOURCES = $(wildcard $(SOURCE_DIR)/$(SCANNER)/*.c) $(wildcard $(SOURCE_DIR)/$(SCANNER)/*/*.c)
$(CORE_LIB)_SOURCES = $(wildcard $(SOURCE_DIR)/$(CORE_LIB)/*.c) $(wildcard $(SOURCE_DIR)/$(CORE_LIB)/*/*.c)

然后创建如下规则:

$(SCANNER): $($(SCANNER)_SOURCES:$(SOURCE_DIR)/%.c=$(OBJECTS_DIR)/%.o)
        # link stuff
$(CORE_LIB): $($(CORE_LIB)_SOURCES:$(SOURCE_DIR)/%.c=$(OBJECTS_DIR)/%.o)
        # link stuff

如果你有更多的这些,你可以创建一个宏并使用eval,但我不会为复杂性而烦恼,除非你真的要有一堆。

您可以使用二级展开来简化目标定义,如下所示:

OBJECTS = $$($$@_SOURCES:$(SOURCE_DIR)/%.c=$(OBJECTS_DIR)/%.o)
.SECONDEXPANSION:
$(SCANNER): $(OBJECTS)
        # link stuff
$(CORE_LIB): $(OBJECTS)
        # link stuff

最新更新