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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 20:10:27