移植Boost Logger C++程序至Yocto嵌入式系统遇非法指令及后续问题
boost::gregorian::date::date非法指令问题 我碰到过类似的嵌入式架构兼容问题,结合你的场景给你梳理下解决方案:
你说程序用了Boost Logger,在Windows和Intel i5的Ubuntu上跑都没问题,但移植到Intel Atom的Yocto嵌入式系统时就触发非法指令,一开始查到是OpenCV的AVX指令搞的鬼,禁用AVX后这个问题没了,结果又冒出来boost::gregorian::date::date的非法指令错误。本质上这都是同一个问题——指令集不兼容,咱们一步步来解决:
一、先搞懂为什么会出这个错
Intel Atom(尤其是早期的Silvermont/Airmont架构)根本不支持AVX、AVX2这些指令集,但你在i5主机上编译的时候,编译器默认会用主机支持的所有指令集(包括AVX),生成的二进制文件里就会有Atom认不出来的指令,跑起来自然就触发非法指令了。
你禁用AVX解决了OpenCV的问题,但Boost这边又出问题,说明Boost库要么是你用了主机上预编译的版本,要么编译Boost的时候没指定Atom兼容的指令集,导致gregorian模块里也混进了Atom不支持的指令。
二、具体解决步骤
1. 统一所有编译的指令集参数
不管是编译你的程序、Boost还是OpenCV,都得明确指定Atom支持的指令集。Atom支持的是SSE、SSE2、SSE3、SSSE3、SSE4.1、SSE4.2,绝对不能用AVX相关的。
如果用CMake的话,直接在CMakeLists.txt里加:
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=atom -mno-avx -mno-avx2") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=atom -mno-avx -mno-avx2")
如果是直接用gcc编译,就把这些参数加到编译命令里。
2. 重新编译适配Atom的Boost库
别再用主机上现成的Boost了,重新编译一个适配Atom的版本:
# 先初始化Boost构建脚本 ./bootstrap.sh # 指定编译参数,强制用Atom兼容的指令集 ./b2 cxxflags="-march=atom -mno-avx -mno-avx2" linkflags="-march=atom -mno-avx -mno-avx2" install
这样编译出来的Boost所有模块(包括gregorian)都会用Atom能识别的指令。
3. 重新编译适配Atom的OpenCV
之前你只是禁用了AVX,但可能没完全对齐Atom的架构,重新编译的时候也加上指令集参数:
在CMake配置OpenCV的时候,除了加上面的编译参数,还可以关掉一些可能不兼容的选项:
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=atom -mno-avx -mno-avx2") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=atom -mno-avx -mno-avx2") set(WITH_IPP OFF) # IPP一般针对高端Intel处理器,Atom可能不兼容,关掉 set(OPENCV_ENABLE_NONFREE OFF) # 可选,避免一些依赖问题
然后重新编译安装OpenCV。
4. 验证二进制文件的指令集
编译完之后,用objdump检查下你的程序和依赖库有没有残留AVX指令:
objdump -d your_program | grep -i avx
如果没有输出,说明已经清理掉AVX指令了,符合Atom的要求。
三、关于禁用AVX后出现的新问题
如果还有新问题,大概率还是依赖库的指令集不统一或者Yocto系统环境的问题:
- 检查所有用到的库(比如系统的glibc、其他第三方库)是不是都是针对Atom编译的,别混合用主机编译的库和Yocto系统的库。
- 核对下编译环境的gcc版本、glibc版本和Yocto系统里的版本是否一致,版本不兼容也会导致各种奇怪的运行时错误。
- 用
gdb挂上去调试新错误,定位到具体出错的函数或指令,看看是不是还是指令集的问题,或者是系统里缺少某个依赖文件、权限不对之类的环境问题。
内容的提问来源于stack exchange,提问作者Humam Helfawi

