Qt源码编译
- 环境选择
- 编译器说明
- Qt源码版本与下载
- configure选项
- make编译
- 测试编译结果
- 问题记录
环境选择
这里说的环境包括开发板环境和编译系统环境。我用的是orangepi3-lts的板子。可以运行的桌面系统官方提供了几个ubuntu的。有linux4.9,linux5.10和linux5.16几个版本的镜像。下表是一个版本对应关系。
发行板类型 | 内核版本 |
---|---|
Ubuntu 18.04 Bionic | linux4.9 |
Ubuntu 20.04 Focal | linux4.9 |
Ubuntu 20.04 Focal | linux5.10 |
Ubuntu 20.04 Focal | linux5.16 |
Ubuntu 22.04 Jammy | linux5.16 |
系统中确认ldd版本一致,如果不一致最好在虚拟机中装一个对应版本的系统。我的orangepi3-lts原来装的ubuntu20.04,ldd版本是2.31。用ubuntu22.04中的编译工具编译出来提示GLIBC的版本不一样,用不了。没办法把orangepi3-lts也换成22.04才可以的。
# 查看ldd版本
ldd --version
ldd (Ubuntu GLIBC 2.35-0ubuntu9.9) 2.35
# 第一行就是版本信息
# 开发板和编译主系统的GLIBC版本一定要一样不然没有办法运行的
# 也可以通过lsb_release -a查看ubuntu版本
lsb_release -a
编译器说明
orangepi的官方也是提供了编译工具链,如下:
gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu
gcc-arm-9.2-2019.12-x86_64-arm-none-linux-gnueabihf
gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabi
gcc-linaro-5.5.0-2017.10-x86_64_arm-linux-gnueabihf
gcc-linaro-7.4.1-2019.02-x86_64_aarch64-linux-gnu
gcc-linaro-7.4.1-2019.02-x86_64_arm-linux-gnueabi
gcc-linaro-aarch64-none-elf-4.8-2013.11_linux
gcc-linaro-arm-linux-gnueabihf-4.8-2014.04_linux
gcc-linaro-arm-none-eabi-4.8-2014.04_linux
这里主要就用前面两个就可以了,后面有些低版本的有的是用于编译u-boot的。
也可以通过ubuntu自带的软件管理安装。
sudo apt install gcc-10-aarch64-linux-gnu g++-10-aarch64-linux-gnu
# gcc和g++都要安装,有可能装后没有aarch64-linux-gnu-gcc命令,需要用ln链接一下
ln -s /bin/aarch64-linux-gnu-gcc-10 /bin/aarch64-linux-gnu-gcc
# g++也是一样的
由于我的板子是orangepi3-lts用的Allwinner H6的芯片。是一个64位芯片所以用aarch64的编译工具。如果你的开发板芯片是32位的就安装gcc-arm-linux-gnueabi和g+±arm-linux-gnueabi工具链。
为保险起见可以用一个简单的"hello world"测试一下编译工具链和编译系统环境。
// 文件名字main.c
#include <stdio.h>
int main(void){
printf("Hello world/n");
return 0;
}
使用方法:
# 编译
aarch64-linux-gnu-gcc -o main main.c
# 用U盘或者nc命令传到开发板
# 开发板上开启端口,接收main文件
nc -l 开启端口号,1024以上 > main
# 主机上传过去
nc -w 1 开发板IP 开发板端口 < main
# 开发板上运行
chmod +x main
./main
# 正确输出下面内容就没有问题
Hello world
源码版本与下载
从Qt官网下载Qt的源码。目录为archive - qt - 选择一个版本 - 再选择一个小版本 - single - 选择.xz结尾的文件下载。
这里的版本我选择的是5.15下面的版本,怕太新的版本编译器会出问题。一般不同版本不同的编译器也会有不同的问题。
make编译
先将源码文件解压,建立几个必要的文件或文件夹
xz -d qt-everywhere-opensource-src-5.15.5.tar.xz
tar xvf qt-everywhere-opensource-src-5.15.5.tar
# 建立一个保存编译文件的目录
mkdir qt-build
cd qt-build
# 创建一个保存编译好后安装Qt的目录
mkdir qt_install_path
touch auto_compile.sh
写配置脚本
vi auto_compile.sh
#将下面的内容写入到auto_compile.sh
#!/bin/bash
../qt-everywhere-src-5.15.5/configure \
-xplatform linux-aarch64-gnu-g++ \
-prefix ./qt_install_path \
-release -opensource -confirm-license \
-make libs \
-pch \
-qt-libjpeg \
-qt-libpng \
-sql-sqlite \
-qt-zlib \
-no-opengl \
-no-sse2 \
-no-openssl \
-no-cups \
-no-glib \
-no-dbus \
-no-xcb \
-no-pch \
-no-iconv \
-no-xcb-xlib \
-no-separate-debug-info \
-nomake examples -nomake tools \
-no-pkg-config \
-c++std c++17 \
# 这里的选项可以通过Qt源码下 ./configure --help查看。也可以直接网上搜索下这些选项的意义
这里还是简单说下编译选项,第一行是配置脚本文件,位于源码文件目录下,这个一定不能错,错了就没有然后了。
第二行的-xplatform是指定编译主机平台的编译器的,这里面必须要有gcc和g++几个编译器。它是一个目录名称,位置位于Qt源码/qtbase/mkspecs/。这个目录下面有很多平台和编译器版本。之前说过我用的开发板是armv8的64位,所以用的编译器就是aarch64-linux-gnu-gcc。如果你用的编译器不是aarch64-linux-gnu-gcc而是aarch64-none-linux-gnu-gcc,或者是其它32位的交叉编译工具就要在这里更改编译器工具。
比如上面的配置脚本指定的目录就是linux-aarch64-gnu-g++,所以进入这个目录,然后更改qmake.conf
cd linux-aarch64-gnu-g++
vi qmake.conf
# 将最后几行改为自己的编译器,开发板芯片是32位的可以用linux-arm-gnueabi-g++目录
# 下面就是qmake.conf内容,将aarch64-linux-gnu的几行改为自己的编译器,但这里一定要确认此编译器,编译出来的程序可以在你的开发板上运行,不然就白忙活了
#
# qmake configuration for building with aarch64-linux-gnu-g++
#
MAKEFILE_GENERATOR = UNIX
CONFIG += incremental
QMAKE_INCREMENTAL_STYLE = sublib
include(../common/linux.conf)
include(../common/gcc-base-unix.conf)
include(../common/g++-unix.conf)
# modifications to g++.conf
QMAKE_CC = aarch64-linux-gnu-gcc
QMAKE_CXX = aarch64-linux-gnu-g++
QMAKE_LINK = aarch64-linux-gnu-g++
QMAKE_LINK_SHLIB = aarch64-linux-gnu-g++
# modifications to linux.conf
QMAKE_AR = aarch64-linux-gnu-ar cqs
QMAKE_OBJCOPY = aarch64-linux-gnu-objcopy
QMAKE_NM = aarch64-linux-gnu-nm -P
QMAKE_STRIP = aarch64-linux-gnu-strip
load(qt_config)
开始编译
# 进入上面建立的qt-build目录
cd ~/qt-build
# 运行配置脚本
./auto_compile.sh
# 开始编译
make -j 12
# 安装
make install
如果没有出现红色的error就表示运行成功,但往往事与愿违,一般都会出现点错误。我在编译过程中也有遇到几个问题,已经记录在问题记录中。
测试编译结果
进入刚编译好的Qt目录,将Qt安装文件打包,传递到开发板。配置开发板Qt环境。
cd ~/qt-build
tar zcvf qt.tar.gz qt_install_path
# 开发板上开启nc服务器
nc -l 2222 > qt.tar.gz
# 主机上直接将文件传递过去
nc -w 1 192.168.1.101 2222 < qt.tar.gz
# 登录开发板,解压文件
tar zxvf qt.tar.gz
# 配置开发板Qt环境
mv qt_install_path /opt
cd /opt
mv qt_install_path qt5.15.5
vi ~/.bashrc
# 将下面内容加入用户配置文件
export QTDIR=/opt/qt-5.15.5
export QT_QPA_FONTDIR=/usr/share/fonts/truetype/freefont
export QT_QPA_PLATFORM_PLUGIN_PATH=$QTDIR/plugins/
export LD_LIBRARY_PATH=$QTDIR/lib:$LD_LIBRARY_PATH
export QT_QPA_PLATFORM=linuxfb
# 生效配置
. ~/.bashrc
然后就是在主机上安装qtcreator,并设置好gcc和g++工具,这里的gcc和g++就是之前的aarch64-linux-gnu-gcc和aarch64-linux-gnu-g++。再配置好Qt的版本,就是指定qmake位置。本文中应当位于~/qt-build/qt_install_path/bin/
目录下面。然后就是建立一个新的Qt项目,编译后将可执行程序传递到开发板运行。出现界面就表示成功了。
这里只是简单说下qtcreator配置。qtcreator安装就很简单了,直接在上面的qt官方ftp服务器上下载qtcreator的程序,以.run结尾的就是用于linux的。加上执行权限就可以安装了,唯一特别的是要一个Qt官网的账号。
- 打开qtcreator
- 选Tools
- 再选Options,左边选Kits,右边选Compilers
- 点Add,名字写AARCH64-GCC,编译路径写/bin/aarch64-linux-gnu-gcc
- 同样的方法加入一个叫AARCH64-G++的g++交叉编译器
- 再切换到Qt Versions选项,类似的方法加入一个Qt版本。qmake location写
~/qt-build/qt_install_path/bin/qmake
- 最后切换到Kits选项,加入一项。名字随便。Device type: Generic Linux Device, Compiler C: AARCH64-GCC, Compiler C++:AARCH64-G++, Qt Version: Qt 5.15.5(
qt_install_path
)
之后就可以新建立一个项目的,可以在这个项目的.ui文件中加点标签或按钮。左下的绿色三角形图形上方,可以选择Release版本。点左下角最下面的铁锤图标编译。在项目同一个目录中生成编译后的文件。将生成项目同名的可执行文件传递到开发板,加入执行权限就可以看到自己画的界面了。
问题记录
- ubuntu系统中有的版本在进行./configure配置时提示找不到max:啥的,在那个文件的中加入limits头文件就可以了。
#include <limits>
- ubuntu中编译qt5.15.5源码make过程中出现下面提示:
mmm/dev/tools/qt-everywhere-src-5.12.6/qtbase/src/corelib/thread/qatomic.cpp:1624:4: error: #error "Q_ATOMIC_INT64_IS_SUPPORTED must be defined on a 64-bit platform"
# error "Q_ATOMIC_INT64_IS_SUPPORTED must be defined on a 64-bit platform"
^~~~~
In file included from /home/mmm/dev/tools/qt-everywhere-src-5.12.6/qtbase/include/QtCore/qglobal.h:1:0,
from /home/mmm/dev/tools/qt-everywhere-src-5.12.6/qtbase/src/corelib/global/qt_pch.h:56:
/home/mmm/dev/tools/qt-everywhere-src-5.12.6/qtbase/include/QtCore/../../src/corelib/thread/qbasicatomic.h: In instantiation of ‘class QBasicAtomicInteger<long int>’:
/home/mmm/dev/tools/qt-everywhere-src-5.12.6/qtbase/include/QtCore/../../src/corelib/thread/qatomic.h:55:7: required from ‘class QAtomicInteger<long int>’
/home/mmm/dev/tools/qt-everywhere-src-5.12.6/qtbase/src/corelib/thread/qatomic.cpp:1631:1: required from here
/home/mmm/dev/tools/qt-everywhere-src-5.12.6/qtbase/include/QtCore/../../src/corelib/global/qglobal.h:121:49: error: static assertion failed: template parameter is an integral of a size not supported on this platform
# define Q_STATIC_ASSERT_X(Condition, Message) static_assert(bool(Condition), Message)
^
/home/mmm/dev/tools/qt-everywhere-src-5.12.6/qtbase/include/QtCore/../../src/corelib/thread/qbasicatomic.h:97:5: note: in expansion of macro ‘Q_STATIC_ASSERT_X’
Q_STATIC_ASSERT_X(QAtomicOpsSupport<sizeof(T)>::IsSupported, "template parameter is an integral of a size not supported on this platform");
^~~~~~~~~~~~~~~~~
/home/mmm/dev/tools/qt-everywhere-src-5.12.6/qtbase/include/QtCore/../../src/corelib/thread/qbasicatomic.h: In instantiation of ‘class QBasicAtomicInteger<long unsigned int>’:
/home/mmm/dev/tools/qt-everywhere-src-5.12.6/qtbase/include/QtCore/../../src/corelib/thread/qatomic.h:55:7: required from ‘class QAtomicInteger<long unsigned int>’
/home/mmm/dev/tools/qt-everywhere-src-5.12.6/qtbase/src/corelib/thread/qatomic.cpp:1632:1: required from here
/home/mmm/dev/tools/qt-everywhere-src-5.12.6/qtbase/include/QtCore/../../src/corelib/global/qglobal.h:121:49: error: static assertion failed: template parameter is an integral of a size not supported on this platform
# define Q_STATIC_ASSERT_X(Condition, Message) static_assert(bool(Condition), Message)
^
/home/mmm/dev/tools/qt-everywhere-src-5.12.6/qtbase/include/QtCore/../../src/corelib/thread/qbasicatomic.h:97:5: note: in expansion of macro ‘Q_STATIC_ASSERT_X’
Q_STATIC_ASSERT_X(QAtomicOpsSupport<sizeof(T)>::IsSupported, "template parameter is an integral of a size not supported on this platform");
可以看到有2个问题,第一个问题是提示有一个宏没有定义所以打开qt-everywhere-src-5.15.5/qtbase/src/corelib/thread/qatomic.cpp
文件。在其中加入一个宏#define Q_ATOMIC_INT64_IS_SUPPORTED
第2个问题是说C++11中的一个静态断言出错了。一旦一个断言出错就不能继续下去。试了几下,只有最粗暴的方式能搞定。将# define Q_STATIC_ASSERT_X(Condition, Message) static_assert(bool(Condition), Message)
中的Condition直接改成1,不可能再出错。有没有后续问题我就不知道了。改后的样子# define Q_STATIC_ASSERT_X(Condition, Message) static_assert(bool(1), Message)
。文件位置差点忘记说了qt-everywhere-src-5.15.5/qtbase/include/QtCore/../../src/corelib/global/qglobal.h
3. Windows中的ububtu子系统编译5.15.7的源码提示找不到qBound(double, float, double)。网上找到是因为Armv8 的float是32位,double是64位。所以在编译时加入选项-qreal double选项。