You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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 $@

核心原因解析

  1. patsubst的本质是字符串处理工具
    patsubst只是Makefile提供的字符串替换函数,它的作用仅仅是把src/xxx.cc这类字符串替换成build/xxx.o,生成一个目标文件名的列表。它不会创建任何实际文件,也不会告诉Make如何生成这些文件。

  2. Make的依赖处理逻辑
    当Make执行build目标时,会检查它的依赖$(CXX_OBJECTS)(比如build/my_lib.o)是否存在:

    • 如果文件不存在,Make会去寻找能生成该文件的规则——要么是你定义的显式规则/模式规则,要么是Make的内置规则。
    • 注释掉自定义模式规则后,Make的内置规则只能处理和源文件同目录的.o文件(比如src/my_lib.o),但你的目标文件在build目录下,内置规则无法匹配这种跨目录的生成需求,所以Make找不到生成build/my_lib.o的方法,就会抛出错误。
  3. 两者的角色完全不同

    • patsubst负责告诉Make最终需要哪些文件(依赖列表);
    • 模式规则负责告诉Make如何生成这些文件(编译逻辑)。
      两者是协作关系,不能互相替代。

补充说明

如果不想写自定义模式规则,也可以通过显式规则逐个定义每个.o文件的生成方式,但显然模式规则更简洁高效,尤其当源文件数量较多时。

内容的提问来源于stack exchange,提问作者Rudransh Srivastava

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 10:57:19