搞了一周,把所有的坑都跳了一遍,最后放弃了。
由于一开始不清楚目标机的情况,就直接在 ubuntu20.04 里装了 Qt5.14.2 开发程序,程序开发完目标机才到,一看是银河麒麟aarch64架构,就开始交叉编译吧。
照着博友提示,下载了 gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu.tar.xz
又下载了Qt5.14.2 源码,一套操作编译成功,这里不详述,只想说版本问题。
移植到目标机,运行程序,提示GLIBC_的版本不对, /lib/aarch64-linux-gnu/libm.so.6: version `GLIBC_2.29' not found (required by /opt/Qt-5.14.2-aarch64/lib/libQt5Widgets.so.5)
敲命令 strings /lib/aarch64-linux-gnu/libc.so.6 | grep GLIBC_ 和 gcc --version 一看版本才5.4,又上网查不能随便给目标机升级gcc版本,有可能会导致系统崩溃,一想也是,可能麒麟的桌面就是5.4编译的,看来只能降低交叉编译的版本了。不然10.3编译的库,5.4提供的链接器去连接动态库新特性怎么能支持呢。
看了看各个版本的时间,下载了gcc-linaro-5.3.1-2016.05-x86_64_aarch64-linux-gnu.tar.xz
交叉编译QT,再搞一遍!! 很不幸make时报错,有些语法编译器不支持,查了下qt5.14需要gcc7.3才能支持。
无奈降低qt的版本吧。银河麒麟默认安装的是Qt5.6.1版本,又交叉编译QT OK。发现编译现在程序缺少好几个模块的支持,哭啊
。最后只能改程序了,看来跨平台移植还是要用低版本,怪不得QT4.8.6还有人用。下次还是先搞清楚目标机情况再开发吧。
最后得出的结论: 移植效率 = 网速 + CPU核数
============再更新一下
秉着不抛弃不放弃原则,查到GCC5.3.1可以编译QT5.7.0, QT5.7支持我用到的qtchart模块,用gcc5.3.1把qt5.7.0源码再次交叉编译,再交叉编译程序,移植到麒麟V10上,运行又报错,但是感觉报错内容已经发生变化,于是交叉编译了一个qt示例analogclock,复制到麒麟上,运行成功了
。再看我的程序报错是 /dev/fb0 权限拒绝,sudo -s切到root账号,重新source env.sh,程序启动起来了。界面没显示出来。。。
=============
又经过不断测试验证,发现在麒麟V10用QPA设置为linuxfb行不通,学习了一下发现 linuxfb 只适用于嵌入式linux(液晶屏那种,没有桌面操作系统的),界面图像数据直接写到framebuffer就能显示。银河麒麟V10白皮书写的窗口系统基于Xserver 和 xwayland 实现的,wayland需要xcb的支持,我艹好大一个坑,qt又要重新交叉编译,还要支持xcb,xcb还需要一系列的库,可自行搜索。我推荐一个连接
===============
搞了好久也没编译全xcb相关的库,太难了,果断放弃。
起始不编译xcb软件也能在银河麒麟上运行,麒麟是基于xcb实现的,当然系统自带xcb的支持,就在 /usr/lib/aarch64-linux-gnu/qt5 里面。只需要补全自己用的其他库就好了。又东拼西凑了一把库,果然软件能运行了。结果又出了新问题,串口不能用,一关闭就崩溃,报段错误,实在是难定位,最后索性在麒麟上装了qt5.7,直接debug源码,提示报错 “ RTTI symbol not found for class 'QObject' ”,又挖着了个坑。
原因是在调用deleteLater() 后,调试执行到析构函数中 报错,调用了两次析构函数
为啥析构了两遍,
connect(m_serialThread,&QThread::finished,m_serialport,&MySerialport::deleteLater);
connect(m_serialThread,&QThread::finished,m_serialThread,&QThread::deleteLater);
这是错误写法
connect(m_serialThread,&QThread::finished,m_serialport,&QObject::deleteLater);
connect(m_serialThread,&QThread::finished,m_serialThread,&QObject::deleteLater);
正确写法,就差在QObject的deleteLater。我在qt5.14中不存在这个问题,但是移植后用qt5.7就有这个问题。 关键在于调用QObject的析构后会自动析构子类,如果调用的子类的deleteLater相当于进入了子类的析构函数中,会先执行父类析构,再执行子类析构,但是设备已经释放了就会报错。
=========================
后来还发现装个qmenu替代VMware可以直接跑arm64的麒麟系统,qmenu模拟硬件,不过弄起来也麻烦,据说还很卡,没走这条路。
最后总结一下,移植到aarch64,找到目标机gcc版本后,找个别人软件的包,包里有依赖的库,比如说海康的客户端MVS也是用qt开发的,然后查看一下他的库的版本,下载对应qt的源码交叉编译,把依赖的库凑一下就可以了
是不是捷径。如果还有差的库可以从目标机的/usr下找拷过来,比自己一个个编译强。