相关:Target-specific Variables as Prerequisites in a Makefile
我正在尝试制作一个Makefile,该文件使用目标特定变量来指定目标文件和最终可执行文件的输出目录。这个想法是维护两个单独的二进制版本,一个“发行”版本和一个“调试”版本,以及额外的调试信息。
我的问题是,即使我没有更改任何内容,“make”也会每次都进行干净的构建。我很确定这是因为'make'在评估'debug'或'release'目标先决条件中的变量声明之前先评估目标'corewars'的先决条件。
Makefile如下所示。
CXX=g++
LD=g++
LDFLAGS=
CXXFLAGS=-Iinclude -Wall -Wextra
OBJECTS=main.o Machine.o Core.o ProcessQueue.o Instruction.o
OUTPUT_DIR:=Test/
.PHONY: default
.PHONY: all
.PHONY: release
default: release
all: release
release: OUTPUT_DIR:=Release/
release: corewars
.PHONY: debug
debug: CXXFLAGS+=-DDEBUG -g
debug: OUTPUT_DIR:=Debug/
debug: corewars
corewars: $(OUTPUT_DIR) $(addprefix $(OUTPUT_DIR),$(OBJECTS))
$(LD) -o $(addprefix $(OUTPUT_DIR),corewars) $(addprefix $(OUTPUT_DIR),$(OBJECTS))
Release:
mkdir -p $@
Debug:
mkdir -p $@
%.o: %.cpp include/%.h
$(CXX) -c $(CXXFLAGS) $< -o $(OUTPUT_DIR)$@
.PHONY: clean
clean:
$(RM) -r Release
$(RM) -r Debug
最佳答案
首先,一个非语音食谱must create a target, $@
, not $(OUTPUT_DIR)$@
。还可以考虑将目录依赖项转换为order-only先决条件。
为了在先决条件列表中获得适当的$(OUTPUT_DIR)
值,您必须使用secondary expansion,因为否则,在主扩展期间,将使用全局定义OUTPUT_DIR:=Test/
而不是特定于目标的定义。
不幸的是,我无法想到一种使用目标特定变量来使其正常工作的明智方法,而无需借助二次扩展和vpath魔术。就我个人而言,我宁愿先设置环境(找出OUTPUT_DIR
的值等),然后使用适当的值重新执行Make。
ifndef OUTPUT_DIR
.PHONY: default all release debug
default all: release
release: export OUTPUT_DIR := Release/
debug: export OUTPUT_DIR := Debug/
debug: export EXTRA_CXXFLAGS := -DDEBUG -g
release debug:
@$(MAKE)
else
# ...
CXXFLAGS := -Iinclude -Wall -Wextra $(EXTRA_CXXFLAGS)
PROGRAM := $(OUTPUT_DIR)corewars
OBJECTS := $(addprefix $(OUTPUT_DIR), \
main.o Machine.o Core.o ProcessQueue.o Instruction.o)
# Default target.
$(PROGRAM): $(OBJECTS) | $(OUTPUT_DIR)
$(LD) -o $@ $<
$(OUTPUT_DIR)%.o: %.cpp | $(OUTPUT_DIR)
$(CXX) -c $(CXXFLAGS) $< -o $@
$(OUTPUT_DIR):
mkdir -p $@
endif # OUTPUT_DIR
这两个部分可以将它们分成单独的makefile,一个是root(启动器),另一个是进行实际工作的文件,以使整个内容更易于管理。关于makefile将特定于目标的变量作为前提条件,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/10824586/