
1. 项目概述与方案设计1.1 为什么要专门写一篇Ceres安装教程在Ubuntu 20.04上部署ORB-SLAM3、VINS-Fusion、COLMAP这类视觉SLAM或三维重建项目时Ceres Solver基本是一个绕不开的依赖。很多同学第一次遇到它是因为编译ORB-SLAM3时终端突然报出一堆找不到ceres/ceres.h的错误然后开始漫无目的地搜教程。但实际上Ceres并不是一个“装上就能跑”的库它牵涉到Eigen版本、SuiteSparse、glog、gflags等一系列底层依赖而Ubuntu 20.04自带的软件源版本又比较老直接apt install libceres-dev装出来的版本经常和SLAM框架的接口对不上最后不得不手动卸载重来。我最初接触Ceres时也走过不少弯路最头疼的是项目明明编译过了运行时却报ceres::Problem相关符号找不到或者版本不匹配导致的模板编译错误。这类问题追根究底大多是安装方式不对、编译选项和项目不一致导致的。这篇内容就是把我自己在Ubuntu 20.04上反复实验、确认可行的完整流程整理出来覆盖依赖安装、源码编译、CMake集成、常见报错排查这几个环节目标是让你照着做一遍就能把Ceres稳定用起来。1.2 源码编译与apt安装怎么选关于Ceres的安装方式网上教程里无非是两条路一条是sudo apt install libceres-dev另一条是源码编译。我强烈建议你用源码编译理由很现实第一Ubuntu 20.04软件源里的Ceres版本停留在1.14.0这个版本太老了。ORB-SLAM3、VINS-Fusion等现代项目通常要求Ceres 2.0以上老版本接口差异明显编译时会出现各种奇怪的模板报错。第二apt装出来的Ceres依赖的是系统自带的Eigen 3.3.7这个Eigen版本也存在不少历史问题尤其在做BA优化时表现不佳很多SLAM项目会要求Eigen 3.4.0。源码编译看似步骤多但每一步都可控版本、编译选项、安装路径全在自己手里。而且Ceres的源码编译流程本身很成熟官方CMake脚本写得清楚真正需要手动处理的坑并不多。依赖装好之后整个编译过程通常五到十分钟就能完成性价比很高。1.3 版本选择与整体思路Ceres Solver目前主流的稳定版本是2.1.0和2.2.0。2.1.0发布时间较早被广泛测试和大多数SLAM项目兼容性很好。2.2.0版本更新修复了一些偶发问题但部分老项目还没有验证过兼容性。我个人推荐安装2.1.0这是一个“稳”字当头的选择。如果你后续要编译的项目明确要求2.2.0再切换也不迟。版本选择确定后整体思路按三步走安装Ceres编译需要的系统依赖库下载Ceres源码配置CMake编译选项并编译安装编写测试程序验证Ceres是否可用并确认项目CMakeLists.txt的正确写法。下面从依赖准备开始逐步展开。2. 编译前依赖准备2.1 核心依赖库逐个说明Ceres不是一座孤岛它需要一系列底层数学和线性代数库来支撑。在Ubuntu 20.04上我们需要先安装以下几类库。下面这个命令是我验证过可用的sudo apt update sudo apt install -y cmake libgoogle-glog-dev libgflags-dev libatlas-base-dev libeigen3-dev libsuitesparse-dev这里每个库都有自己的角色我来逐个说一下方便你理解为什么少了它们会出问题。Eigen3是Ceres最核心的依赖之一。Ceres内部大量的矩阵运算、求导计算都基于Eigen完成。Ubuntu 20.04默认的Eigen版本是3.3.7这个版本可以满足Ceres 2.1.0的编译要求不过如果你要跑ORB-SLAM3我建议顺手升级到3.4.0因为很多SLAM项目默认按3.4.0来写的低版本Eigen会带来编译期的模板报错。libgoogle-glog-dev和libgflags-dev是一对好搭档。glog是Google开源的日志库Ceres用它输出优化过程中的调试信息、错误提示gflags则是命令行参数解析库Ceres的部分测试程序会用到。如果你不装这两个库CMake配置时会提示找不到虽然可以通过-DMINIGLOGON选项让Ceres启用内置的迷你日志库但这样做会丢失很多调试信息排查问题时会很痛苦所以还是建议完整安装。libatlas-base-dev和libsuitesparse-dev用于提供BLAS/LAPACK和稀疏矩阵求解能力。Ceres在求解大规模非线性最小二乘问题时需要高效的线性代数求解器。SuiteSparse是其中最常用的后端包括了SPQR、CHOLMOD等求解器模块缺失会导致Ceres无法使用稀疏矩阵加速大场景BA优化性能明显下降。另外还有一个容易忽略的依赖liblapack-dev。虽然atlas-base包会顺带处理一部分但部分版本的Ceres在CMake检测LAPACK时会有遗漏建议一起装上sudo apt install -y liblapack-dev2.2 升级Eigen版本的正确姿势既然前面提到Eigen 3.4.0的好处这里就顺便说一下升级方法。但请注意Eigen的升级不推荐用apt源直接替换因为Ubuntu 20.04的软件源里最高只有3.3.7而且系统很多组件都依赖这个版本的Eigen盲目替换可能导致ROS等环境出问题。安全的做法是单独下载源码安装到独立的路径然后在你的项目CMakeLists.txt里通过指定EIGEN3_INCLUDE_DIR来优先使用新版本。具体操作如下wget https://gitlab.com/libeigen/eigen/-/archive/3.4.0/eigen-3.4.0.tar.gz tar -xzf eigen-3.4.0.tar.gz cd eigen-3.4.0 mkdir build cd build cmake .. sudo make install默认安装路径是/usr/local/include/eigen3不会覆盖系统的/usr/include/eigen3。之后在项目里使用新版本Eigen时在CMakeLists.txt中这样写set(EIGEN3_INCLUDE_DIR /usr/local/include/eigen3) include_directories(${EIGEN3_INCLUDE_DIR})这样就能在不影响系统环境的情况下让SLAM项目用到新版本Eigen。有一个细节需要提醒Ceres源码编译时也会检测Eigen版本如果你先升级了EigenCeres会自动用最新版本如果先编译Ceres后升级Eigen理论上Ceres是静态链接Eigen的影响不大但还是建议先把Eigen处理好再编译Ceres。3. 源码编译与安装实操3.1 下载源码与准备工作依赖库就绪后开始下载Ceres源码。建议直接克隆官方仓库并切换到2.1.0这个稳定taggit clone https://github.com/ceres-solver/ceres-solver.git cd ceres-solver git checkout 2.1.0这里有一个经验之谈不要直接使用master分支。master分支是开发版本代码更新频繁虽然功能更全但偶尔会有实验性改动可能在编译时遇到未知问题。切换到正式release tag至少保证这个版本是被社区广泛验证过的出现问题也更容易搜到解决方案。下载完成后建一个build目录进行编译。Ceres官方不推荐在源码根目录下直接编译因为会产生大量中间文件污染源码后续想切换版本或者clean都会麻烦。mkdir build cd build3.2 CMake配置参数详解编译前需要配置CMake选项。以下这组参数是我在多个项目里验证过覆盖了大多数使用场景cmake .. -DCMAKE_BUILD_TYPERelease -DBUILD_EXAMPLESOFF -DBUILD_TESTINGOFF这里每个参数都有讲究我展开聊聊。-DCMAKE_BUILD_TYPERelease设置编译模式为发布版。Release模式会开启编译优化Ceres在求解非线性优化时性能提升明显。很多教程不写这一项默认是空值即无优化SLAM项目跑起来明显卡顿。实测中Release模式比Debug模式下BA求解速度快两到三倍这个差距在大型场景中会被放大所以这一项务必加上。-DBUILD_EXAMPLESOFF表示不编译官方示例程序。Ceres自带的示例代码质量很高但对日常部署来说不是必需取消可以节省不少编译时间。-DBUILD_TESTINGOFF同理跳过测试用例的编译。如果想自定义安装路径可以加上-DCMAKE_INSTALL_PREFIX/your/desired/path默认是/usr/local。对绝大多数场景用默认路径就行后续项目链接时不用额外指定路径省心。如果遇到glog相关报错还可以考虑加上-DCMAKE_PREFIX_PATH/usr/local来帮助CMake定位库文件。这一项不是必需的但如果你之前手动编译过glog到/usr/local下加上它会更稳妥。配置完成后开始编译make -j$(nproc)$(nproc)会自动获取CPU核心数用满并行编译。如果机器内存较小比如8GB以下建议用make -j4避免编译过程中内存溢出。实际测试中Ceres全量编译在8核机器上大约需要三到六分钟视CPU性能而定耐心等就好。编译完成后安装sudo make install sudo ldconfigldconfig这一步很容易被忽略它的作用是刷新动态链接库缓存确保系统能找到新安装的.so文件。不执行的话后续编译项目时也许没问题但运行时可能报libceres.so.2: cannot open shared object file的错误。3.3 验证安装是否成功安装完成后用一个小例子验证Ceres是否能正常使用。先检查库文件是否安装到位ls /usr/local/lib/libceres* ls /usr/local/include/ceres/ceres.h正常情况下能看到libceres.a、libceres.so或libceres.so.2等文件和头文件目录。自定义安装路径后验证命令需要改为ls /your/path/lib/和ls /your/path/include/ceres/。然后写一个最简单的测试程序验证Ceres的核心功能——求解一个最小二乘问题。这里我们构建一个简单的一元二次函数拟合问题检验Ceres能否正确求解#include ceres/ceres.h #include iostream struct CostFunctor { template typename T bool operator()(const T* const x, T* residual) const { residual[0] T(10.0) - *x; return true; } }; int main(int argc, char** argv) { double x 0.5; ceres::Problem problem; ceres::CostFunction* cost_function new ceres::AutoDiffCostFunctionCostFunctor, 1, 1(new CostFunctor); problem.AddResidualBlock(cost_function, nullptr, x); ceres::Solver::Options options; options.linear_solver_type ceres::DENSE_QR; options.minimizer_progress_to_stdout true; ceres::Solver::Summary summary; ceres::Solve(options, problem, summary); std::cout summary.BriefReport() std::endl; std::cout x : x std::endl; return 0; }这段代码的含义很直白我们希望找到一个x使得10 - x的残差最小。显然最优解是x10。将代码保存为test_ceres.cpp接着编译g test_ceres.cpp -o test_ceres -I/usr/local/include -L/usr/local/lib -lceres -lglog如果Ceres正确安装运行时输出类似Ceres Solver Report: Iterations: 8, Initial cost: 9.025000e01, Final cost: 0.000000e00, Termination: CONVERGENCE x : 10能够看到cost降为0x收敛到10说明Ceres从编译到链接再到动态库加载都完全正常。3.4 在SLAM项目中的CMake配置写法Ceres安装好之后需要把它集成到自己的项目中。最规范的写法是在CMakeLists.txt中使用find_packagefind_package(Ceres REQUIRED) include_directories(${CERES_INCLUDE_DIRS}) target_link_libraries(your_project ${CERES_LIBRARIES})这样CMake会自动找到Ceres的头文件路径和库文件并将其链接到你的目标程序。需要注意如果你的Ceres是自定义安装路径还需要设置环境变量或CMake变量export Ceres_DIR/your/path/lib/cmake/Ceres或者在CMakeLists.txt中set(Ceres_DIR /your/path/lib/cmake/Ceres)非要自定义安装路径的话一定要记得先设置这个变量否则find_package(Ceres)会报找不到的错。这也是很多同学自定义路径后遇到的第一个坑。4. 常见问题与排查技巧实录4.1 编译报错速查表从网上各路反馈和我自己的踩坑经验来看Ceres安装过程中常见的报错集中在这几类。我把典型问题和解决方式整理成一个速查表供你对照排查。报错信息原因分析解决方案Could not find a package configuration file provided by Eigen3Eigen未安装或CMake找不到Eigen路径安装libeigen3-dev或指定-DEIGEN3_INCLUDE_DIRUnable to find Google Log ...glog/gflags未安装安装libgoogle-glog-dev libgflags-devCannot find SuiteSparse稀疏矩阵库缺失安装libsuitesparse-devceres/ceres.h: No such file or directory项目头文件搜索路径未包含Ceres检查include_directories(${CERES_INCLUDE_DIRS})cannot find -lceres链接器找不到Ceres库文件检查-L路径是否正确或是否执行ldconfiglibceres.so.2: cannot open shared object file动态链接库缓存未更新执行sudo ldconfig或设置LD_LIBRARY_PATHUnable to find LAPACK libraries缺少BLAS/LAPACK安装libatlas-base-dev liblapack-dev这里面的坑80%集中在“依赖没装全”和“链接路径不对”两类。尤其第一个和最后一个看起来只是小缺失实际上直接导致CMake配置失败极其影响心情。4.2 Eigen版本冲突的典型场景Eigen版本冲突问题主要出现在编译ORB-SLAM3这类大型项目时终端会刷出大段模板报错最典型的是error: no match for operator- in ...或者error: static assertion failed: YOU_MIXED_DIFFERENT_NUMERIC_TYPES_这类报错如果出现在Eigen相关代码中十有八九是Eigen版本和项目要求不匹配。ORB-SLAM3的官方文档明确要求Eigen 3.3以上但实际开发测试用的是3.4.0。Ubuntu 20.04系统自带3.3.7理论上可以编译但在某些优化场景下会触发编译器无法处理的边缘情况。解决办法就是我前面提到的源码编译Eigen 3.4.0然后在项目CMakeLists.txt中将EIGEN3_INCLUDE_DIR指到新版本路径。如果你不想修改CMakeLists.txt还有一个快速办法直接替换系统的Eigen头文件。操作前做好备份sudo mv /usr/include/eigen3 /usr/include/eigen3_backup sudo ln -s /usr/local/include/eigen3 /usr/include/eigen3这个方式风险较高如果后面其他软件依赖旧Eigen可能会有问题。但很多SLAM项目是独立环境这样处理效率最高实测可用。如果你之后要跑ROS相关的功能包这个方法不建议采用还是走局部指定更稳妥。4.3 卸载重装Ceres的正确姿势如果之前装的是apt版本或者编译安装过出问题的版本需要干净卸载后再重装。apt版本卸载sudo apt remove libceres-dev sudo apt autoremove源码编译安装的卸载比较复杂因为make install不会记录安装文件清单。一个实用的思路是重新进入之前的build目录执行make uninstall前提是当时CMake生成了uninstall目标。如果没有只能手动删除相关文件sudo rm -rf /usr/local/include/ceres sudo rm -f /usr/local/lib/libceres* sudo rm -f /usr/local/lib/cmake/Ceres sudo rm -f /usr/local/share/Ceres这里我提醒一句如果在多个路径下都装过Ceres用find / -name libceres*搜索所有残留文件逐一确认删除避免系统里存在多个版本的Ceres文件编译时被CMake随机命中造成线上问题和本地开发结果不一致的诡异情况。5. 一些进阶配置与编译选项解析5.1 开启OpenMP加速Ceres在求解大规模问题时可以通过OpenMP实现多线程加速。默认编译模式下OpenMP的支持取决于CMake是否能检测到。如果你希望显式开启在CMake配置时加一行cmake .. -DCMAKE_BUILD_TYPERelease -DBUILD_EXAMPLESOFF -DBUILD_TESTINGOFF -DOPENMPON开启OpenMP后Ceres的线性求解器会在多核CPU上并行计算大型BA问题的求解速度提升明显。实测中在8核机器上开启OpenMP后稠密增量求解DENSE_SCHUR大概快1.5到2倍。代价是编译产物体积稍大、内存占用提高但对桌面级SLAM项目来说完全值得。5.2 使用CUDA后端加速如果你有NVIDIA显卡并安装了CUDA工具链比如热搜词里出现的nvidia-driver-535说明很多人已经配好了显卡驱动可以在Ceres里启用CUDA后端cmake .. -DCMAKE_BUILD_TYPERelease -DBUILD_EXAMPLESOFF -DBUILD_TESTINGOFF -DCUDAON启用CUDA后Ceres可以使用GPU加速某些稠密矩阵运算。但需要说明的是Ceres的CUDA支持主要面向大规模稠密求解场景对SLAM中常见的稀疏BA问题帮助有限很多情况下甚至感觉不出明显加速。所以除非你明确知道自己需要GPU求解否则不用刻意开启这个选项。5.3 使用自定义安装路径时的CMake配置细节自定义安装路径在一些服务器环境比较常见因为没有sudo权限只能装到用户目录。这时候CMake配置和系统默认路径有些差异。cmake .. -DCMAKE_BUILD_TYPERelease -DCMAKE_INSTALL_PREFIX$HOME/ceres-install make -j$(nproc) make install之后在项目CMakeLists.txt里设置为set(Ceres_DIR $ENV{HOME}/ceres-install/lib/cmake/Ceres) find_package(Ceres REQUIRED) include_directories($ENV{HOME}/ceres-install/include) target_link_libraries(your_project ${CERES_LIBRARIES})同时记得设置动态库搜索路径export LD_LIBRARY_PATH$HOME/ceres-install/lib:$LD_LIBRARY_PATH这是无sudo权限环境下最完整的方案。很多服务器用户卡在这一步其实核心就两个CMake配置时指定Ceres_DIR运行时指定LD_LIBRARY_PATH。6. 我在实操中的一些体会Ceres的安装本身并不复杂真正消耗时间的往往是Eigen版本、依赖缺失、链接路径这些“周边问题”。我见过不少人卡在Could not find a package configuration file provided by Eigen3这一行报错上其实也就是一条apt install libeigen3-dev的事但如果不理解CMake查找规则就很容易到处乱试。理解每个库在Ceres里的角色比死记硬背安装命令有用得多。还有一点想特别说明不管你后续是编译ORB-SLAM3、VINS-Fusion还是自己的优化代码尽量保持“把Ceres当作项目的一部分来管理”这个意识而不是“装完就万事大吉”。Ceres版本、Eigen版本和项目代码三者之间存在隐形的兼容性链条任何一环断裂都会产生极难排查的模板报错。最简单的做法就是记录自己在用的版本组合换项目时先检查版本是否一致。按照上面的流程装好后其实你还能顺手做一件小事就是保留好Ceres源码目录和build目录不要删。后续如果想切换版本、查看官方示例或者用make uninstall清理这些目录都能派上用场。我把这视为源码编译安装“最后的保险”虽然平时用不上但真遇到问题时会给你省下大量的排查时间。