文章目录
- 0.问题背景
- 1.程序启动失败常见原因
- 2.排查依赖库问题
- 2.1 依赖库缺失
- 2.2 依赖库加载路径错误
- 2.3 依赖库版本不匹配
- 2.4 QT插件库缺失
- 2.4.1 QT插件库缺失
- 2.4.2 插件库自身的依赖库缺失
- 2.5 系统基础C库不匹配
- 3.资源问题
- 3.1 缺少翻译文件
- 3.2 缺少依赖的资源文件
- 3.3 缺少依赖的可执行程序
- 4.程序权限问题
- 5.运行崩溃问题
0.问题背景
在当前的主流开发语言中Java和web都有成熟的包依赖管理工具,能够轻松的管理程序依赖,然而C++目前仅仅只有像vcpkg和conan这样的开源库构建工具,并没有程序依赖库管理工具。在Linux系统软硬件如此丰富的今天,想一个C++程序能够兼容多个操作系统,是一件很有挑战的事情。下面文章中将要讲到的是平时在实践过程中遇到的一些问题的总结分享,希望能给读者一些启发。
1.程序启动失败常见原因
Linux下程序启动失败的原因主要有几个原因,下面将从每个原因进行具体的分析。
2.排查依赖库问题
2.1 依赖库缺失
通过ldd命令查看依赖库问题的正确步骤,第一步先确认可执行程序的依赖库是否缺失,如果缺失查看缺失依赖库自身的依赖库是否正常,通过一层层查询,基本能定位缺失的依赖库问题。
#查看可执行程序依赖库示例
ldd -d example
#查看动态库的依赖库
ldd -d libQt5Gui.so
依赖库缺失示例:
2.2 依赖库加载路径错误
因为windows和Linux系统机制的问题,Linux默认从系统路径加载动态库,这导致程序启动时加载的不是当前路径下的动态库,如果版本不匹配就会出现程序启动失败。解决这个问题的办法有两个:1.编译动态库时指定需要链接动态库的相对路径;2.通过pathelf命令修改动态库的运行时路径。
2.3 依赖库版本不匹配
依赖库版本不匹配的情况一般有两种情况,第一种动态库编译环境编译时依赖的动态库版本和运行环境中依赖的库版本不同,这就导致运行时库版本不匹配,最常见的问题像libicui18n.so、libicudata.so、libssl等。
2.4 QT插件库缺失
QT自带插件是在使用特定模块时必须依赖的动态库,在发布程序时必须一起发布,但是因为我们在开发阶段因为开发环境的的问题很容易忽视这个问题,导致在纯净环境部署时出现程序因为缺少必须的插件库而无法运行。
2.4.1 QT插件库缺失
解决QT插件库缺失的两种方法,第一种利用经验根据自己使用到的板块拷贝对应的插件到发布目录;第二种方法利用开源工具linuxdeployqt自动拷贝所有依赖的Qt环境到发布目录。
2.4.2 插件库自身的依赖库缺失
QT插件库很多是依赖系统库的,比较典型的是libqxcb.so依赖libxcb-xinput.so,很多系统没有这个依赖环境,因此在打包时我们需要将这个系统依赖库放到我们发布目录进行一起发布。
2.5 系统基础C库不匹配
当我们使用高版本的gcc编译器编译程序在低版本的gcc系统中运行时很容易出现C库找不到的问题,主要是因为使用高版本gcc进行编译时会引入高版本c库的函数,而在低gcc环境上是没有这些函数的,这就导致程序找不到依赖的c库的接口而无法启动。
3.资源问题
3.1 缺少翻译文件
Qt的QWebEngine模块强依赖翻译文件,在缺失翻译文件时程序直接启动失败。解决办法需要将QT安装目录下的translations文件夹放到发布目录的根目录,尤其是其中的qtwebengine_locales文件夹一定不能少。
3.2 缺少依赖的资源文件
Qt的QWebEngine模块强依赖翻译资源文件,在缺失资源文件时程序直接启动失败。解决办法是将QT安装目录下的resources文件夹放到发布目录的根目录。
3.3 缺少依赖的可执行程序
Qt的QWebEngine模块依赖QtWebEngineProcess进程和qwebengine_convert_dict可执行程序,缺少这两个文件程序将无法启动。QtWebEngineProcess是chromium内核的独立进程,为了避免chromium内核崩溃导致主进程崩溃QT设计人员将其独立成了一个单独的进程,所以这个在做嵌入网页的功能时是必不可少的。
4.程序权限问题
权限问题是linux下非常常见的问题,主要有两种操作可能出现权限问题,第一种我们的软件安装是是非root权限安装的软件,第二种是我们替换软件目录的可执行程序导致可执行无运行权限。对于第一种我们只能卸载重装使用有root权限的账号进行安装,第二种情况我们可以使用chmod命令修改权限即可。
5.运行崩溃问题
程序启动运行崩溃看起来像程序运行不起来,这是程序本身代码的问题,有两种方法可以进行排查。第一种拿到程序崩溃生成的core文件使用gdb查看调用栈进行分析,第二种通过strace命令启动应用程序,可以查看详细的程序加载过程。