简介:Qt 5.9.9在Ubuntu 14.04 LTS下执行./configure -prefix $PWD/qtbase -opensource时,常报'The OpenGL functionality tests failed'错误,导致配置中断。遇到该报错的开发者,可参考这套包含3个文件的排错记录与验证文件,快速定位编译失败的原因。压缩包共3个文件,包括2个txt说明文件和1个c源码文件,总体积仅2KB,核心信息集中;已有4468人学习/下载,说明该问题在Linux环境中具有一定普遍性。txt文件记录了报错上下文、OpenGL环境检测失败的可能原因及解决思路;c文件可用于直接查看Qt的OpenGL功能测试代码,帮助理解检测条件,从而判断是缺少库、驱动还是配置参数问题。适合在Ubuntu等Linux发行版上从源码编译Qt、希望快速绕过OpenGL检测坑的开发者参考。
1. 解决 Qt 源码编译报 OpenGL functionality tests failed:先别急着怪显卡
用源码编译 Qt 时,configure 步骤走到一半弹出一句The OpenGL functionality tests failed,很多人的第一反应是显卡驱动坏了。实际上,这个报错跟显卡的关系通常不大,真正的问题是 configure 在检测 OpenGL 开发环境时,头文件、链接库或者测试程序编译链接失败。这个检测是 Qt 源码编译的前置条件,它过不去,qtbase 就编不出来,后面依赖 OpenGL 的模块也全部免谈。本文就从检测机制讲起,把常见平台下的处理路径和参数选择整理清楚,适合 Linux、Windows、macOS 上自己做 Qt 源码编译的工程师,也适合做 ARM 交叉编译的从业者。
2. configure 阶段如何检测 OpenGL:先看懂判据再动手
2.1 检测的三类对象:头文件、库文件、链接结果
Qt 源码里的 OpenGL 检测并不是简单地看一下系统里有没有显卡驱动,而是按“头文件 → 库文件 → 链接测试”三层顺序做的。configure 运行时,Qt 的 qmake 构建系统会去查找 OpenGL 相关的头文件,比如GL/gl.h、GL/glext.h,在 X11 环境下还会找EGL/egl.h和GLES2/gl2.h。这一步用的是编译器的 include 路径,不是系统里随便哪个目录有文件就行。
找到头文件之后,configure 还要去找对应的库。Linux 下常见的是libGL.so、libEGL.so、libGLESv2.so;macOS 下是系统的OpenGL.framework;Windows 下 msvc 用的是opengl32.lib。库文件查找依赖编译器的默认库路径或者 pkg-config 提供的路径,这里最容易出问题:运行时库明明存在,比如libGL.so.1,但开发者没装-dev包,导致libGL.so这个软链不存在,链接阶段直接失败。
最后一步是链接测试。configure 会把一个最小的 OpenGL 测试程序编译并链接,这个测试程序会调用glXCreateContext、glClear这类入口符号,链接器能找到符号才算通过。三层检测任何一个环节出问题,configure 都会放弃,最终统一汇总成标题里那句The OpenGL functionality tests failed。所以看到这个报错之后,第一步不是去装显卡驱动,而是去查 configure 的日志,定位死在哪个阶段。
2.2 报错出现的两种形态,处理优先级不同
同样是OpenGL functionality tests failed,出现的位置和处理逻辑并不一样。最常见的是在 qtbase 这个模块的 configure 阶段直接挂掉,这种情况下整个 Qt 构建都会终止,你要解决的是基础 OpenGL 开发环境。第二种形态是 qtbase 已经编过去了,但后续模块如 qtdeclarative、qtsvg、qt3d 在各自 configure 时又报同样的错,这种情况多半是你在配置 qtbase 时用了过于激进的参数,比如-no-opengl,或者把 OpenGL 相关 feature 显式关掉了。
先判断是哪种形态,再看日志,能少走很多弯路。如果 qtbase 还没过去,优先排查系统的 GL 开发包、pkg-config 路径、X11 相关依赖。如果 qtbase 已经过了但子模块失败,回到 qtbase 的 configure 参数里看 OpenGL feature 是不是被某条-no-*或者-feature-*误伤了。这两个方向的处理手段完全不一样,混淆了就会在无关的地方反复折腾。
2.3 加参数看似跳过,后续模块为什么又炸
最常见的“跳过式”做法是给 configure 加-no-opengl,然后发现 qtbase 能编了,但后面的模块又开始报错。原因是 Qt 的很多模块默认启用了openglfeature,比如qtdeclarative里的场景图渲染、qt3d的整个渲染管线。qtbase 的 OpenGL 支持被关掉之后,这些模块的 configure 会检测到 feature 缺失,随后报错或者生成一个被裁剪掉的配置。用-skip把这些模块跳过当然可以,但代价是 Qt 库里重要的功能模块没了,这对绝大多数项目是不能接受的。
正确思路是把 OpenGL 检测当作一个环境前置条件去补齐,而不是绕过。configure 的检测逻辑写得很死,它要的不是“你有个显卡”,而是“编译期能拿到头文件、链接期能定位库、运行时能加载”。这三个条件分别对应开发包、链接路径、运行库,理解了这三层,后面的排查才有方向。
3. 通用解决步骤:从日志定位到可复现的 configure 命令
3.1 先读 configure 日志,不要急着加参数
拿到报错后,第一件事是打开 configure 生成的日志文件。qtbase 的构建目录下会有config.log,里面记录了每一项检测的详细输出,包括编译器执行的命令行、头文件查找路径、链接器报错信息。直接搜索关键字就能定位到失败点。
cd /path/to/qt-everywhere-src/qtbase grep -i "opengl" config.log | tail -80如果 grep 出来的内容不够,还可以看末尾部分,configure 通常会把失败的检测项集中记录在文件靠后的位置。需要重点看的是两个维度:第一,报错是GL/gl.h: No such file or directory这类头文件缺失,还是cannot find -lGL这类链接失败;第二,检测用的编译器是不是你预期的交叉工具链。这两点直接决定后面的解决方向。
很多人在这一步图省事,直接回到 configure 命令上瞎试参数,比如把-opengl desktop改成-opengl es2,试几次还是失败,最后发现问题是系统里连 mesa 的开发包都没装。日志文件是免费的排错信息,不花这几分钟实在可惜。
3.2 选对 opengl 参数:desktop、es2、dynamic 还是关闭
看懂了日志里确定失败原因后,再回到 configure 命令选择 OpenGL 模式。Qt 的 configure 提供了几个互斥的 OpenGL 配置开关,不同场景选不同的值。
| configure 参数 | 适用场景 | 注意事项 |
|---|---|---|
-opengl desktop | 桌面 Linux、Windows 下使用系统 OpenGL 驱动 | 需要系统有 GL 开发库;驱动太老时可能检测通过但运行崩 |
-opengl es2 | 嵌入式平台、Android、只有 GLES 的环境 | 系统里要提供 GLES 头文件和库;桌面端不禁用的话很多模块不可用 |
-opengl dynamic | 希望运行时在 desktop 与 es2 间自动选择 | Qt 5 之后加入的配置;运行时比以前略复杂 |
-no-opengl | 纯软件渲染、服务器无窗口环境 | QOpenGLWidget 和 RHI 相关的功能会被裁掉 |
选择原则是:桌面开发优先-opengl desktop;如果目标设备是板子或者 GPU 只支持 GLES,那么-opengl es2;只有当需要兼容多种设备时才用-opengl dynamic,它会在运行时根据 EGL 和 GLX 的实际能力切换。-no-opengl不到万不得已不要碰,Qt 6 之后很多底层渲染都走 RHI,关闭 OpenGL 的代价比 Qt 5 时代更大。
3.3 补齐依赖库:三个平台的通用清单
依赖库补齐到位后,绝大多数检测失败都能解决。Linux 桌面环境最核心的是 mesa 的开发包和 X11 扩展库,Debian/Ubuntu 下安装命令如下。
sudo apt install build-essential libgl1-mesa-dev libegl1-mesa-dev \ libgles2-mesa-dev libxcb*-dev libx11-xcb-dev libxkbcommon-devFedora/RHEL 系对应的是mesa-libGL-devel和mesa-libEGL-devel,用 dnf 安装即可。Windows 下如果使用 msvc 工具链,opengl32.lib随 Windows SDK 自带,通常不需要额外安装;如果选了-opengl es2,Qt 源码会自己构建 ANGLE,不需要手工下载,但构建 ANGLE 需要 Python 和合适的 MSVC 版本,这部分环境缺失也会导致检测失败。macOS 不需要单独装 OpenGL 库,系统自带OpenGL.framework,检测失败的常见原因是 Xcode 版本过旧或 SDK 路径配置不对。
3.4 清理旧配置后重跑,避免脏构建干扰
configure 检测失败之后会留下半成品状态的构建目录,直接在这个目录里重跑 configure 很危险,因为 Qt 的 qmake 会缓存上次检测的结果,新参数未必能完全覆盖旧状态。
make distclean # 在 qtbase 源码目录内执行 rm -rf build/ # 如果使用独立构建目录,直接删除更干净 ./configure -prefix /opt/Qt-5.15.2 \ -opensource -confirm-license \ -opengl desktop \ -skip qtwebengine \ -nomake examples make -j$(nproc)参数说明:-skip qtwebengine是去掉体积最大且编译最重的模块,它依赖 Python、Ninja 和平台浏览器引擎,和 OpenGL 检测无关,加上它能让很多验证性的编译提前完成。-nomake examples可以省掉例子代码的编译时间。如果你前面报错的机器环境特殊,比如只有软件渲染,那么-opengl es2加-no-feature-opengles3的组合也值得试,但一般先紧着桌面 GL 解决。
重跑 configure 后,建议把命令最后加的选项都记入一个文本文件,后续重新编译时直接复制。Qt 的 configure 也支持-recheck或者从config.opt里复用参数,但这个文件得是之前成功过才可靠。
4. 四个高频场景的定向处理:桌面、Windows、macOS、ARM 交叉编译
4.1 Linux 桌面:Mesa 开发包与 X11 依赖缺一不可
Linux 桌面环境下的 Qt 源码编译,OpenGL 检测失败的原因排在第一位的是没装 mesa 的开发包。很多人的系统里显卡驱动正常工作,桌面也跑得起来,但那是运行时的情况,编译期需要的GL/gl.h和libGL.so属于libgl1-mesa-dev包,默认不随驱动安装。
装了 mesa 开发包之后还失败,就要查 X11 相关依赖。Qt 的 xcb 平台插件依赖libxcb-*系列开发库,特别是libxcb-icccm4-dev、libxcb-keysyms1-dev、libxcb-shape0-dev这些,它们虽然不直接参与 GL 检测,但是会影响 xcb 插件是否能编译出来。GL 检测通过后,如果 xcb 插件编不出来,Qt 程序跑起来会报 platform plugin 缺失,这是另一个典型的连坐问题。
4.2 Windows + msvc:opengl32 与 ANGLE 的取舍
Windows 上用 msvc 编译 Qt,OpenGL 检测失败的频率不高,但一旦失败,常见原因是强制选择了 GLES 模式,导致 Qt 尝试构建 ANGLE 时找不到合适的 DirectX SDK 头文件。桌面 Windows 环境下,最稳妥的配置是-opengl desktop,直接使用系统自带的opengl32.lib,微软的编译器对它的支持很完整,几乎不会在链接阶段出问题。
如果你确实需要 ANGLE,比如你的应用要跑在只有 GLES 驱动的老机器上,那么-opengl dynamic比-opengl es2更好。dynamic 模式在运行时优先加载系统 OpenGL,如果失败再回退到 ANGLE 的 ES 实现,开发和交付都更灵活。mingw 环境下容易出现一个问题:opengl32.lib的路径不在默认的库搜索目录里,此时需要在 configure 的-I或环境变量LIB里把 mingw 的 lib 目录补进去。这个问题在 msys2 里尤其常见,因为 mingw 的库通常位于C:/msys64/mingw64/lib,和 msvc 的默认搜索路径不一致。
4.3 macOS:OpenGL.framework 不存在时的问题
macOS 系统的 OpenGL 支持是通过系统的OpenGL.framework提供的,它位于/System/Library/Frameworks/OpenGL.framework,正常安装 Xcode 后该路径必然存在。源码编译 Qt 时,如果在 macOS 上报 OpenGL 检测失败,多数不是框架缺失,而是 configure 找不到对应版本的 SDK 路径。
xcode-select -p输出的路径如果不对,或者系统里同时存在多个 Xcode 版本,会让 configure 里的 SDK 检测混乱。处理方式是先用xcode-select --switch指定正确的 Xcode 路径,然后再重跑 configure。另外 macOS 从高版本开始逐步弃用 OpenGL,Qt 5.15 和 Qt 6.x 在较新的 SDK 上需要注意部署兼容性,但这个跟编译检测失败是两回事,别混在一起查。
4.4 ARM 与嵌入式交叉编译:sysroot 里要有正确 GL 库
交叉编译是 OpenGL 检测失败的高发区,因为宿主机的 GL 库和开发头文件跟目标系统是两套东西。最常见的问题是你的 sysroot 里只有运行时的libGL.so.1,而没有编译期需要的libGL.so软链,configure 在链接测试时直接报cannot find -lGL。
树莓派这类 ARM 板子上,如果目标系统用的是 Mesa,那么 sysroot 里需要完整安装libgl1-mesa-dev和libegl1-mesa-dev;如果板子的 GPU 厂商提供的是私有驱动,比如 Mali 的libmali.so,那么系统里通常只有 EGL 和 GLES 库,没有 desktop GL。这时候 configure 应该选-opengl es2,并且确保 sysroot 里有GLES2/gl2.h和libGLESv2.so。银河麒麟这类信创环境也一样,先确认目标系统提供的是桌面 GL 还是 GLES,再决定参数,顺序反了就是连续几轮翻车。
5. OpenGL 检测失败的常见坑与排查手段
5.1 现象:装了显卡驱动还是失败
很多人在 Linux 桌面上用nvidia-smi确认驱动正常,然后编译 Qt 依然报OpenGL functionality tests failed。原因不是驱动本身,而是编译期需要的开发包没有装。显卡驱动属于运行时组件,编译期需要的是libgl1-mesa-dev或者 Nvidia 提供的libglvnd-dev。解决方法是把 mesa 开发包装上,如果你的系统用的是 Nvidia 专有驱动,还需要确保libglvnd安装完整,后者负责把 GL 调用分发到不同的驱动实现上。
5.2 现象:cannot find -lGL但libGL.so.1存在
configure 日志里如果出现cannot find -lGL,但手动在/usr/lib/x86_64-linux-gnu/下能看到libGL.so.1,说明系统里缺少开发软链。运行时库不带.so软链很正常,链接器要的是libGL.so而非libGL.so.1。解决方法是安装对应的-dev包,不要手工建软链,因为大部分系统的 GL 软链关系到多个库版本,手工操作容易把环境搞乱。在 Ubuntu 上执行apt install libgl1-mesa-dev即可自动建立正确的软链。交叉编译环境里没有包管理器可用时,才用手工ln -s libGL.so.1 libGL.so临时顶上,但要注意这只是权宜之计。
5.3 现象:交叉编译时 pkg-config 指向宿主机
交叉编译 Qt 时,configure 读取 pkg-config 来定位 OpenGL 和 X11 相关开发包。如果宿主机上装了 mesa 开发包,而目标 sysroot 里也有一套不同的 GL 库,pkg-config 的搜索路径顺序不对时,configure 可能找到宿主机的.pc文件,检测结果是“通过”,但编译时却链接到错误的库,最终产物放到板子上跑不起来。解决方法是把 sysroot 的 pkgconfig 路径放到PKG_CONFIG_PATH的最前面,并且用PKG_CONFIG_SYSROOT_DIR指明交叉根目录,这样 configure 拿到的路径就会全部重定位到 sysroot 之下。
export PKG_CONFIG_SYSROOT_DIR=/opt/sysroot export PKG_CONFIG_PATH=/opt/sysroot/usr/lib/arm-linux-gnueabihf/pkgconfig设置完这两个变量后再执行 configure,日志里搜索 pkg-config 相关的行确认路径已经指到 sysroot,这一步能避免很多后知后觉的链接错误。
5.4 现象:qtbase 编过了,qtdeclarative 又报同样的错
Qt 源码是多模块体系,qtbase 的 OpenGL 检测过了不表示后续模块就没问题。最常见的原因是在 qtbase 的 configure 里加了-no-opengl或-no-feature-opengl,然后把 qtdeclarative、qt3d 这些模块的默认检测直接打断。解决方法是回到 qtbase 的 configure 参数里启用 OpenGL,如果实在要裁掉某些模块,用-skip qt3d -skip qtdeclarative这类模块级跳过参数,而不是在 Qt 库内部把 OpenGL feature 关掉。否则即使编过了,后面写代码时QOpenGLWidget不可用,局面更被动。
6. 用示例程序验证 OpenGL 是否真的可用:轻量冒烟测试
OpenGL 检测通过并不代表运行环境就没问题,Qt 库编出来后,建议做一次冒烟测试。Qt 源码自带 OpenGL 示例,编译出来运行一下,远比事后在业务工程里才发现问题要省事。
make -C examples/opengl/box ./examples/opengl/box/box程序能弹出一个旋转的立方体窗口,说明桌面 GL 的运行链路是通的。这个例子对驱动要求不高,Mesa 的软件渲染都能跑起来,能有效排除平台插件和 GL 上下文创建方面的问题。运行时如果遇到qt.qpa.plugin: could not find the qt platform plugin "linuxfb"这类提示,说明你设了QT_QPA_PLATFORM=linuxfb但当前构建没有编译对应插件,这和 OpenGL 检测不是一回事,可以先用export QT_QPA_PLATFORM=xcb切回桌面 GL,或者把linuxfb平台的插件编进去。
再进一步,可以用 qmake 双向确认配置结果。qmake -query QT_CONFIG | grep opengl输出里有opengl字符串,说明编译期配置是带上了的。运行时则看glxinfo | grep "OpenGL vendor",确认当前用户环境能拿到真实渲染上下文。这两个命令合起来,能覆盖从编译配置到运行时的完整链路。
在我自己的项目里,凡是编译 Qt 遇到 OpenGL 检测失败,我习惯先把 configure 命令、系统包列表、config.log 关键片段三样东西存到一个 notes 文件里再动手改环境。这样一旦下次在别的机器上遇到同样的事,可以直接翻出来对照,比每次从头查一遍日志快得多。希望这次的拆解能让你把这个报错彻底解决掉,编译过程少一点玄学感。
本文还有配套的精品资源,点击获取