资讯动态

LIO-SAM 编译报错找不到 -lBoost::timer:根因与修复全解析

发布时间:2026/10/5 3:35:38 来源:尧图企业网站定制
LIO-SAM 这个库做激光惯性 SLAM 的应该都不陌生用因子图把激光雷达、IMU 和 GPS 先验压到一起做全局优化效果确实能打但编译环节也是出了名的磨人。这两天帮人排查一个报错卡在最后链接那一步终端里就一行/usr/bin/ld: 找不到 -lBoost::timer估计不少人第一次看到这个提示都懵了Boost::timer 到底是啥系统里明明装了 Boost怎么还找不到这个报错的迷惑性就在于它看起来像缺库实际却是构建系统把 CMake 的 target 名字当成了普通库名原封不动传给了链接器。这篇文章把这个错误的前因后果、排查路径和修复方法完整讲一遍正在编译 LIO-SAM、或者在任何 ROS/CMake 工程里遇到-l系列报错的朋友都可以直接对照着操作。1. 先搞清楚报错在说什么再动手改1.1 链接器只认 libxxx.so不认 Boost::timerC/C 的构建分四步预处理、编译、汇编、链接。你写的头文件、函数调用到链接这一步才会真正和外部库产生关系。编译器把源码变成一堆.o目标文件之后链接器也就是报错里这个/usr/bin/ld负责把这些.o和用到的库拼成最终的可执行文件或者动态库。这一步一旦出错整个构建就卡死前面编得再快也没用。链接器找库靠的是一套非常朴素的规则-l名字会去搜索路径下找lib名字.so或者lib名字.a。比如-lboost_timer找的就是libboost_timer.so。搜索路径包括你用-L参数指定的目录、环境变量LIBRARY_PATH以及系统默认目录Ubuntu 上通常是/usr/lib/x86_64-linux-gnu这类带架构后缀的目录。找不到就报找不到 -lxxx。现在回到报错本身。-lBoost::timer意味着链接器收到的参数是Boost::timer于是它去找libBoost::timer.so。注意细节大写B、中间有冒号。文件系统里根本不会存在这种名字的库所以必然报找不到。翻译成人话就是构建系统把一个本不该出现在链接命令里的字符串硬塞给了链接器。真正要查的不是系统缺库而是这个字符串是从哪儿冒出来的。1.2 Boost::timer 本来是 CMake 的 target 名Boost 的 timer 组件真实存在库文件叫libboost_timer.so但Boost::timer这种写法不是文件名而是 CMake 里导入目标imported target的名字。find_package(Boost COMPONENTS timer)执行成功之后CMake 会在内部生成一个名为Boost::timer的目标你在target_link_libraries里写它CMake 会把这个目标解析成实际的库文件路径再传给链接器。这是一个封装得很好的抽象你不需要关心库在哪个目录、叫什么名字。问题就出在如果find_package没有生成这个目标而你的target_link_libraries里又写了Boost::timerCMake 的默认处理方式是——不报错、不警告把这个字符串当成普通库名照样生成链接命令。于是链接器就收到了-lBoost::timer后面的事大家都知道了。这种设计坑就坑在太宽容本来是你写错了它不提醒你还把错误一路送到最后一步才炸。1.3 缺库和传错名别混为一谈很多教程一看到找不到 -lBoost::timer就让你apt install libboost-timer-dev确实有人装完就好了但这不代表问题根源就是缺库。我把两种情况放一起对比你对着自己的报错看一眼就知道属于哪种。报错形态真实原因典型场景找不到 -lboost_timer系统确实没有这个库文件没装 dev 包或库路径不对找不到 -lBoost::timerCMake 目标未定义字面量传给链接器CMakeLists 里 find_package 与链接写法不匹配配置阶段出现 Could not find the following Boost libraries: boost_timer组件缺失CMake 直接拒绝缺libboost-timer-dev编译过程直接被 Killed内存不足不是链接问题-j开太大GTSAM/PCL 模板实例化吃内存判断的方法很简单看库名。小写的是真库大概率是没装带大写B和双冒号的是 target优先查 CMakeLists。这个区分能帮你少走很多弯路也决定了后面的修复方向完全不同。2. LIO-SAM 的 Boost 链路坑通常埋在哪2.1 LIO-SAM 为什么和 Boost 绑在一起LIO-SAM 全称是 Tightly-coupled Lidar-Inertial Odometry via Smoothing and Mapping整套系统按功能拆成几个节点imageProjection做点云预处理和去畸变featureExtraction提取角点和平面点mapOptmization负责因子图优化和地图维护imuPreintegration做 IMU 预积分。节点之间靠 ROS 通信核心优化部分依赖 GTSAM点云处理依赖 PCL图像部分依赖 OpenCV 和 cv_bridge。任何一个依赖在 CMakeLists 里声明了编译期就绕不开。Boost 在这里面扮演的角色比较杂它是一个大型 C 库集合timer 组件主要用来做耗时统计。比如很多 fork 版本会在mapOptmization或点云处理模块里用boost::timer::cpu_timer去测各环节处理时间方便调优。虽然 LIO-SAM 核心功能不用 timer 也能转但既然 CMakeLists 里声明了这个依赖链接阶段就必须正确解析它。2.2 标准 CMakeLists 应该怎么写LIO-SAM 的 CMakeLists.txt 里和 Boost 相关的典型写法是这样find_package(Boost REQUIRED COMPONENTS timer) ... include_directories( include ${catkin_INCLUDE_DIRS} ${PCL_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} ${GTSAM_INCLUDE_DIRS} ) ... target_link_libraries(${PROJECT_NAME}_mapOptmization ${catkin_LIBRARIES} ${PCL_LIBRARIES} ${Boost_LIBRARIES} ${GTSAM_LIBRARIES} )这里有两个关键点。第一find_package(Boost REQUIRED COMPONENTS timer)里的COMPONENTS timer是必须的它除了检查库是否存在还会在 CMake 里生成Boost::timer这个目标。第二链接时用${Boost_LIBRARIES}是老式变量写法CMake 会把它展开成实际的库路径如果你更喜欢新式写法也可以改成一个Boost::timer目标但前提是前面的find_package确实执行成功。两种风格都能用不要混着写更不能在没执行find_package的情况下去链接一个 target 名。2.3 三种常见的人为制造错误根据我在各种交流群和论坛看到的求助帖这个错八成是下面三种情况之一。第一种find_package没写组件就直接用 target。比如有人把find_package(Boost REQUIRED)写在前面后面链接时写了Boost::timer。Boost 基础头文件都在这个find_package能过但因为没有指定COMPONENTS timerCMake 不会生成Boost::timer目标链接时自然就变成字面量传参了。第二种手动改链接库列表改出问题。有些人觉得${Boost_LIBRARIES}路径太长、看着不顺眼自作聪明改成target_link_libraries(... Boost::timer)。如果前面没写完整的find_package或者因某种原因执行失败这就是事故现场。第三种变量被覆盖。有些工程里会这样写set(Boost_LIBRARIES Boost::timer) target_link_libraries(my_node ${Boost_LIBRARIES})或者是某个第三方模块在父作用域里改了变量结果${Boost_LIBRARIES}展开出来就是Boost::timer链接器同样一脸懵。遇到这种问题不要只盯着target_link_libraries那一行往上看变量是在哪儿被赋值的。2.4 还有一种隐蔽来源依赖库传染出来的排查时还要留个心眼这个传错的字符串不一定来自你自己的 CMakeLists也可能是某个依赖库的 CMake config 文件里带出来的。比如 GTSAM 或某些自己编译的第三方库它们的xxxConfig.cmake里如果通过INTERFACE_LINK_LIBRARIES导出了Boost::timer你的工程在链接那个库的时候这个字符串就会跟着传进链接命令。如果那个库编译时依赖的 Boost 组件和你当前环境不一致就会出现这种莫名其妙的目标未定义。怎么判断来源看完整链接命令最靠谱。如果完整命令里只能看到-lBoost::timer而自己的 CMakeLists 里压根没写这个词那基本可以锁定是从依赖库的导出接口带过来的。处理方式很简单在你的工程里补上find_package(Boost REQUIRED COMPONENTS timer)让目标先定义出来后面链接时就能正确解析了。3. 实操流程从定位到修复3.1 第一步打开详细构建日志找到案发现场很多人遇到编译错误只看终端最后一屏就到处问人。正确做法是先拿详细日志。LIO-SAM 如果用 catkin_tools 构建命令是catkin build lio_sam -v如果用的 catkin_make则是catkin_make VERBOSE1。加了详细输出之后你会看到类似这样的完整链接命令[ 88%] Linking CXX executable /home/user/catkin_ws/devel/lib/lio_sam/lio_sam_mapOptmization /usr/bin/ld: 找不到 -lBoost::timer collect2: error: ld returned 1 exit status make[2]: *** [CMakeFiles/lio_sam_mapOptmization.dir/build.make:1235: ...] Error 1注意看Linking CXX executable这一行它标注了是哪个可执行文件链接失败对应的是哪个 ROS 节点。再结合你自己的 CMakeLists基本能定位到是哪个add_executable、哪一行target_link_libraries出了问题。这一步不需要任何技巧就是耐心看日志。3.2 第二步检查 Boost 组件是否装全虽然我认为这个报错的核心是 target 问题但也不排除你恰好没装全。先把底数摸清。Ubuntu 上查 Boost timer 库是否安装用这两条命令dpkg -l | grep libboost ls /usr/lib/x86_64-linux-gnu/libboost_timer*如果ls结果为空或者只有libboost_timer.so.1.71.0而没有不带版本号的开发符号链接那就确实缺 dev 包装上sudo apt update sudo apt install libboost-timer-dev不想一个一个装直接sudo apt install libboost-all-dev也行就是包比较大。装完后用ldconfig -p | grep boost_timer确认一下动态库能被系统找到。做完这一步至少排除了物理缺库这个变量后面的排查就可以专心放在 CMake 配置上。3.3 第三步修改 CMakeLists让 target 真正存在排除缺库之后重点回到 CMakeLists。核心修复思路只有一句话让链接器收到的库名是真实的库文件路径而不是Boost::timer这个字面量。有两种改法。改法一保持新式 target 风格补上组件声明。在文件里找到 Boost 相关的find_package确认写的是find_package(Boost REQUIRED COMPONENTS timer)然后在链接处用Boost::timertarget_link_libraries(${PROJECT_NAME}_mapOptmization ${catkin_LIBRARIES} ${PCL_LIBRARIES} Boost::timer ${GTSAM_LIBRARIES} )改法二整体退回老式变量用${Boost_LIBRARIES}代替所有手写的Boost::timertarget_link_libraries(${PROJECT_NAME}_mapOptmization ${catkin_LIBRARIES} ${PCL_LIBRARIES} ${Boost_LIBRARIES} ${GTSAM_LIBRARIES} )我个人更推荐第一种target 风格是 CMake 官方建议的方向能自动处理传递依赖和路径细节。无论选哪种改完都记得全局搜一下 CMakeLists 里还有没有::写法残留别改了一半。另外提醒一句如果报错来自某个依赖库的导出接口你不需要去改那个库在自己的 CMakeLists 里补上find_package(Boost REQUIRED COMPONENTS timer)就行。3.4 第四步清理缓存完整重编译CMake 是有缓存的。只改 CMakeLists 不清理有时候不会重新触发配置或者配置了但链接命令没更新导致你以为改了没用。建议直接清掉构建产物# catkin_tools catkin clean -y catkin build lio_sam -v # catkin_make rm -rf build devel catkin_make -j4注意-j别开太大这项目吃内存-j4或者把$(nproc)减半都行。编译通过后再用ldd看一眼可执行文件确认它最终链接的是/usr/lib/x86_64-linux-gnu/libboost_timer.so这个真实路径ldd devel/lib/lio_sam/lio_sam_mapOptmization | grep boost到这一步报错就算彻底解决。整个流程先看日志、再查依赖、再改配置、最后验证每一步都有明确目的不会瞎折腾。4. 顺手把 CMake 的 :: 规则彻底搞明白4.1 target_link_libraries 到底怎么解析参数这个报错之所以反复出现是因为很多人没搞懂target_link_libraries的参数解析规则。其实逻辑很简单CMake 拿到你写的每一项会分三种情况处理。第一看这个字符串是不是一个已存在的 target。什么叫已存在就是你在当前作用域里通过add_library、add_executable创建的目标或者通过find_package导入的目标。如果是CMake 走 target 语义解析出它的实际文件路径和附带的使用要求。第二如果这个字符串以-l开头CMake 会原样把它当作链接参数传下去不做任何解析。第三如果这个字符串既不是 target、也不以-l开头CMake 就把它当成普通库名在前面补一个-l再传给链接器。而带::的字符串恰好卡在这个分支——它不是合法 target又不是-l开头于是变成-lBoost::timer。所以问题的本质从来不是 Boost 没有 timer而是你的 CMake 作用域里没有Boost::timer这个 target。一切围绕这个 target 到底存不存在来排查思路就会非常清晰。别被报错里的找不到带偏它不是找不到库是找不到目标。4.2 Boost 的目标命名体系和老式变量对照Boost 的 CMake 导入目标都是Boost::开头后面跟组件名比如Boost::headers、Boost::timer、Boost::chrono、Boost::filesystem。和它们对标的还有一套老式变量整理成表看得更清楚新式 target老式变量对应真实库Boost::headersBoost_INCLUDE_DIRS头文件目录无库Boost::timerBoost_TIMER_LIBRARY也含在Boost_LIBRARIESlibboost_timer.soBoost::chronoBoost_CHRONO_LIBRARY也含在Boost_LIBRARIESlibboost_chrono.soBoost::filesystemBoost_FILESYSTEM_LIBRARY也含在Boost_LIBRARIESlibboost_filesystem.so这里要注意大小写。CMake 的 target 名区分大小写Boost::timer是官方定义的名字如果你写成boost::timer同样会变成-lboost::timer的字面量。别小看这个细节我见过有人排查了半天最后发现是手滑把大写B写成了小写。这种错误编译器不会提醒链接器只会莫名其妙地报找不到。4.3 时序为什么 timer 会牵连 chrono 和 system还有一个值得了解的知识点Boost 的 timer 组件不是孤立的。libboost_timer.so内部依赖libboost_chrono.so和libboost_system.so你可以用ldd验证ldd /usr/lib/x86_64-linux-gnu/libboost_timer.so这也是为什么libboost-timer-dev安装时会自动拉上 chrono、system 等 dev 包。如果你遇到的是链接时提示-lboost_timer或-lboost_chrono找不到大概率是这几个依赖组件没装全直接装libboost-all-dev最省心。另外如果将来想切静态链接可以在find_package之前设置set(Boost_USE_STATIC_LIBS ON)和set(Boost_USE_MULTITHREADED ON)。这两个开关会影响 CMake 寻找libboost_timer.a还是libboost_timer.so。LIO-SAM 这种 ROS 工程一般不需要折腾静态库了解有这回事就行真遇到再查官方文档。5. 高频问题速查与避坑清单5.1 ld 找不到 -lxxx 的通用排查表这类-l报错并不只是 Boost 的专利任何 C 工程都可能遇到Qt/QML 工程、纯 CMake 项目也不例外。排查思路是通用的先看链接命令里出现的库名是真实库名还是target 名。我把常见情况整理成表。报错关键词大概率原因处理-lboost_timer小写缺libboost_timer.soapt install libboost-timer-dev-lBoost::timer含冒号CMake target 未定义检查find_package(Boost COMPONENTS timer)和链接写法-lboost_chrono/-lboost_system缺配套 Boost 组件装libboost-chrono-dev等或用libboost-all-dev-lfoo任意其他库缺库或-L路径不对用dpkg -S或apt-file查库属于哪个包再安装链接命令里出现奇怪的::某个依赖库导出了未定义 target在工程里补对应find_package或清理依赖这套表放之四海皆准。Qt/QML 那边报出/usr/bin/ld: 找不到 -lxxx时处理逻辑完全一样先搞清楚这个xxx是文件名还是 target 名然后决定是装包还是改工程配置。5.2 LIO-SAM 编译期的其他高频坑既然聊到 LIO-SAM 编译顺手把另外几个高频问题也列一下省得你修完这个又撞上下一个。GTSAM 版本不兼容是最常见的LIO-SAM 官方推荐特定版本的 GTSAM如果你从源码编译的是最新 GTSAM可能在链接时出现一些和 Boost 无关的undefined reference报错位置非常零散。建议严格按照官方 README 的版本依赖来装别手滑装了个太新的。OpenCV 和 cv_bridge 的冲突在 Noetic 上也很典型。Ubuntu 20.04 默认 OpenCV 4ROS Noetic 的 cv_bridge 默认也是针对 OpenCV 4 编译的但如果你以前手动装过别的 OpenCV 版本或者系统里有多个 OpenCV 共存就会出现两个版本的头文件和库文件混链接报错千奇百怪。处理方式是检查/usr/local下有没有自定义安装的 OpenCV必要时把它暂时移走。PCL 版本不一致也是老问题。LIO-SAM CMakeLists 里写的是find_package(PCL 1.7 REQUIRED)在 Noetic 上实际装的是 PCL 1.10这个版本号只是最低要求通常能过但如果你在 conda 或者其他环境里也装了 PCL就可能头文件混乱。编译前用pcl-config --version确认当前默认 PCL 是谁。还有一个偏物理的坑编译内存不够。LIO-SAM 编译时 GTSAM、PCL 相关的模板实例化非常吃内存-j8经常被 OOM 干掉表现为编译进程被Killed或者直接卡死。建议-j4确实不行就-j2多等几分钟总比反复被杀死强。5.3 几个保命经验都是踩坑踩出来的最后分享几条亲身实践下来的经验不是文档里会写的。第一遇到-l找不到永远先开 verbose 看完整链接命令再决定是修库还是修 CMakeLists。终端最后那几行只是表象完整命令才能暴露Boost::timer是从哪一行、哪一个变量展开出来的。这一步能省你至少半小时。第二改完 CMakeLists 千万别忘了清缓存。CMake 的缓存机制经常让人误判修复无效catkin clean或者直接删build/ devel/然后从头编译。很多人改了没效果其实就是因为少了这一步。第三不要用创建软链接的方式去骗过链接器。网上确实有人给出这种操作sudo ln -s libboost_timer.so libBoost::timer.so。这种办法能让当前编译通过但完全绕过了问题本身而且含冒号的符号链接会污染你的系统以后别的工程会踩更深的坑。链接器报错是好事它在提醒你工程配置有毛病把配置板正才是正道。第四装 Boost 组件用系统包管理器别去网上手动下载源码包自己编。系统包管理器能保证多个 Boost 组件的版本一致手动编译很容易搞出版本错配到时候libboost_timer和libboost_filesystem版本对不上链接阶段又是一堆莫名其妙的 undefined reference。说实话这种链接错误在 SLAM 这个圈子里太常见了几乎每周都有人在群里问。但它的排查逻辑其实非常固定链接命令里的库名长什么样决定了问题的方向。把这个思路内化成习惯以后再遇到/usr/bin/ld: 找不到 -lxxx你大概扫一眼报错就知道该往哪个方向修了。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