Ubuntu 18.04下Deepin QQ 9.1.8在NVIDIA环境中报libGL error的不完美解决方案
本文首发于博客园(https://www.cnblogs.com/ArrowKeys/p/12152602.html),禁止转载。
更新
已发现该错误的根本原因:官方网站上直接下载的CUDA安装包安装时会直接覆盖系统的libGL.so等相关文件。
解决方案:参考 https://github.com/ValveSoftware/steam-for-linux/issues/5778#issuecomment-575334890
其中提到的nvidia-drivers PPA是 http://ppa.launchpad.net/graphics-drivers/ppa
背景
本机环境:NVIDIA GTX 1660Ti,Ubuntu 18.04,CUDA 10.2(显卡驱动版本440.33.01)
笔者按照wszqkzqk的方案安装了最新的deepin QQ(9.1.8),安装了CUDA 10.2(自带440.33.01显卡驱动)并切换至NVIDIA模式登录系统。此时发现QQ无法正常启动。
经过若干验证,基本确定如下现象:
-
在Intel核显模式下可正常启动QQ 8.9.4和QQ 9.1.8。
-
在NVIDIA独显模式下可正常启动QQ 8.9.4,无法启动QQ 9.1.8。
为了观察错误情况,在命令行中使用/opt/deepinwine/apps/Deepin-QQ/run.sh
启动之,打印出错误如下:libGL error: No matching fbConfigs or visuals found
libGL error: failed to load driver: swrast
X Error of failed request: GLXBadContext
Major opcode of failed request: 152 (GLX)
Minor opcode of failed request: 6 (X_GLXIsDirect)
Serial number of failed request: 204
Current serial number in output stream: 203
探索
错误报告明显指向libGL.so的错误使用。结合两种显卡模式下的不同表现,猜测问题出在使用NVIDIA显卡时不应使用现在版本的libGL.so,即可能两显卡各有自己适用的libGL.so。(顺便吐槽一句,之前的960M卡就没出问题……)
Deepin QQ调用的是32位库,于是尝试将软链接/usr/lib/i386-linux-gnu/libGL.so.1
指向系统中的各种libGL库文件,但都没有解决问题。
偶然发现
由于笔者每次修改libGL.so.1的指向时都使用如下命令:
mv libGL.so.1 libGL.so.1.backup
ln -s xxx libGL.so.1
某次修改时,因为手误,仅仅进行了mv就再次运行QQ,但意外地成功启动了。至于QQ是直接忽略了该库还是按加载优先级顺序加载了另一优先级较低的库,笔者至今未探明,但这一发现使笔者找到了一种比较hack的方案以启动QQ。
不完美但可用
为了避免妨碍其他程序正常运行,显然不能直接删除libGL.so.1。方便起见,也不能每次运行QQ前都手动mv一遍,等成功启动后再改回来。能直接想到的方案就是写一个启动脚本,每次先mv再启动QQ再mv,但在libGL.so.1所在目录下操作需要sudo获取权限,这也算是另一种麻烦。想要在加载时唯独跳过这个so文件也没有合适的环境变量可供使用。最后可用的方案就是劫持加载so的过程(即dlopen()
函数),使得QQ当且仅当加载libGL.so.1时加载失败。
撰写mydlopen.c如下(参考StackOverflow的某问题,对代码稍作了格式上的修改):
#define _GNU_SOURCE
#include <dlfcn.h>
#include <string.h>
void *dlopen (char const *Fnm, int Flg)
{
void *(*real_dlopen) (char const *, int);
*(void**)(&real_dlopen) = dlsym(RTLD_NEXT, "dlopen");
if (strcmp("libGL.so.1", Fnm) == 0) {
return NULL;
} else {
return real_dlopen(Fnm, Flg);
}
}
使用命令gcc mydlopen.c -fPIC -ldl -shared -m32 -o mydlopen32.so
将其编译为32位动态链接库(需gcc支持multilib,可通过apt-get install gcc-7-multilib
安装支持)。
最后,使用env LD_PRELOAD=/path/to/mydlopen32.so /opt/deepinwine/apps/Deepin-QQ/run.sh
运行QQ。(应用程序菜单中的QQ启动命令可在/usr/share/applications/deepin.com.qq.im.desktop
文件中修改)