前言:
现时同学们对“丢失qt5network”大体比较关怀,兄弟们都想要学习一些“丢失qt5network”的相关知识。那么小编在网摘上网罗了一些关于“丢失qt5network””的相关内容,希望小伙伴们能喜欢,朋友们快快来了解一下吧!整个Linux底层基于gcc 编译器编译C和C++程序构造的,因此 gcc 通用c类库是最基本,最重要的类库,称为glibc库.不仅一般的应用程序,各种操作系统的命令行工具也是基glibc的构建的.
在部署C/C++应用时,经常碰到这样问题,就是开发环境 的glibc版本较高,但是实际部署的运行环境 有的glibc,版本高,有的glibc版 本低,强行运行会显示如下提示,
./ResolverService: /lib/aarch64-linux-gnu/libc.so.6: version GLIBC_2.28' not found (required by /usr/lib/libQt5Network.so.5)
这就是因为运行环境 最高支持GLIBC 2.26,而程序是在2.31的环境 编译的,这是一个非常常见的问题.如何解决?
高成本解决方案
升级系统glibc库
最容易想到是升级系统glibc库,这危险性相当于自己给自己做心脏手术,基本做到一半,所有系统工具都无法工作,导致系统崩掉,只能重装系统,所以严重不推荐.
使用虚拟机环境
在服务端部署经常采用的办法,就是在操作系统之上再运行一层虚拟机,比如 Docker,KVM,在虚拟机运行是统一glibc库版 本,这个方法缺点就需要系统资源较多,安装成本比较高.在嵌入式Linux下并不适用.
低成本解决办法 -- 修改应用程序
解决的思路就是让应用程序 不去装载默认glibc的入口程序 ,一般固定是在/lib目录下,通常是名字是 ld-linux打头动态库文件.
转而让应用程序 去寻找用户自己安装的glibc目录下的装载程序.
这个方法只需在用gcc编译应用程序,链接选项就可以一次性解决所有动态库版本不符问题,而且哪怕你没有源码只有运行程序,也可以同样用patchelf这个工具 给应用程序 打补丁即可.代价非常低.
比如我一个QT应用程序 ,使用了几十个Qt 的so动态库,很多都 引用高版本的glibc函数,只需要在编译最终应用程序加一句就行.不需要重新编译Qt类库,是不是很方便?
步骤1:准备高版本的glibc
可以在安装高版本的环境直接把文件拷出来即可,比如我ARM64板上glibc 2.31需要如下库,其中 ld-linux-aarch64.so.1 就是入口可执行,假设我把这一些文件放在 /home/hxy/glibc-2.31 目录下.大体有如下文件
ld-2.31.so libc.so.6 libpthread.so.0ld-linux-aarch64.so.1 libdl-2.31.so libresolv-2.31.solibc-2.31.so libdl.a libresolv.alibc.a libdl.so libresolv.solibc_nonshared.a libdl.so.2 libresolv.so.2libcrypt.a libgcc_s.so.1 librt-2.31.solibcrypto.so.1.1 libm-2.31.so librt.alibcryptsetup.so.12 libm.a librt.solibcryptsetup.so.12.5.0 libm.so librt.so.1libcrypt.so libm.so.6 libstdc++.so.6libcrypt.so.1 libpthread-2.31.so libstdc++.so.6.0.28libcrypt.so.1.1.0 libpthread.alibc.so libpthread.so
找不到对应glibc动态库,可以这个开源项目下 取得自己的想要的版本编译一下.或者直接搜索相应的 deb安装包
步骤2: 编译时加入对另一版本glibc 的引用
需要增加两个gcc 的链接参数:
显式链接指定动态库加载器 -Wl,--dynamic-linker
显式链接是相对用 -L -l c 隐式链接而言, 隐式链接就是编译后的应用程序ELF可执行文件只保存链接库名字,不带路径,加径顺序按缺省规则来进行. 一般是 /lib --> ld.so.conf-->LD_LIBRARY_PATH 这样顺序进行.而使用--dynamic-linker表示这是带路径动态库加载器直接装入即可.
在我的例子是,这样就跳开了/lib下同名动态glibc入口的引用,直接引用我的目录名字
-Wl,--dynamic-linker=/home/hxy/glibc-2.31/ld-linux-aarch64.so.1
2.指定动态库的装载目录 -Wl,--rpath
相当其它未带路径so,优先从这个目录装入,这一句也很重要因为ld-linux-xxx.so动态库需要装入同目录下其它glibc的动态,因此必须设置这个目录,否则又去装入/lib的动态库导致运行失败
-Wl,--rpath=/home/hxy/glibc-2.31/
以上两句是要同时放在一个链接语句当中,顺便提一下,如果你是Linux 下Qt 项目,只需在pro文件增加一句QMAKE_LFLAGS的定义即可在最终的编译语句达到这样效果
QMAKE_LFLAGS = -Wl,--dynamic-linker=/home/hxy/glibc-2.31/ld-linux-aarch64.so.1 \ -Wl,--rpath=/home/hxy/glibc-2.31/
编译好在目标主机上也建立一个/home/hxy/glibc-2.31 并放入动态库.即可运行
补充步骤2: 只有可执行文件 ,用patchelf 打补丁
当没有源码编译或者编译很麻烦的情况,可以直接对可执行elf文件打补丁加上上述两个参数,效果一样的 ,首先安装patchelf
sudo apt-get install patchelf
elf 的interpreter字段是指明动态加载器路径,修改这个字段的作用等同于 -Wl,--dynamic-linker
rpath字段就是对应-Wl,--rpath的内容,假设应用程序名叫ResolverService,补丁指令如下
patchelf --set-interpreter /home/firefly/glibc-2.31/ld-linux-aarch64.so.1
--set-rpath /home/firefly/glibc-2.31 ResolverService
以上两种方法bluedrum即在RK3399的高版本环境运行成功,同时又能切换到RK3308低版 本下环境 运行.
标签: #丢失qt5network