使用Clang编译C项目报错:arm64架构下符号未定义
问题描述
我正在开发一个C项目,此前一直使用GCC编译运行,现在在M2 Mac上尝试用Clang编译该项目。项目将所有头文件放在单独的include/目录下,项目结构如下:
bin/ // 二进制输出目录 docs/ include/ // 头文件存放目录 input/ makefile obj/ // 生成的.o目标文件目录 src/ // 源代码.c文件目录 tesh.sh
我的Makefile内容:
# Compiler Makefile # Author: John L. Carveth <jlcarveth@gmail.com> SRC_DIR := src# Source Code Location OBJ_DIR := obj# Object Output Location BIN_DIR := bin# Binary Output location DOC_DIR := docs# Document location OUT_DIR := out# Testing output location CC := gcc # Output file named ZeroCompiler TARGET := $(BIN_DIR)/ZeroCompiler # Include directory IDIR := include # All source files to compile SRC := $(wildcard $(SRC_DIR)/*.c) # Object files linked to the .c files OBJ := $(SRC:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o) # All Document files to be rendered (all files w/ .md extension) DOC := $(wildcard $(DOC_DIR)/*.md) # Compiler flags CFLAGS := -Wall -D DEBUG -g CPPFLAGS := -I$(IDIR) -MMD -MP LDFLAGS := -Llib LDLIBS := -lm # PHONY targets so they can still be executed .PHONY: all clean docs all : $(TARGET) $(TARGET): $(OBJ) | $(BIN_DIR) $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(OBJ_DIR) $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ $(BIN_DIR) $(OBJ_DIR): mkdir -p $@ clean: @$(RM) -rv $(TARGET) $(OBJ_DIR) $(BIN_DIR) $(DOC_DIR)/out $(OUT_DIR) docs: mkdir -p $(DOC_DIR)/out mdtodoc $(DOC) --dest "docs/out" --layout "page" --theme "github" --highlight-style "atom-one-light" test: ./test.sh -include $(OBJ:.o=.d)
使用GCC时该Makefile可正常生成目标文件、完成链接并产出可用二进制程序,但在Mac上执行make时出现以下错误:
Undefined symbols for architecture arm64: "_arithmeticExpression", referenced from: _forStatement in Parser.o [...]
其中arithmeticExpression是一个在include/目录下某头文件中声明了原型的函数。我对编译流程的理解存在不足,请问如何确保编译应用时正确链接include/目录?
问题分析与解决
首先明确:你遇到的链接错误(Undefined symbols)和头文件目录的识别无关——头文件找不到会在编译阶段报「未声明的标识符」类错误,而当前错误是链接阶段找不到函数的实现代码。下面是具体排查和解决步骤:
1. 确认函数实现文件是否被纳入编译
- 检查
arithmeticExpression函数的定义所在的.c文件是否在src/目录下:你的Makefile里用$(wildcard $(SRC_DIR)/*.c)只收集src/下的所有.c文件,如果该函数的实现文件在其他目录(比如错误地放在了include/下),就会被遗漏,导致链接时找不到符号。 - 临时添加Makefile目标验证源文件列表:在Makefile末尾加一行:
执行print-SRC: @echo $(SRC)make print-SRC,看看输出里有没有包含该函数的.c文件。如果没有,要么把文件移到src/,要么修改SRC变量的取值范围(比如SRC := $(wildcard $(SRC_DIR)/*.c $(OTHER_DIR)/*.c))。
2. 明确指定编译器为Clang
M2 Mac上默认的gcc其实是Clang的别名,直接在Makefile里把CC改成clang可以避免编译器混淆:
CC := clang
3. 清理旧文件后重新编译
旧的目标文件可能残留了GCC编译的内容,和Clang生成的文件不兼容,执行以下命令彻底清理后重新构建:
make clean && make
4. 验证头文件路径(可选)
虽然这不是当前错误的原因,但可以确认头文件路径配置正确:编译阶段没有报错,说明CPPFLAGS里的-I$(IDIR)已经正确让Clang找到了include/下的头文件,这部分无需修改。
内容的提问来源于stack exchange,提问作者JLCarveth
相关产品推荐
相关产品推荐

