在Windows平台上,桌面客户端软件通常使用C/C++语言和Qt跨平台开发框架进行开发。因此,大部分代码可以运行于不同平台环境,但是程序运行依赖的三方库以及代码中一些平台相关的头文件和接口需要进行平台兼容。本文以windows桌面端应用迁移到Linux平台桌面端应用为例,简要叙述迁移流程及注意事项。为了迁移后应用程序能够正常运行需要做以下事情:
- 在Linux操作系统上部署C/C++编程语言开发环境;
- 在操作系统上部署Qt开发环境;
- 三方库获取及集成(找对应三方库的接口人,需告知其编译参数);
- 修改Qt工程配置文件(.pro文件)中的配置项,保证其兼容Linux平台;
- 修改工程中平台相关的头文件和接口(解决与平台相关的代码问题);
- 项目各工程编译、链接、测试验证;
- 问题解决,如堆在Windows和Linux上差异性引起的异常崩溃等问题。
一、三方库的获取及集成
迁移前应用程序运行于windows平台,其依赖的第三方库文件也是于windows平台编译的,程序切换到Linux平台后,需要更换所有的三方库文件(Linux平台编译)。在与三方库的接口人对接时,需要告知其编译参数,如本文实例程序迁移到Linux平台的操作系统是x86架构的,所需三方库的
编译链如下:make platform=aarch64-linux-gnu-483 make platform=m64x86
镜像如下:centos6或7上用x86_64的通用编译链
需要更换的三方库如果涉及开源库,如QtXlsx、quazip、jsoncpp等,可以通过GitHub下载对应版本的库源文件,然后使用cmake编译获取。
二、修改工程配置文件(pro文件)
在pro文件中,对于需要区分平台的配置,可以使用win32{…}和unix:!maxc{…}的方式来解决。需要区分不同构建方式的配置,可以使用CONFIG(debug,debug|release){…}else{…}的方式来解决。
需要修改的配置主要包括LIBS和INCLUDEPATH,在Linux平台下,静态库需要同时列出以下两项配置:
PRE_TARGETDEPS += $$PWD/../Linux/Release/Lib/libStreamApp.a
LIBS += -L$$PWD/../Linux/Release/Lib/ -lStreamApp
三、修改头文件和接口
此项修改的难易程度取决于项目在开发初期的设计规划,如果项目需要跨平台兼容,在编写和设计代码模块时,尽量不要使用与平台强相关的头文件和接口,而是选择如 Boost、Qt、STL (标准模板库)等跨平台库或框架。如果实在无法此问题,推荐使用条件编译(如:#ifdef)来区分不同平台的代码。
本文开发实例由于未考虑跨平台兼容问题,在windows平台开发时使用了不少与windows平台强相关的头文件(如windows.h)和接口(如绘图库的绘图接口Draw),导致后期迁移到Linux系统编译运行时出现了很多崩溃问题,特别是如果三方动态库的源代码与平台强相关时,问题可能只会在程序运行过程中使用这些库模块时才会出现,解决这类问题会浪费巨大的人力成本和时间成本!
四、常见问题
4.1 编译出现"cannot find -lGL"错误
当代码中使用了gui、widgets等模块后,在编译时可能会出现错误,这是因为这类模块的头文件中包含了GL/gl.h头文件,此文件是opengl库的,即程序间接依赖opengl库,Qt默认包含了OpenGL库,因此在没有安装OpenGL库时编译Qt程序,则会出现错误。所以我们需要运行命令sudo apt-get install libgl1-mesa-dev安装gl库。
4.2 链接出现“undefined reference”错误
如果遇到“undefined reference”错误,这通常意味着某些符号在链接时未被找到。
第一步检查是否所有必需的库都已添加,并且路径和名称正确无误。
第二步检查库的添加顺序是否正确。在Qt项目中,链接库的添加顺序通常遵循从左到右原则:库的添加顺序通常是从依赖最少的库开始,到依赖最多的库结束。例如,如果你的项目依赖于某个库A,而库A又依赖于库B,那么你应该先添加库B,然后是库A。
第三步检查库是否循环依赖,确保没有循环依赖的情况发生。如果存在循环依赖,尝试重新组织项目结构或调整链接顺序。
4.3 目录路径分隔符问题
可以使用静态函数 QString QDir::toNativeSeparators(const QString & pathName)把目录路径字符串中的斜杠分隔符转换成本地操作系统风格,在引用头文件时也要注意文件路径的斜杠是否正确,在Linux系统中使用正斜杠“/”,尤其是在界面显示时,斜杠的方向应与当前操作系统的风格匹配。
4.4 使用Windows API导致编译或运行失败
某些Windows 应用程序中由于用到了 Windows 平台相关的 API,因而包 含了相应的 Windows 平台开发库的头文件,例如:windows.h,同时也使用了 MSVC 编译器。对于这些应用的迁移,应该首先设法去掉所涉及的 Windows 平台相关 API 及相关头文件、动态库的调用,同时在Linux平台上使用对应的实现方式来进行替代。 也可以使用条件编译(如:#ifdef)来区分不同平台的代码。
4.5 内存耗尽导致程序崩溃的问题
本文实例软件程序涉及大量json数据的读写操作,起初我们使用c++开源库jsoncpp编写处理json的相关代码,这在windows平台下没有发生任何问题,但是在linux平台下出现了内存耗尽程序崩溃的问题,最终定位到崩溃的原因是json读写操作导致的。当我们将程序里所有json处理代码改换为Qt自身携带的json库编写后,崩溃问题得以解决。综上所述,在使用第三方开源库时,应该尽量了解三方库的特性,以防需要耗费大量时间定为问题。