我有一个用来构建几个不同程序的Makefile。我的SOURCES
和OBJECTS
取决于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