☰
Ubuntu 16.04 源码编译 OpenVINO 2021.4:避开 GLIBC 版本坑
2026/10/19 5:17:44 网站建设 项目流程

如果你手头还有一批跑在 Ubuntu 16.04 上的工控机或服务器,又想把推理组件升级到 OpenVINO 2021.4,那你大概率会在第一步就卡住:官方预编译包默认面向 18.04 和 20.04 构建,直接搬到 16.04 上跑,最常见的报错就是GLIBC_2.27 not found或者GLIBCXX_3.4.22 not found。这个组合的痛点在于系统基础库太老,官方发布包不可能回头兼容这么旧的发行版。

不过只要拿到源码,自己编译一遍是完全可行的,而且能自己控制依赖版本和构建项。这篇文章我会把从环境准备、依赖升级到最终编译运行的全过程写下来,包括实际环境里踩过的坑。适合部署环境被锁死在 16.04、又需要更新推理能力的开发者和运维参考。

1. 为什么要在老系统上折腾 OpenVINO 2021.4

1.1 预编译包和源码编译的区别

先说清楚问题的根源。OpenVINO 预编译包在发布时是带 glibc 版本要求的。Ubuntu 16.04 的 glibc 是 2.23,而 2021.4 的官方二进制包基本是针对 glibc 2.27 以上构建的,所以你会看到类似version 'GLIBC_2.27' not found的动态链接报错。这不是你少装了某个库,而是系统底层的 C 运行库根本不满足要求。系统运行库这种东西不能随便替换,强行升级 glibc 极有可能搞挂整个系统,所以在 16.04 上走源码编译反而是最安全的路线。

源码编译的逻辑是:从源码把推理引擎和它依赖的第三方库重新构建出来,最终产物链接的是当前环境的运行库版本。也就是说,针对 glibc 2.23 的 16.04 环境编译出的库,在运行时就不会再挑 glibc 版本毛病。代价是你需要准备一套可用的编译链,包括较新的 CMake、GCC 和 Python,这些工具的版本门槛会在后面详细展开。

1.2 什么场景适合选择源码编译

实际上并不是所有机器都需要源码编译。如果你的系统是 18.04 及以上,直接下载官方 tar 包或者 pip 包,跑setupvars.sh就能用。但下面这几类场景,源码编译几乎是绕不开的:

  1. 系统被安全策略或业务约束固定在 16.04,不批准升级发行版。
  2. 机器没有外网访问受限,不便从官方源拉预编译包,但可以内网访问代码仓库和本地依赖源。
  3. 需要裁剪组件,只保留 CPU 推理插件,去掉 GPU、VPU、GNA 等不用的部分。
  4. 需要把编译产物放到多台相同系统的机器上复用,此时源码编译一次,rsync 分发即可。

我自己遇到的主要是第一种和第三种。一台现场设备上的系统不能动,但算法模型需要迁移到新版本推理框架上,所以只能选择在构建机上编译好,再拷贝过去。源码编译看起来费时间,实际上只要配置对,整个流程比反复排查动态链接错误要快得多。

2. 编译前的环境检查与依赖准备

2.1 先盘点系统现状,不要上来就编译

编译 OpenVINO 之前,先确认本机环境。建议按顺序执行下面几条命令:

lsb_release -a gcc --version cmake --version python3 --version ldd --version | head -n 1

在一台典型的 Ubuntu 16.04 机器上,你大概率会看到这样的结果:

  • Ubuntu 16.04.7 LTS
  • GCC 5.4.0
  • CMake 3.5.1
  • Python 3.5.2
  • glibc 2.23

这套组合基本没法直接编译 OpenVINO 2021.4。核心问题是 CMake 太旧,GCC 5.4 对 C++17 的支持不完整,Python 3.5 不在官方 Python API 支持范围内。你需要按下面的顺序升级工具链。

2.2 CMake 升级是第一道门槛

