如何在Makefile中保持构建配方不变,按构建类型修改编译标志
语法错误导致目标依赖未正确设置:你在
release和debug目标的变量赋值行里,错误地将$(TARGET)写入了FLAGS的值中。原代码release: FLAGS = $(OPT_FLAGS) $(TARGET)的含义是给release目标的FLAGS变量赋值为$(OPT_FLAGS)加$(TARGET)的文件名,而非让release依赖$(TARGET),这导致make release/debug不会自动触发$(TARGET)的构建(除非手动指定$(TARGET)作为目标)。目标特定变量的作用域限制:即使修正了依赖问题,目标特定变量(如
release: FLAGS = ...)的作用域仅局限于该目标自身的配方,以及该目标执行时的后续依赖。但Make构建目标时会先处理前置依赖(即$(TARGET)),此时$(TARGET)的配方运行在全局上下文,无法读取到release/debug目标的特定变量FLAGS。
方案一:递归Make传递全局变量(推荐)
通过启动子Make进程并传递全局变量FLAGS,确保所有构建配方都能读取到正确的标志:
CXX = g++ CXX_FLAGS = -pedantic -Wall -Wextra TARGET_FLAGS = $(CXX_FLAGS) -shared -fPIC OPT_FLAGS = -Ofast -march=native DBG_FLAGS = -g3 -Og -ggdb SRC = $(wildcard ./src/*/impl.cpp) INCLPATH = ./headers OBJECTS = $(patsubst ./src/%/impl.cpp,./build/%.o,$(SRC)) TARGET = lfds.so .PHONY: release debug clean release: $(MAKE) FLAGS="$(OPT_FLAGS)" $(TARGET) debug: $(MAKE) FLAGS="$(DBG_FLAGS)" $(TARGET) $(TARGET): $(OBJECTS) echo "Hi $(FLAGS)" $(CXX) -I$(INCLPATH) $(TARGET_FLAGS) $(FLAGS) $^ -o $@ ./build/%.o: ./src/%/impl.cpp echo "Hi $(FLAGS)" $(CXX) -I$(INCLPATH) $(CXX_FLAGS) $(FLAGS) -c $< -o $@ clean: rm -rf $(OBJECTS) rm $(TARGET)
执行make debug时,子Make进程会将FLAGS设为$(DBG_FLAGS),所有构建步骤都能读取到该变量;执行make release同理。
方案二:利用目标特定变量的继承
通过给$(TARGET)设置目标特定变量,并让release/debug触发该目标的构建,确保依赖的构建上下文能继承变量:
CXX = g++ CXX_FLAGS = -pedantic -Wall -Wextra TARGET_FLAGS = $(CXX_FLAGS) -shared -fPIC OPT_FLAGS = -Ofast -march=native DBG_FLAGS = -g3 -Og -ggdb SRC = $(wildcard ./src/*/impl.cpp) INCLPATH = ./headers OBJECTS = $(patsubst ./src/%/impl.cpp,./build/%.o,$(SRC)) TARGET = lfds.so .PHONY: release debug clean # 定义release/debug目标依赖TARGET,并给TARGET设置对应FLAGS release: $(TARGET) $(TARGET): FLAGS = $(OPT_FLAGS) debug: $(TARGET) $(TARGET): FLAGS = $(DBG_FLAGS) # 确保OBJECTS的构建能继承TARGET的FLAGS变量 $(OBJECTS): ./build/%.o: ./src/%/impl.cpp echo "Hi $(FLAGS)" $(CXX) -I$(INCLPATH) $(CXX_FLAGS) $(FLAGS) -c $< -o $@ $(TARGET): $(OBJECTS) echo "Hi $(FLAGS)" $(CXX) -I$(INCLPATH) $(TARGET_FLAGS) $(FLAGS) $^ -o $@ clean: rm -rf $(OBJECTS) rm $(TARGET)
这种方式中,当执行make debug时,$(TARGET)会使用debug版本的FLAGS,其依赖的$(OBJECTS)也会在同一个上下文里构建,从而读取到正确的FLAGS。
内容的提问来源于stack exchange,提问作者Setu

