Qt5.9.6未遵循RPATH搜索OpenSSL动态库问题咨询
问题描述
我在Linux系统上开发基于Qt 5.9.6的项目,启动应用时Qt输出如下报错日志:
qt.network.ssl: Incompatible version of OpenSSL
排查确认Qt当前加载的是OpenSSL 1.1版本,但Qt 5.9.6依赖的OpenSSL版本为1.0.2k。我将版本匹配的OpenSSL库存放在应用程序同级目录,配置了RPATH但未生效;使用LD_LIBRARY_PATH指定库路径时可以正常加载。
通过LD_DEBUG=libs查看程序动态库加载搜索路径,发现Qt加载动态库时仅部分遵循、甚至完全不遵循RPATH配置。
我制作了名为eaglejoe/qtopenssl-bug的Docker镜像,内置最小复现示例,可通过如下命令编译示例:
cmake --preset default cmake --build build
编译完成后执行build/testqt即可启动测试程序。
注:示例中默认使用的是RUNPATH,切换为RPATH测试时仍存在相同问题。
原因说明
RPATH/RUNPATH未生效的核心原因是Qt 5.9加载OpenSSL的方式是运行时调用dlopen动态加载,而非编译链接阶段就写入可执行文件的直接依赖项,动态链接器对这类动态加载库的搜索逻辑和直接依赖库完全不同:
- 搜索优先级第一的是
LD_LIBRARY_PATH指定的路径,这也是用这个环境变量可以正常加载的原因 - RUNPATH属性只对当前二进制文件的直接依赖库生效,对
dlopen动态加载的库完全无效,这是用RUNPATH不生效的直接原因 - 即使把属性改成RPATH,动态链接器处理
dlopen请求时,只会读取发起dlopen调用的二进制文件自身的RPATH配置,不会读取主程序的RPATH。Qt里发起OpenSSL加载调用的是libQt5Network.so.5这个共享库,只给主程序testqt配置RPATH,完全不会被这个加载流程识别到,这就是切了RPATH还是不生效的根本原因。
用LD_DEBUG=libs看到的RPATH搜索路径,是主程序加载自身直接依赖库时的路径,和Qt加载OpenSSL时的搜索上下文不是同一个,自然看不到配置的路径。
可行解决方案
- 方案1:启动程序前通过
LD_LIBRARY_PATH指定存放OpenSSL 1.0.2库的目录,这个方案零改造成本,已经验证过可用性,适合快速部署 - 方案2:用
patchelf工具给libQt5Network.so.5.9.6设置RPATH,指向存放OpenSSL库的目录,示例命令:
命令中# 假设libQt5Network.so和自带的OpenSSL库都在应用同级的lib目录下 patchelf --set-rpath '$ORIGIN' ./lib/libQt5Network.so.5.9.6$ORIGIN代表当前被修改的二进制文件自身所在的目录,可以根据库存放位置调整相对路径 - 方案3:如果是容器等隔离环境,可以把自带的OpenSSL库路径写入
/etc/ld.so.conf.d/下的自定义配置文件,执行ldconfig刷新系统动态库缓存,让系统优先找到提供的1.0.2版本库,不建议在物理机环境使用这个方案,避免影响全局库依赖 - 方案4:重新编译Qt 5.9.6,编译时通过configure参数指定OpenSSL 1.0.2的路径,让Qt网络模块直接链接对应版本的OpenSSL,从根源避免动态搜索的问题,缺点是重编Qt时间成本较高。
内容的提问来源于stack exchange,提问作者Stiven
相关产品推荐
相关产品推荐