OpenVINO 2021.4 要求 CMake 3.13 或更高版本,而 Ubuntu 16.04 自带的 3.5.1 差得太远。不要用源码去编译安装 CMake,那会浪费大量时间。最省事的方式是下载官方编译好的二进制 tar.gz 包,放到/usr/local下:

wget https://github.com/Kitware/CMake/releases/download/v3.16.9/cmake-3.16.9-Linux-x86_64.tar.gz sudo tar -zxvf cmake-3.16.9-Linux-x86_64.tar.gz -C /opt sudo ln -s /opt/cmake-3.16.9-Linux-x86_64/bin/cmake /usr/local/bin/cmake

装完以后执行cmake --version确认版本。这里有一个经验:如果你的 shell 之前已经缓存过旧版的路径,执行hash -r刷新一下命令缓存,否则可能还会调到老版本的 CMake。

2.3 Python 环境处理思路

2021.4 的 Python API 支持 Python 3.6 到 3.9,Ubuntu 16.04 自带的 Python 3.5 不满足条件。如果不需要 Python API,只想用 C++ 接口,可以跳过 Python 升级。但如果需要跑 Python 推理脚本,就得装一个更新的 Python。

我建议通过第三方工具链 PPA 安装 Python 3.6,装完以后不要把它设为系统默认的python3,而是在编译时通过参数显式指定路径。这样做的好处是避免干扰系统里已有的 Python 3.5 脚本:

sudo add-apt-repository ppa:deadsnakes/ppa sudo apt-get update sudo apt-get install python3.6 python3.6-dev python3.6-distutils

之后编译时加上-DPYTHON_EXECUTABLE=/usr/bin/python3.6参数,OpenVINO 会基于 3.6 生成对应的 Python 模块。需要说明的是,用 Python 3.6 编译出的openvino包只能在 Python 3.6 环境里加载,这就意味着运行时也要用同一个 Python 版本。为了不污染系统环境,建议建一个 venv:

/usr/bin/python3.6 -m venv /opt/ovenv source /opt/ovenv/bin/activate

2.4 GCC 版本升级是避坑关键

GCC 5.4 在编译 OpenVINO 的部分组件时会出现结构体初始化、正则表达式相关的问题,根本原因是它对 C++17 的支持不完整。OpenVINO 2021.4 在 18.04 上官方使用 GCC 7.5 构建,所以我们也要在 16.04 上装一套 GCC 7。

同样是走第三方 PPA:

sudo add-apt-repository ppa:ubuntu-toolchain-r/test sudo apt-get update sudo apt-get install gcc-7 g++-7

安装完成后,编译时直接指定CC=gcc-7 CXX=g++-7即可,不需要修改系统默认 GCC。这样可以避免把系统里其他 C 代码的编译环境搞乱。我踩过一次坑,想直接把软链接全局切到 GCC 7,结果系统里某些旧模块重新编译时出现了二进制不兼容问题,所以还是建议只在 OpenVINO 构建时临时指定编译器。

3. 源码结构与编译参数详解

3.1 源码目录里有哪些东西

拿到 OpenVINO 2021.4 源码后,先看清楚目录结构再动手。克隆代码:

git clone --recursive https://github.com/openvinotoolkit/openvino.git cd openvino git checkout 2021.4 git submodule update --init --recursive

源码根目录下主要有这几个部分:

  • inference-engine:推理引擎核心,包含 CPU、GPU、VPU 等插件。
  • ngraph:模型解析和计算图优化层,OpenVINO 通过它把不同框架的模型统一成中间表示。
  • openvino:新版本的顶层封装和 Python API 绑定。
  • docs:文档和示例程序。
  • cmake:公共的 CMake 工具脚本。

编译入口在inference-engine目录,OpenVINO 2021.4 的构建流程会把ngraph和inference-engine一起构建。实际上你也可以在根目录创建build目录,再指向inference-engine目录进行配置,两种方式等价。

3.2 关键 CMake 选项说明

