Makefile疑问:注释编译规则后为何报“无目标生成规则”错误?
Makefile中patsubst无法替代模式规则的原因解析
问题背景
我正在学习Makefile,若我的理解有误请指正。
我使用以下代码生成源文件和目标文件列表:
CXX_SOURCES = $(wildcard $(SOURCE_DIR)/*.cc) CXX_OBJECTS = $(patsubst $(SOURCE_DIR)/%.cc, $(BUILD_DIR)/%.o, $(CXX_SOURCES))
我的理解是:patsubst会将$(CXX_SOURCES)中所有匹配$(SOURCE_DIR)/%.cc的字符串替换为$(BUILD_DIR)/%.o,但它仅做字符串重命名,不会将.cc文件编译为.o文件。因此需要创建与patsubst替换参数一致的$(BUILD_DIR)/%.o目标来完成编译。
但当我注释掉以下模式规则后:
$(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.cc $(CXX_COMPILER_CALL) -c $< -o $@
出现错误:
mingw32-make: *** No rule to make target 'build/my_lib.o', needed by 'build'. Stop.
为何不能仅通过patsubst完成文件重命名?
附完整Makefile代码:
DEBUG = 1 INCLUDE_DIR = include SOURCE_DIR = src BUILD_DIR = build CXX_STANDARD = c++17 CXX_WARNINGS = -Wall -Wextra -Wpedantic CXX = g++ CXXFLAGS = $(CXX_WARNINGS) -std=$(CXX_STANDARD) CPPFLAGS = -I $(INCLUDE_DIR) LDFLAGS = ifeq ($(DEBUG), 1) CXXFLAGS += -g -O0 EXECUTABLE_NAME = mainDebug else CXXFLAGS += -O3 EXECUTABLE_NAME = mainRelease endif CXX_COMPILER_CALL = $(CXX) $(CXXFLAGS) $(CPPFLAGS) CXX_SOURCES = $(wildcard $(SOURCE_DIR)/*.cc) CXX_OBJECTS = $(patsubst $(SOURCE_DIR)/%.cc, $(BUILD_DIR)/%.o, $(CXX_SOURCES)) ############## ## TARGETS ## ############## create: @mkdir -p build build: $(CXX_OBJECTS) @echo $(CXX_OBJECTS) Hi $(CXX_COMPILER_CALL) $(CXX_OBJECTS) $(LDFLAGS) -o $(BUILD_DIR)/$(EXECUTABLE_NAME) execute: ./$(BUILD_DIR)/$(EXECUTABLE_NAME) clean: rm -f $(BUILD_DIR)/*.o rm -f $(BUILD_DIR)/$(EXECUTABLE_NAME) ############## ## PATTERNS ## ############## #$(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.cc # $(CXX_COMPILER_CALL) -c $< -o $@
核心原因解析
patsubst的本质是字符串处理工具patsubst只是Makefile提供的字符串替换函数,它的作用仅仅是把src/xxx.cc这类字符串替换成build/xxx.o,生成一个目标文件名的列表。它不会创建任何实际文件,也不会告诉Make如何生成这些文件。Make的依赖处理逻辑
当Make执行build目标时,会检查它的依赖$(CXX_OBJECTS)(比如build/my_lib.o)是否存在:- 如果文件不存在,Make会去寻找能生成该文件的规则——要么是你定义的显式规则/模式规则,要么是Make的内置规则。
- 注释掉自定义模式规则后,Make的内置规则只能处理和源文件同目录的
.o文件(比如src/my_lib.o),但你的目标文件在build目录下,内置规则无法匹配这种跨目录的生成需求,所以Make找不到生成build/my_lib.o的方法,就会抛出错误。
两者的角色完全不同
patsubst负责告诉Make最终需要哪些文件(依赖列表);- 模式规则负责告诉Make如何生成这些文件(编译逻辑)。
两者是协作关系,不能互相替代。
补充说明
如果不想写自定义模式规则,也可以通过显式规则逐个定义每个.o文件的生成方式,但显然模式规则更简洁高效,尤其当源文件数量较多时。
内容的提问来源于stack exchange,提问作者Rudransh Srivastava
相关产品推荐
相关产品推荐

