GNU Make报src/main.c:*** missing separator. Stop错误排查
问题根因
你的判断完全正确,报错和C代码无关,是Makefile的变量替换逻辑错误,导致make把C源码文件当成Makefile配置解析了:
- 你写的OBJ路径替换规则
$(SRC:$(SRCDIRS)/%.$(SRCEXT)=$(BUILDDIR)/%.o)存在致命问题:$(SRCDIRS)是空格分隔的两个目录路径,直接拼到匹配模式里会生成带空格的无效匹配串,完全匹配不到SRC里的任何源码路径,因此替换完全不生效,OBJ变量的值直接等于SRC的值,也就是两个.c源码文件路径。 - 后续
DEP := $(OBJ:.o=.d)的作用是把OBJ路径里的.o后缀替换为.d,但此时OBJ里全是.c后缀的路径,没有任何.o字符串,因此DEP变量的值也直接等于SRC,还是两个.c源码文件路径。 - 末尾的
-include $(DEP)本来是要引入gcc生成的.d依赖文件,结果实际变成了引入src/main.c和io.c两个C源码文件。make会把include指定的所有文件都当做Makefile语法解析,解析到main.c里的C代码时,自然会因为不符合Makefile的分隔符规则抛出missing separator错误,报错行号对应main.c里的代码行。
其他附带的配置错误
除了触发报错的核心问题,你的Makefile还有几个会导致后续构建异常的问题:
all目标错误依赖了clean:每次构建完成链接后就会自动执行clean删除整个build目录,不仅每次都要全量编译,还会把生成的.d依赖文件直接删掉。- 编译规则写法错误:
$(OBJ): $(SRC)是普通多目标规则,会让所有目标文件都依赖全部源码文件,且命令里的$<只会取第一个依赖文件(永远是main.c),就算路径正确也会把main.c重复编译为所有目标文件。 find命令的匹配模式没加引号:-name *.$(SRCEXT)会被shell提前展开通配符,当当前目录下存在.c文件时会导致find参数异常。- 多源码目录的路径处理逻辑不成立:原替换逻辑只能支持单个源码根目录,无法适配你两个独立源码目录的场景。
修复后的完整Makefile
# Compiler and linker CC := gcc # Target binary TARGET := the-program # File extensions SRCEXT := c # Directories TARGETDIR := bin BUILDDIR := build SRCDIRS := src /home/myusername/otherfolder/src INCDIRS := inc /home/myusername/otherfolder/inc # gcc options CCFLAGS := -Wall -Wextra -O3 #--------------------------------------------------------------------------------- #DO NOT EDIT BELOW THIS LINE #--------------------------------------------------------------------------------- vpath %.$(SRCEXT) $(SRCDIRS) vpath %.h $(INCDIRS) CCFLAGS += $(addprefix -I,$(INCDIRS)) -MMD -MP # 修正find命令匹配串引号问题 SRC := $(shell find $(SRCDIRS) -name "*.$(SRCEXT)") # 修正多源目录下目标文件路径生成逻辑 OBJ := $(patsubst %.$(SRCEXT),$(BUILDDIR)/%.o,$(notdir $(SRC))) DEP := $(OBJ:.o=.d) TARGET := $(TARGETDIR)/$(TARGET) # RULE: Default make # 移除all目标对clean的错误依赖 all: makedirs $(TARGET) # RULE: Remake remake: fullclean all # RULE: Clean clean: rm -rf $(BUILDDIR) # RULE: Full clean (objects and binaries) fullclean: clean rm -rf $(TARGETDIR) # RULE: Make dirs makedirs: mkdir -p $(BUILDDIR) mkdir -p $(TARGETDIR) # RULE: Link $(TARGET): $(OBJ) $(CC) $(OBJ) -o $@ # RULE: Compile # 使用静态模式规则配合vpath完成多目录源文件编译 $(BUILDDIR)/%.o: %.$(SRCEXT) $(CC) $(CCFLAGS) -c $< -o $@ # RULE: Non-file targets .PHONY: all remake clean fullclean makedirs # include dependencies -include $(DEP)
注意:上述修复默认两个源码目录下不存在同名
.c文件,如果存在同名文件会出现目标文件覆盖问题,需要调整目录结构或给目标文件加目录前缀区分。
内容的提问来源于stack exchange,提问作者Oh Fiveight
相关产品推荐
相关产品推荐