编译 OpenVINO 时有一批 CMake 选项需要提前理解。下面列出我实际用到的几个,并说明每个的作用:

选项作用建议值
-DCMAKE_BUILD_TYPE=Release编译优化级别,Release 模式性能更好必选
-DCMAKE_INSTALL_PREFIX指定安装目录/opt/openvino
-DTHREADING=SEQ使用顺序线程模式,不依赖额外线程库无 TBB 时使用
-DENABLE_VPU=OFF关闭 VPU 插件不需要神经棒时关闭
-DENABLE_GNA=OFF关闭 GNA 插件不需要语音加速时关闭
-DENABLE_CLDNN=OFF关闭 GPU 插件相关代码不跑 GPU 推理时关闭
-DENABLE_OPENCL=OFF关闭 OpenCL 运行时不使用 GPU 时不开启
-DENABLE_PYTHON=ON构建 Python API需要 Python 时开启
-DPYTHON_EXECUTABLE指定 Python 解释器路径指向 Python 3.6

如果你不需要 GPU 推理,千万记得把ENABLE_CLDNN和ENABLE_OPENCL关掉。这两个组件编译时会引入大量 GPU 相关依赖,开着会显著拉长编译时间,而且 16.04 上配套的 OpenCL 运行库版本也不好凑。

3.3 推荐用于 16.04 的编译配置

综合上面的考虑,我的推荐配置如下:

cd inference-engine mkdir build cd build cmake .. \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX=/opt/openvino \ -DCMAKE_C_COMPILER=gcc-7 \ -DCMAKE_CXX_COMPILER=g++-7 \ -DTHREADING=SEQ \ -DENABLE_VPU=OFF \ -DENABLE_GNA=OFF \ -DENABLE_CLDNN=OFF \ -DENABLE_OPENCL=OFF \ -DENABLE_PYTHON=ON \ -DPYTHON_EXECUTABLE=/usr/bin/python3.6

这里解释一下THREADING=SEQ的选择。OpenVINO 默认会尝试集成 TBB 线程库,而 2021.4 的 TBB 版本在 16.04 上需要额外处理链接路径。如果我只需要 CPU 推理且没有特殊并发要求,直接用顺序线程模型可以少绕很多坑。如果后续需要 TBB,可以在编译好 TBB 之后再加-DTBB_DIR指定路径,这个后面会在问题排查里提到。

关于编译的并发度,内存有限的机器建议make -j4,如果内存小于 8GB,-j2更稳妥。我以前在 4GB 内存的小机器上用-j8编译,跑到一半直接被 kill,浪费了整整半天时间。编译是一个内存和 CPU 双重消耗的过程,不要贪并行度。

4. 完整实操流程记录

4.1 编译前需要安装的本地软件包

正式编译之前,先把系统内的基础依赖装齐。OpenVINO 构建过程中会用到一些开发头文件,缺了会在 CMake 配置阶段报错:

sudo apt-get update sudo apt-get install build-essential pkg-config sudo apt-get install libgtk-2.0-dev libcanberra-gtk-module sudo apt-get install libssl-dev libffi-dev sudo apt-get install libusb-1.0-0-dev

libgtk-2.0-dev主要影响 OpenCV 和推理示例的构建。如果你不需要编译带 GUI 的示例程序,可以暂时不装,但建议还是装上,避免后续跑 demo 时缺图形库依赖。另外 OpenVINO 构建过程中会检测系统中的 OpenCV。如果系统已有 OpenCV 2.4,可能会出现版本冲突,这个到第 5 节再讲处理办法。

4.2 模块初始化和生成构建文件

OpenVINO 源码仓库包含多个子模块,clone 时必须用--recursive。如果你 clone 时漏掉了子模块,或者只想下载特定版本,可以手动初始化:

git checkout 2021.4 git submodule update --init --recursive

