
如果你面前正摆着这么一屏红色报错CMake Error at /opt/ros/noetic/share/catkin/cmake/empy.cmake:30 (message): Unable to find either executable empy or Python module em或者这样一句Could NOT find PythonInterp: Found unsuitable version 3.9.12, but required is at least 2.7不用怀疑你大概率不是功能包写错了而是你的编译环境里同时混进了两个Python一个系统自带的一个Anaconda带来的。这种在Anaconda环境下跑catkin_make引发的Python路径冲突和empy模块缺失几乎是我见过劝退ROS新手最多的坑之一。这篇文章不改任何代码只讲怎么让catkin_make安安静静地把包编译完。我会先带你看清报错到底在说什么再拆解几个核心病灶然后给三套从简单到彻底的解法最后附一份排查速查表。适合刚装好Anaconda和ROS、正被编译报错卡住的朋友也适合那些想彻底搞懂“为什么别人能编译我就不行”的人。1. 问题全貌这串报错到底在说什么1.1 报错现场最典型的三种报错我帮人排查过不少ROS环境问题这类Anaconda引发的编译失败报错形式上五花八门但归根结底就三种。第一种是empy相关报错。catkin在生成消息、服务或者某些动态配置头文件时会调用一个Python模板引擎叫empy模块名是em。如果当前Python环境里找不到它就会抛出上面那种Unable to find either executable empy or Python module em。很多人看到这个第一反应是“那我装一个empy不就行了”结果装了再编译还是报同样错误。第二种是Python版本检测失败。catkin_make基于CMake它在配置阶段会通过find_package(PythonInterp)去找Python解释器。如果系统默认要Python 2.7比如旧版ROS Kinetic、Melodic而Anaconda环境里是Python 3.8/3.9CMake就会直接拒绝“Found unsuitable version 3.9.12, but required is at least 2.7”。这时候无论你怎么重装empy都白搭因为CMake已经彻底锁定错了解释器。第三种比较隐蔽是链接阶段或者运行阶段的动态库冲突。编译到一半链接器报/usr/bin/ld: cannot find -lboost_python或者编译通过了但一运行节点就Segmentation fault。这个经常被忽视但根源还是Anaconda把自己那一套动态库塞进了系统搜索路径。这三种报错单独看都像是软件包缺失凑在一起看其实是同一个故事你的编译系统拿到了一个不属于它的Python环境。1.2 为什么Anaconda和ROS容易闹矛盾先说结论ROS尤其是catkin这类构建体系极其依赖系统自带的Python环境而Anaconda的设计理念是“把整个Python生态都圈到自己地盘里”。这两个东西放在一起天然就打架。Anaconda激活环境后做的事情说白了就是改环境变量。它会把自己的bin目录插到PATH的最前面把lib目录插到LD_LIBRARY_PATH里有时还会往PYTHONPATH里塞东西。这些操作对跑深度学习、数据处理是好事但对ROS来说是灾难。打个比方catkin_make像一个在大楼里找人的前台。它通过门禁系统查“谁是python”系统只有一个门禁的时候它找到系统Python大家相安无事。Anaconda来了之后不但改了门禁顺序还塞了一堆“自己人”排在队伍前面于是前台每次都拉到conda的Python。conda的Python虽然也能干活但它对ROS的消息生成、模板渲染、动态库链接都有自己的脾气两边一较劲编译就炸了。更深层的原因是ROS的许多工具链包括rosbash、roslaunch、catkin脚本是用系统Python启动的而catkin_make在编译功能包时会选择PATH里的Python。两者不一致轻则功能残缺重则直接编译失败。所以Anaconda环境下跑catkin_make你真正要解决的不是“缺哪个包”而是“让整个编译链路的Python统一起来”。2. 核心病灶拆解Python路径冲突与empy缺失2.1 Python路径冲突CMake找错了Python这是最核心的病灶。catkin_make本身不是一个编译器它是CMake的封装脚本。CMake在配置项目时会按顺序做这么几件事查Python可执行文件、查Python头文件目录、查Python库文件、在生成代码时调用Python执行模板渲染。问题就出在“查Python可执行文件”这一步。CMake的find_package(PythonInterp)会从PATH环境变量里找python、python3这类命令。当conda环境处于激活状态时PATH的第一项是/home/你的用户名/anaconda3/binCMake找到了/home/你的用户名/anaconda3/bin/python于是所有后续的Python相关操作全部绑定到这个解释器。你可能觉得“那也还好吧conda的Python也是Python啊”。可问题在于ROS自带的那堆脚本和库是链接到系统Python的。比如/usr/lib/python3/dist-packages/catkin_pkg系统Python能直接importconda的Python却不一定能识别这个路径因为conda会把site-packages指向自己的lib/python3.x/site-packages。结果就是catkin需要的Python模块找不着或者找着了但版本对不上编译自然失败。还有一个很冷门的坑我在实际项目里踩过。conda环境的Python在启动时会在stderr输出一行诊断信息类似Warning: this Python interpreter is in a conda environment。Cmake在探测Python版本时会把它的标准输出拿去做版本判断有时候甚至会把stderr的内容也混进去导致解析出乱七八糟的版本号。这个问题非常隐蔽光看报错根本想不到Python没找错只是“信息被污染了”。2.2 empy模块缺失只是表象根子在环境empyEmPy是Python社区一个非常老的模板引擎库模块名是em。它和Jinja2这类现代化模板库相比功能简单很多但ROS这么多年一直用它来生成消息、服务、动作相关的头文件也用来渲染一些CMake脚本和启动文件。简单理解你可以把它当成一个“用Python脚本往文本模板里填参数”的工具。当catkin_make执行到消息生成阶段它会把em当作Python模块去导入。如果当前Python环境里没装empy报错就是“No module named em”。注意这里的关键是“当前Python环境”——catkin_make用的是CMake锁定的那个Python不是你终端里默认的那个Python。我见过一个很有意思的场景一位朋友在conda里执行python -c import em发现确实没有这个模块然后他退出conda在系统环境下执行同样的命令能正常导入。于是他以为只要在conda里装一个empy就行。结果装了之后重新编译还是报错。为什么因为CMake虽然找到了conda的Python但catkin在做generate_messages时调用的是它自己缓存的PYTHON_EXECUTABLE如果你的bashrc里还遗留了PYTHONPATH指向系统Python的库路径那conda的Python在导入em时会优先去系统路径里找找到的又是一个旧版本或者不兼容的文件照样失败。说到底empy缺失是“果”不是“因”。真正的因是Python解释器已经被搞乱了导致依赖模块的查找路径全程跟着乱。只补empy等于头痛医头下次还会遇到别的模块缺失。2.3 隐藏的第三个坑动态库里的冲突Python路径冲突是明面上的问题还有一类问题是暗处的Anaconda自带的动态库覆盖了系统的。Anaconda为了自洽把一大堆so文件放进了自己的lib目录激活环境后这个目录会出现在LD_LIBRARY_PATH里。比较典型的是libstdc.so.6。ROS以及很多功能包在编译时会链接系统路径下的libstdc.so.6运行时会加载LD_LIBRARY_PATH里靠前的那个libstdc.so.6。如果conda的版本和系统版本不一致轻则警告重则直接报GLIBCXX_3.4.xx not found。这个报错通常出现在你编译好不容易通过、正要运行时很容易让人误以为“功能包代码有bug”。这类动态库冲突还有一个变种是Boost库。ROS功能包经常用到Boost.Python而Boost.Python和Python版本是强绑定的。你在编译时如果让CMake找到了conda的Python再去链接系统仓库里的libboost_python两个Python版本一碰撞就会报一堆诡异的重定义、符号找不到的问题。所以动态库冲突往往和Python路径冲突是连锁反应解决的时候不能只盯一个。3. 实操解决从简单到彻底的三种方案3.1 方案一编译时临时退出conda环境这是最简单粗暴、也最不容易出错的方法。如果你只是在做ROS功能包开发并不强依赖conda里的第三方库那就别在conda环境里编译让catkin_make老老实实使用系统Python。操作步骤conda deactivate如果你之前设置了conda activate base开机自启还需要保证当前终端确实已经退出了conda。验证一下which python正常情况下应该输出/usr/bin/python或者/usr/bin/python3如果输出的是/home/你的用户名/anaconda3/bin/python说明conda环境还占着PATH。然后清理上次编译产生的缓存。这一步很多人会忽略结果明明已经退出了condaCMake还缓存着旧的Python路径照样报错。稳妥的做法cd ~/catkin_ws rm -rf build devel catkin_makebuild目录里存的是CMake的缓存和中间文件devel目录里是编译产物和setup脚本。删掉它们catkin_make会重新运行完整配置此时CMake重新查找Python找到的就是系统Python了。这个方法的好处是零成本但缺点也有一旦你需要用conda里的包比如numpy、pytorch、cv2编译就会受影响。所以它适合“平时不用conda反正编译完再切回去”的人。3.2 方案二给conda环境补齐ROS所需依赖如果你就是要在conda环境里编译比如你的功能包强依赖cv2或者某个深度学习框架那就需要把ROS编译所需的Python依赖全部装进conda环境让它在“自己家里”也能自洽。我建议的清单是这样的conda install -c conda-forge empy catkin_pkg pyyaml defusedxml rospkg也可以用pippip install empy catkin_pkg pyyaml defusedxml rospkg装完之后先验证一下这些模块能不能被当前环境的Python正常导入python -c import em; import catkin_pkg; import rospkg; import yaml; print(ok)如果输出ok说明基础依赖齐了。接着清理缓存重新编译cd ~/catkin_ws rm -rf build devel catkin_make这里有个实际经验要分享empy在PyPI上更新比较慢新一点儿的Python版本尤其3.11以上直接pip install empy有时会安装失败或者装上后import报兼容性错误。遇到这种情况优先用conda-forge渠道安装conda会帮你编译好适配当前Python的版本。还需要提醒一点这个方法即使成功了也只是绕过了empy缺失的报错。如果你的ROS版本是Melodic默认Python 2.7而conda环境是Python 3.8CMake在版本检测阶段就会挂掉根本走不到empy那一步。这种情况就别硬在conda里配了老老实实回系统环境编译更靠谱。3.3 方案三从源头隔离让Anaconda不干扰ROS这是我个人最推荐的长期方案。思路很简单让Anaconda和ROS各用各的终端互不干扰。核心就一步让conda不要在终端启动时就自动激活base环境。Anaconda安装完成后.bashrc里会被写入一段conda初始化代码默认情况下新终端一打开就进入base环境这会污染所有后续命令的环境变量。把它关掉conda config --set auto_activate_base false执行后新打开的终端默认不再激活base环境。此时which python应该显示系统Python。需要用到conda的时候手动执行conda activate base或者进入你自己创建的其他环境。这样ROS开发和conda使用就在物理上分开了。另外我还建议检查一下.bashrc里有没有硬编码的PYTHONPATH和LD_LIBRARY_PATH。有些教程会让你把Anaconda的路径写到这两个变量里这种操作在ROS环境里是灾难。如果发现了直接注释掉。对于必须同时用ROS和conda做开发的情况我一般写一个编译用的环境清理脚本放在~/catkin_ws目录下#!/bin/bash # build.sh使用系统环境编译避免conda干扰 export PATH/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin unset PYTHONPATH unset LD_LIBRARY_PATH cd ~/catkin_ws catkin_make $每次编译前执行source build.sh或者直接bash build.sh让编译在一个干净的PATH下进行。这个方法结合auto_activate_base false基本能根治Anaconda环境下catkin_make的所有诡异报错。3.4 编译成功后如何验证当你跑完catkin_make不要只看最后有没有打印Build finished最好再做几个验证。首先确认devel目录下生成了setup脚本ls ~/catkin_ws/devel/setup.bash然后source它source ~/catkin_ws/devel/setup.bash再检查环境变量echo $ROS_PACKAGE_PATH如果能看到你的工作空间路径说明catkin的环境加载成功了。最后用rospack find看一下自己的功能包能不能被找到rospack find 你的包名如果你的包里有消息定义还可以尝试编译完成后跑一个简单的Python节点确认import消息类型不报错。这一步能验证Python绑定是否真的正常而不只是“编译过”。4. 常见问题与排查技巧实录4.1 报错速查表我把实际遇到的高频报错整理成一张表方便你快速对照。报错信息可能原因解决方式Unable to find either executable empy or Python module emconda环境缺empy或CMake锁定到conda Python退出conda编译或给conda安装empyCould NOT find PythonInterp: Found unsuitable version 3.x.yCMake找到conda Python但版本不符合ROS要求指定系统Python或退出conda再编译No module named rospkgconda环境缺少rospkg安装rospkg或退出conda/usr/bin/ld: cannot find -lboost_pythonBoost.Python链接的Python版本不匹配统一编译用的Python版本清理缓存重编GLIBCXX_3.4.x not foundconda的libstdc覆盖系统库运行前unset LD_LIBRARY_PATH避免加载conda动态库Segmentation fault (core dumped)运行节点时加载了不兼容的动态库用ldd检查可执行文件依赖确认没有conda路径CMake Error: The current CMake version is lower than requiredconda环境自带CMake版本过老用/usr/bin/cmake或升级conda里的cmake这张表里面最关键的是第一行和第五行。第一行是绝大多数人遇到的第五行是那种“编译成功但一跑就崩”的元凶。如果你碰到的是表格里没有的报错不要慌按下一节的排查顺序一步步来。4.2 排查优先级环境、依赖、库路径遇到catkin_make报错我建议按下面这个顺序排查而不是一上来就重装ROS、重装Anaconda。第一步看Python环境。执行which python python --version如果which python指向/home/xxx/anaconda3/bin/python那环境已经确认被conda接管了不用再看别的。第二步看CMake缓存。在build目录下执行grep -r PYTHON_EXECUTABLE CMakeCache.txt这一步非常有用它能直接告诉你CMake锁定的Python解释器到底是谁。如果你看到的是conda路径那就证明路径冲突已经到了源头。第三步看依赖。执行python -c import em这一步能帮你判断当前环境是否缺empy。如果导入失败就可以在解决路径冲突后再针对性安装依赖。第四步看动态库。执行echo $LD_LIBRARY_PATH如果有类似/home/xxx/anaconda3/lib的路径就需要警惕动态库冲突。你还可以用ldd查看具体二进制文件的依赖ldd devel/lib/你的节点名 | grep anaconda如果在输出里看到anaconda的路径基本可以断定运行问题出在动态库覆盖上。4.3 几个经验心得与避坑建议这套问题我前前后后遇到过很多次自己电脑和帮同事弄的都算上总结出几条很实在的经验。第一条安装Anaconda后第一件事就是执行conda config --set auto_activate_base false。很多教程只教你一路点击安装没人告诉你装完之后终端默认就进了base。这个默认行为对ROS开发是巨大的坑关掉它能避免八成以上的环境问题。第二条不要试图让ROS和Anaconda在同一个编译进程里“和平共处”。ROS的构建体系对系统Python的依赖是写死在脚本里的你可以在conda里补齐各种包强行编译但后续维护成本很高。时间一长你就会发现各种找不到模块、链接失败的问题像打地鼠一样此起彼伏。更好的做法是把职责分开ROS专注机器人控制conda专注数据科学和模型推理两者用不同终端隔离。第三条清理缓存比重装更有效。很多人遇到编译错误第一反应是百度搜索“卸载Anaconda”或者“卸载ROS重装”实际上大部分Anaconda导致的catkin_make问题只需要退出conda环境、删掉build和devel目录再重编就能解决。原因是CMake的缓存文件会记住第一次配置时的Python路径环境变了它不会自动更新。这一点在排查时优先尝试成本最低。第四条如果系统Python已经被折腾得不像样可以考虑用apt重新安装Python核心包。比如sudo apt install --reinstall python3 python3-dev这个命令不会影响你的功能包代码但能把系统Python的环境恢复到相对干净的状态。它能解决一部分由于系统Python库被误删或者被覆盖导致的问题。最后再分享一个小技巧如果你经常需要切换conda环境和ROS环境可以在.bashrc里给两套环境分别设置别名。比如alias rsenvconda deactivate conda config --set auto_activate_base false这样每次要进入ROS开发环境时执行一次rsenv就能保证当前终端不激活任何conda环境。我试过这个方案实测下来很稳省去了每次手动检查which python的麻烦。