这不是编译问题,是链接器未找到符号定义;需检查定义来源、链接顺序及库是否正确加入target_link_libraries或gcc命令。

直接说结论:这不是编译问题,是链接器没找到符号定义,90%的情况靠检查“谁写了定义、谁该被链接、谁先谁后”就能解决。
undefined reference to 'xxx' 是链接器在喊你补零件
链接器不看头文件,也不管你有没有 #include,它只认两样东西:
- 所有
.o文件里声明但未定义的符号(比如调用了ceres::Problem::Problem()) - 所有你命令行里给它的库(
.a、.so)或目标文件中,是否真有这个符号的实现
常见错误现象:
- 编译单个
.cpp没报错,一链接就炸 - 错误里出现
ceres::、glog::、Eigen::这类前缀,说明是第三方库没链上 - 报错函数名带一堆
_Z开头的乱码?那是 C++ 符号修饰,用c++filt _Z...能还原成可读名
关键判断:
立即学习“C++免费学习笔记(深入)”;
- 如果错误里的符号是你自己写的(比如
add、MyClass::init),优先查源文件是否漏编译、定义是否拼错、命名空间是否漏写 - 如果是第三方库的符号,跳到下一条
CMake 项目里 ceres/glog/Eigen 报 undefined reference
CMake 不会自动帮你把依赖库的实现塞进链接命令,它只负责“找得到头文件”。find_package(Ceres REQUIRED) 成功 ≠ 你就能链接上 Ceres 的库。
必须显式做两件事:
- 在
target_link_libraries(your_target ...)里把Ceres::ceres(或ceres)列进去 - 确保
glog、gflags、Eigen3也进了target_link_libraries,顺序不能反(例如your_target依赖Ceres,Ceres依赖glog,那Ceres必须写在glog前面)
容易踩的坑:
- 用了
find_package(Ceres)却没在target_link_libraries中引用它导出的 target(比如写成target_link_libraries(app PRIVATE ceres)而不是Ceres::ceres) - Ceres 是静态编译的,但你的项目用了
-fvisibility=hidden,导致符号被隐藏(加set(CMAKE_CXX_VISIBILITY_PRESET default)临时绕过) -
pkg_check_modules找到了头文件路径,但没把LIBRARIES传给target_link_libraries
验证方法:
- 运行
make VERBOSE=1,看最终的g++ ... -o app main.o ...命令里有没有-lceres -lglog这类参数 - 用
nm -C libceres.a | grep "Problem::Problem"确认符号确实存在于库中
gcc/g++ 命令行链接时 missing .o or -lxxx
最朴素但最容易忽略的场景:你写了 main.cpp 调用 utils.cpp 里的函数,却只执行了:g++ main.cpp -o app
这等于只编译了 main.cpp,生成一个 app,但里面所有对 utils 函数的调用都只是“空壳”,链接器找不到实现。
正确做法分两种:
- 一起编译:
g++ main.cpp utils.cpp -o app - 分开编译再链接:
g++ -c main.cpp -o main.o && g++ -c utils.cpp -o utils.o && g++ main.o utils.o -o app
如果你依赖的是系统库(如数学库):
-
sqrt、sin这类要加-lm(注意m在最后) -
pthread_create要加-lpthread - 第三方库如
libjsoncpp.a,得写-ljsoncpp,且确保-L/path/to/jsoncpp/lib在命令行里
关键细节:
-
-lxxx的顺序很重要:依赖者靠前,被依赖者靠后。比如app→libfoo.a→libm.a,就得写成g++ app.o -lfoo -lm - 静态库
.a会被“按需抽取”,如果libfoo.a里某个函数又调用了libbar.a的符号,而你没把libbar.a放在后面,就会报 undefined reference - 动态库
.so不受此限,但运行时要确保LD_LIBRARY_PATH包含其路径,否则是./app: error while loading shared libraries,不是链接错误
真正卡住人的地方,往往不是“不知道要链接”,而是:
- 以为
find_package自动解决了所有事 - 看到
ceres/ceres.h被 include 了,就默认实现也在那儿 - 把
.h和.cpp放同一个目录,却忘了 CMakeLists.txt 没add_executable它 - 库文件是 x86_64 编译的,但你在 aarch64 上跑,
nm看着有符号,ld就是不认
别急着改代码,先盯住那一行报错里的符号名,顺藤摸瓜查它该在哪定义、你有没有把它对应的 .o 或 -lxxx 塞进链接命令——这事说清了,就只剩执行。


