然后进入构建目录进行 CMake 配置。CMake 配置阶段结束以后,认真看一遍屏幕输出的Features表格,确认CPU插件是开启状态,VPU、GNA等插件是关闭状态。这一步值得多看两眼,因为如果漏了某个依赖,CMake 也会在配置阶段直接报错,而不是等到编译阶段。配置成功后会生成 Makefile,下面可以开始编译。

4.3 编译安装和产物确认

执行编译:

make -j4

编译时间取决于机器性能。我在一台 16 核的机器上大约花费 40 分钟,在 4 核的机器上则接近 2 小时。编译过程中如果发现某个文件报语法错误,先回想一下 GCC 版本是否设置正确,不要一味修改源码。OpenVINO 这种大型项目的源码经过大量测试,大多数编译错误都是工具链不匹配引起的。

编译完成后执行:

make install

安装完成后确认一下关键产物:

ls /opt/openvino/bin/ ls /opt/openvino/lib/

正常情况下bin目录会包含benchmark_app、setupvars.sh等可执行文件和脚本,lib目录会包含libinference_engine.so、libngraph.so等库文件。看到这些文件基本说明推理引擎编译成功了。

4.4 运行环境和快速验证

每次使用前需要加载环境变量:

source /opt/openvino/bin/setupvars.sh

验证编译产物是否可用的最快方法是跑一下benchmark_app:

./benchmark_app -h

如果能看到帮助信息,说明推理引擎核心库加载正常。想要完整验证模型推理,准备一个 OpenVINO IR 格式的模型,运行:

./benchmark_app -m /path/to/model.xml -i /path/to/input.jpg -d CPU -api sync

我第一次跑的时候遇到过一个动态链接问题:libinference_engine.so找不到libngraph.so。原因是setupvars.sh没有正确配置LD_LIBRARY_PATH,或者安装目录被移动过。解决办法是手动把安装目录追加到环境变量:

export LD_LIBRARY_PATH=/opt/openvino/lib:$LD_LIBRARY_PATH

4.5 多台机器分发部署的注意事项

OpenVINO 编译完成后,产物可以直接拷贝到其他同样版本的系统上使用。我实际分发的文件包括:

  • bin目录下的可执行文件和脚本
  • lib目录下的所有.so库文件
  • share目录下的模型转换相关辅助文件
  • Python API 模块文件(如果开启)

拷贝后必须在目标机器上重新执行setupvars.sh,并且确认目标机器的 GLIBC 版本不低于编译机。虽然源码编译理论上生成的是当前环境的兼容产物,但如果编译机和目标机的系统版本差距过大,仍可能出现 libstdc++ 不兼容的问题,这个问题在下一节详细展开。

5. 遇到的典型错误与排查实录

5.1 运行时 GLIBCXX 版本报错

场景:编译机器是 18.04,目标机器是 16.04,把编译产物拷到 16.04 上运行,报错:

libstdc++.so.6: version GLIBCXX_3.4.22 not found

这个问题的根源不是 OpenVINO,而是编译机 GCC 7 的运行时库比 16.04 自带的 libstdc++ 新。解决办法有两种:一种是在编译机下载老版本 libstdc++ 并静态链接,一种是在目标机上把 GCC 7 的 libstdc++ 通过LD_LIBRARY_PATH带上。最稳妥的方案是让编译机和目标机系统保持同版本。如果确实做不到,建议用下面的命令确认当前 libstdc++ 提供的最高版本:

strings /usr/lib/x86_64-linux-gnu/libstdc++.so.6 | grep GLIBCXX | sort -V | tail -n 5

如果在 16.04 上连GLIBCXX_3.4.22都没有,就需要用 GCC 7 自带的新 libstdc++,并将它的路径提前到LD_LIBRARY_PATH最前面。

5.2 编译过程中内存耗尽被杀死

编译 OpenVINO 的ngraph组件时,GCC 的内存占用非常高。某些复杂模板元编程代码会让单进程占用 1GB 以上内存。如果同时用-j8编译,8 个进程叠加起来,内存很容易爆掉。系统日志里面会出现 OOM kill 记录。

