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

多源码树外置构建Makefile问题:跨目录源码目标文件路径不符预期

Makefile编译多目录源码到指定build目录问题解决

问题描述

我写了个简易Makefile,想把SRC_DIRS指定的多个目录下的.c文件编译成单个可执行文件。源码文件放在./src和../pmlin/src/master目录,要求中间文件输出到./build目录。

目前遇到的问题:./src下的文件能正确编译到./build目录,但../pmlin/src/master下的文件还是生成在原目录,没到预期的./build/pmlin/master路径。试了用pathsubst移除OBJS路径里的../,折腾几小时没解决,当前Makefile代码如下:

TARGET_EXEC = aslac-calibrator

BUILD_DIR = ./build
SRC_DIRS = ./src ../pmlin/src/master
SRCS := $(foreach dir, $(SRC_DIRS), $(wildcard $(dir)/*.c))
OBJS := $(SRCS:%=$(BUILD_DIR)/%.o)
DEPS := $(OBJS:.o=.d)

INC_DIRS := $(shell find $(SRC_DIRS) -type d) ../pmlin/src ../pmlin/src/devices
INC_FLAGS := $(addprefix -I,$(INC_DIRS))

CPPFLAGS ?= $(INC_FLAGS) -MMD -MP

$(TARGET_EXEC): $(OBJS)
    $(CC) $(OBJS) -o $@ $(LDFLAGS)

$(BUILD_DIR)/%.c.o: %.c
    $(MKDIR_P) $(dir $@)
    $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@

.PHONY: clean

clean:
    $(RM) -r $(BUILD_DIR)

-include $(DEPS)

MKDIR_P ?= mkdir -p

解决方案

核心问题是原规则里的../会被Make解析为上层目录,导致目标路径实际等价于原源码目录,需要先清理掉路径里的../,再映射到build目录。修改后的Makefile如下:

TARGET_EXEC = aslac-calibrator

BUILD_DIR = ./build
SRC_DIRS = ./src ../pmlin/src/master
# 遍历获取所有.c源码文件
SRCS := $(foreach dir, $(SRC_DIRS), $(wildcard $(dir)/*.c))
# 处理路径:先把源码路径拼到BUILD_DIR下,再移除开头的../,最后替换为.o后缀
OBJS := $(SRCS:%=$(BUILD_DIR)/%)
OBJS := $(OBJS:../%=%)
OBJS := $(OBJS:.c=.o)
DEPS := $(OBJS:.o=.d)

INC_DIRS := $(shell find $(SRC_DIRS) -type d) ../pmlin/src ../pmlin/src/devices
INC_FLAGS := $(addprefix -I,$(INC_DIRS))

CPPFLAGS ?= $(INC_FLAGS) -MMD -MP

$(TARGET_EXEC): $(OBJS)
	$(CC) $(OBJS) -o $@ $(LDFLAGS)

# 通用模式规则,匹配所有.c文件到对应build目录下的.o文件
$(BUILD_DIR)/%.o: %.c
	$(MKDIR_P) $(dir $@)
	$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@

.PHONY: clean

clean:
	$(RM) -r $(BUILD_DIR)

-include $(DEPS)

MKDIR_P ?= mkdir -p

关键修改说明

  1. 调整OBJS生成逻辑:
    原代码里$(SRCS:%=$(BUILD_DIR)/%.o)会把../pmlin/src/master/file.c变成./build/../pmlin/src/master/file.c.o,而./build/../等价于当前目录,所以文件还是生成在原路径附近。修改后先把源码路径拼到BUILD_DIR下,再用$(OBJS:../%=%)去掉开头的../,最后替换成.o,得到正确的./build/pmlin/src/master/file.o路径。
  2. 修改模式规则:
    把$(BUILD_DIR)/%.c.o: %.c改成$(BUILD_DIR)/%.o: %.c,因为现在OBJS的后缀直接是.o,不需要额外的.c.o,确保规则能正确匹配所有目标文件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 12:29:56