解决思路很简单:降低并行度。建议先free -h看下可用内存,内存 8GB 以下用-j2,16GB 左右用-j4。另外可以在make命令后面加上-l参数限制系统负载:

make -j4 -l 4

-l 4表示当系统平均负载超过 4 时不再启动新任务,对共享编译资源的机器尤其有用。

5.3 系统已安装 OpenCV 导致链接冲突

OpenVINO 构建过程中如果检测到系统里有 OpenCV,它可能会优先尝试使用系统版本。但系统上的 OpenCV 多半是 2.4 或 3.x 的老版本,和 OpenVINO 自带的 OpenCV 头文件不一致,结果就是编译出来的程序在运行时出现大量undefined reference或者直接崩溃。

排查思路是看 CMake 配置阶段的日志,搜索OpenCV相关信息。如果发现它使用了系统路径,可以在 CMake 配置时显式指定:

-DOpenCV_DIR=/usr/share/OpenCV \ -DENABLE_OPENCV=OFF

我这里更推荐直接把ENABLE_OPENCV关掉,因为 OpenVINO 自身的推理示例对 OpenCV 的依赖并不多,关掉反而少一个变量。如果你确实需要跑带图像解码的 demo,再单独编译配套的 OpenCV 版本并让 OpenVINO 使用它。

5.4 Python 模块导入报错

如果开启 Python API 后,执行import openvino报错:

ModuleNotFoundError: No module named 'openvino'

或者:

ImportError: libpython3.6m.so.1.0: cannot open shared object file

前者通常是环境变量没配置好,setupvars.sh里已经写了 Python 模块路径,需要确认你当前使用的 Python 版本正是编译时指定的那一个。后者是因为构建时虽然指定了 Python 3.6 的头文件和库路径,但运行时系统的动态库搜索路径不包含 Python 自身库目录,需要单独加入:

export LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu:$LD_LIBRARY_PATH

这个坑比较隐蔽,因为 Python 模块使用的是编译期的 Python 路径,而 OpenVINO 的 Python 绑定又通过ctypes加载底层库,这个组合在非标准 Python 安装路径下特别容易出现。

6. 一些实际体会与调整建议

OpenVINO 2021.4 在 Ubuntu 16.04 上编译,难度主要集中在前期的工具链准备上,真正跑起来之后问题反而不多。就我个人的体验而言,下面这几条是值得一开始就做对的:

第一,尽量使用独立的编译目录。不要直接在源码目录下编译,因为 OpenVINO 的子模块比较多,一旦编译残留物混进源码目录,后续切换分支或重新生成 CMake 配置时,很容易因缓存产生诡异问题。我就是一直保持inference-engine/build目录的独立,出问题直接删掉整个 build 目录,重新生成,成本最低。

第二,认真对待 CMake 配置输出。OpenVINO 配置完成以后会在终端打印一张组件开关表,包括各个插件的构建状态。每次我用grep检查输出,都确认 CPU 插件是ON状态。很多人编译完以后发现没有 CPU 推理能力,基本都是ENABLE_MKL_DNN=OFF或 CPU 插件构建状态异常。

第三,不要在同一台机器上反复用不同的 GCC 版本切换编译。GCC 5 和 GCC 7 编译出的对象文件混在同一个 build 目录里,链接时会出现奇奇怪怪的符号冲突。如果你尝试过不同编译器版本,建议彻底清空 build 目录再重新配置。

第四,如果只是想要一个能跑的推理环境,而目标机器有网络,可以先用 18.04 的 Docker 容器完成全流程验证,再把编译好的产物带到 16.04 上测试运行。我这里试过最顺利的部署方式其实是:在一台 16.04 的构建机上用 GCC 7 编译,产物直接放到同样 16.04 的目标机,全程不出现 GLIBC 和 GLIBCXX 报错。如果你有两台相同版本的系统,这会是最省心的方案。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询