64位Intel/AMD 架构的Ubantu上安装Qt6.5.3

环境:x86_64 22.04.1-Ubuntu

  1. 安装Qt Online Installer for Linux (x64):
# 具体地址可能会变,参考https://my.qt.io/download
wget https://d13lb3tujbc8s0.cloudfront.net/onlineinstallers/qt-online-installer-linux-x64-4.10.0.run
  1. 为在线安装器新增可执行权限:
chmod a+x qt-online-installer-linux-x64-4.10.0.run
  1. 一次性安装xcb,xkb,Vulkan相关库
# 更新包列表
sudo apt-get update

# 安装gcc,g++等工具
sudo apt-get install build-essential

# 安装xcb相关库
sudo apt install libxcb-cursor0 libxcb-cursor-dev

# 安装 XKB 开发包
sudo apt install -y libxkbcommon-dev libxkbcommon-x11-dev

# 安装 Vulkan 开发包
sudo apt install -y libvulkan-dev vulkan-tools

# 安装OpenGL 开发包
sudo apt install libgl1-mesa-dev libglu1-mesa-dev freeglut3-dev
  1. 安装
# 指定阿里云镜像
./qt-online-installer-linux-x64-4.10.0.run  --mirror https://mirrors.aliyun.com/qt/
  1. 环境变量配置:

    1. 在.bashrc文件末尾中新增如下内容
    # cmake的安装路径
    export PATH="/home/wzh/Qt/Tools/CMake/bin:$PATH"
    # 根据你的 Qt 版本调整
    export QTDIR="/home/wzh/Qt/6.5.3/gcc_64"  
    # 目录下有一些工具,比如文档助手,设置这个环境变量可以方便打开
    export PATH="$QTDIR/bin:$PATH"
    # Qt 库路径,运行程序时,除了默认路径外,也要去Qt的库目录进行寻找
    export LD_LIBRARY_PATH="$QTDIR/lib:$LD_LIBRARY_PATH"
    # 查找Qt6Config.cmake等配置文件的路径
    export CMAKE_PREFIX_PATH="$QTDIR/lib/cmake:$CMAKE_PREFIX_PATH"
    
    1. 使配置生效
    source ~/.bashrc
    
  2. 创建一个QWidgets项目,项目名称叫做test,然后在包含CMakeLists.txt配置文件的目录下依次执行如下命令,如果成功则表示Qt安装成功。

mkdir build && cd build
cmake ..
make -j 2
./test

交叉编译环境搭建

需求:现在想要在64位Intel/AMD 架构的Ubantu上编译Qt程序,使得程序可以在64位或者32位ARM架构的机器上运行

  1. 安装ARM GUN的工具链,用于交叉编译
# 默认下载的gcc version 11.4.0
sudo apt-get install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
  1. 安装完成以后查看一下gcc,g++的位置
wzh@wzh:~$ which  aarch64-linux-gnu-gcc
/usr/bin/aarch64-linux-gnu-gcc
wzh@wzh:~$ which  aarch64-linux-gnu-g++
/usr/bin/aarch64-linux-gnu-g++
  1. 在https://download.qt.io/archive/qt/地址上下载指定Qt版本的源码包,并解压
wget https://download.qt.io/archive/qt/6.5/6.5.3/single/qt-everywhere-src-6.5.3.tar.xz

tar -xvf qt-everywhere-src-6.5.3.tar.xz
  1. 查看源码目录下可用的qt模块:
ls xxx/qt-everywhere-src-6.5.3/ | grep ^qt
  1. 查看configure脚本可用参数:
xxx/qt-everywhere-src-6.5.3/configure -help
  1. 与源码同级的目录下新建一个build目录,这个目录下新建一个toolchain.cmake,如下所示:
# 设置目标系统、处理器架构
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm64)

# 设置工具链目录
set(TOOL_CHAIN_DIR /usr/bin)

# 设置编译器位置
set(CMAKE_C_COMPILER ${TOOL_CHAIN_DIR}/aarch64-linux-gnu-gcc)
set(CMAKE_CXX_COMPILER ${TOOL_CHAIN_DIR}/aarch64-linux-gnu-g++)

# 验证编译器是否存在
if(NOT EXISTS ${CMAKE_C_COMPILER})
    message(FATAL_ERROR "Compiler not found: ${CMAKE_C_COMPILER}\n"
                        "Please install: sudo apt install gcc-aarch64-linux-gnu")
endif()

# 设置根查找路径
set(CMAKE_FIND_ROOT_PATH /usr/aarch64-linux-gnu)


# 程序(如编译工具)在主机路径查找
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)

# 库文件只在 sysroot 中查找
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)

# 头文件只在 sysroot 中查找
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

# 包配置只在 sysroot 中查找
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

# ============================================================================
message(STATUS "=== Cross-compilation toolchain loaded ===")
message(STATUS "Target system: ${CMAKE_SYSTEM_NAME} (${CMAKE_SYSTEM_PROCESSOR})")
message(STATUS "C compiler: ${CMAKE_C_COMPILER}")
message(STATUS "CXX compiler: ${CMAKE_CXX_COMPILER}")
message(STATUS "Sysroot: ${CMAKE_SYSROOT}")

  1. 生成Makefile:
    1. 使用命令如下:
    # -prefix:指定安装路径,编译后的库、头文件、工具会安装到这里
    # -submodules:表示指定需要编译的库
    # -platform <target>:表示指定交叉编译平台 Select mkspec for the qmake companion files
    # -device <name> :Select devices/mkspec for the qmake companion files
    # -skip:表示跳过某个模块,不进行编译。比如-skip qtdeclarative表示不需要编译QML模块
    # -no-opengl:表示禁用 OpenGL
    # -sysroot <dir>   设置 <dir> 作为目标系统的根目录
    # -qt-host-path <path> . Specify path to a Qt host build for cross-compiling.
    # -tslib  Enable tslib support [auto](tslib为支持触摸屏设备的库)
    # -sysroot <dir> ....... Set <dir> as the target sysroot
    # -I <string> .......... Pass additional include path
    # -L <string> .......... Pass additional library path
    
    # 默认编译为动态库
    ../qt-everywhere-src-6.5.3/configure \
    -prefix /home/wzh/Qt_Arm/qt_arm_installtion \
    -platform linux-aarch64-gnu-g++ \
    -device linux-aarch64-gnu-g++ \
    -submodules qtbase,qtdeclarative \
    -qt-host-path /home/wzh/Qt/6.5.3/gcc_64\
    -no-opengl\
    -DCMAKE_GENERATOR=Ninja \
    -- -DCMAKE_TOOLCHAIN_FILE=/home/wzh/Qt_Arm/build/toolchain.cmake | tee log.txt
    
    1. note:执行qt-everywhere-src-6.5.3/configure脚本,实际执行的是qt-everywhere-src-6.5.3/qtbase/configure脚本
    #! /bin/sh
    # Copyright (C) 2020 The Qt Company Ltd.
    # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
    
    # 获取脚本所在的目录路径
    srcpath=`dirname $0`
    # 将相对路径转换为绝对路径
    srcpath=`(cd "$srcpath"; pwd)`
    # 构建实际的 configure 脚本路径
    configure=$srcpath/qtbase/configure
    # 检查 qtbase/configure 脚本是否存在
    if [ ! -e "$configure" ]; then
        echo "$configure not found. Did you forget to run \"init-repository\"?" >&2
        exit 1
    fi
    
    set -ex
    
    mkdir -p qtbase
    cd qtbase
    
    # 执行实际的configure 脚本路径,$@表示传递所有命令行参数(保持引号)
    exec "$configure" -top-level "$@"
    
  2. 编译,日志信息保存到build.log中:
# 方式1

# 2>&1:标准错误输出合并到标准输出
# tee表示用于从标准输入读取数据,并将其同时输出到标准输出和一个或多个文件中
make -j2 2>&1 | tee build.log

# 方式2
cmake --build . --parallel
  1. 安装
# 方式1
make install
# 方式2
make --install .
  1. 查看编译完成后的动态库的信息:
file libQt6QmlCompiler.so.6.5.3
libQt6QmlCompiler.so.6.5.3: ELF 64-bit LSB shared object, ARM aarch64, version 1 (GNU/Linux), dynamically linked, BuildID[sha1]=7c0d32a983bbabcbd056e510a9ef43ae27768e8f, not stripped

交叉编译环境测试

qmake管理的项目工程
  1. 在Qt Creator中新建一个构建套件,方便创建项目。注意设置正确的c/c++编译器,Qt版本,sysroot,调试器
  2. 创建一个项目,使用qmake进行管理
  3. 编译后产生一个可执行文件,然后使用file命令查看该可执行文件的信息
cmake管理的项目工程
  1. cmake配置如下:
cmake_minimum_required(VERSION 3.19)

# 设置目标系统、处理器架构
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm64)
# 设置交叉工具链目录
set(TOOL_CHAIN_DIR /usr/bin)

set(CMAKE_SYSROOT /usr/aarch64-linux-gnu)

# 设置编译器位置
set(CMAKE_C_COMPILER ${TOOL_CHAIN_DIR}/aarch64-linux-gnu-gcc)
set(CMAKE_CXX_COMPILER ${TOOL_CHAIN_DIR}/aarch64-linux-gnu-g++)

# 验证编译器是否存在
if(NOT EXISTS ${CMAKE_C_COMPILER})
    message(FATAL_ERROR "Compiler not found: ${CMAKE_C_COMPILER}\n"
                        "Please install: sudo apt install gcc-aarch64-linux-gnu")
endif()

# 设置Qt6的安装位置
set(Qt6_INSTALLATION /home/wzh/Qt_Arm/qt_arm_installtion)
set(Qt6_DIR "${Qt6_INSTALLATION}/lib/cmake/Qt6")


# 设置根查找路径
set(CMAKE_FIND_ROOT_PATH
    ${CMAKE_SYSROOT}
    ${Qt6_INSTALLATION}
)

# 程序(如交叉编译工具)在主机路径查找
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# 库文件只在 sysroot 中查找
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
# 头文件只在 sysroot 中查找
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
# 包配置只在 sysroot 中查找
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)


project(test_arch64 LANGUAGES CXX)

# ============================================================================
message(STATUS "=== Cross-compilation toolchain loaded ===")
message(STATUS "Target system: ${CMAKE_SYSTEM_NAME} (${CMAKE_SYSTEM_PROCESSOR})")
message(STATUS "C compiler: ${CMAKE_C_COMPILER}")
message(STATUS "CXX compiler: ${CMAKE_CXX_COMPILER}")
message(STATUS "Sysroot: ${CMAKE_SYSROOT}")
# 打印Qt版本信息
message(STATUS "Qt6 version: ${Qt6_VERSION}")
message(STATUS "Qt6 found at: ${Qt6_DIR}")


find_package(Qt6 6.5 REQUIRED COMPONENTS Core Widgets)


# 内部设置cxx标准,启用moc,uic,rcc工具支持
qt_standard_project_setup()

qt_add_executable(test_arch64
    WIN32 MACOSX_BUNDLE
    main.cpp
    mainwindow.cpp
    mainwindow.h
    mainwindow.ui
)

target_link_directories(test_arch64 PRIVATE
    ${Qt6_INSTALLATION}/lib     # 显式添加Qt库路径
    ${CMAKE_SYSROOT}/lib
)


target_link_libraries(test_arch64
    PRIVATE
        Qt::Core
        Qt::Widgets
)
  1. 编译生成可执行程序
cmake xxx
make -j2
  1. 使用cmake生成Makefile的过程中报错:
    1. 报错信息如下:实际上我的libc_nonshared.a,libc.so.6,ld-linux-aarch64.so.1都是在的。
    /usr/lib/gcc-cross/aarch64-linux-gnu/11/../../../../aarch64-linux-gnu/bin/ld: cannot find /usr/aarch64-linux-gnu/lib/libc.so.6 inside /usr/aarch64-linux-gnu
    /usr/lib/gcc-cross/aarch64-linux-gnu/11/../../../../aarch64-linux-gnu/bin/ld: cannot find /usr/aarch64-linux-gnu/lib/libc_nonshared.a inside /usr/aarch64-linux-gnu
    /usr/lib/gcc-cross/aarch64-linux-gnu/11/../../../../aarch64-linux-gnu/bin/ld: cannot find /usr/aarch64-linux-gnu/lib/ld-linux-aarch64.so.1 inside /usr/aarch64-linux-gnu
    collect2: error: ld returned 1 exit status
    
    1. 修改sysroot目录/lib目录下的libc.so文件:sudo vim libc.so
    /* GNU ld script
       Use the shared library, but some functions are only in
       the static library, so try that secondarily.  */
    OUTPUT_FORMAT(elf64-littleaarch64)
    /*GROUP ( /usr/aarch64-linux-gnu/lib/libc.so.6 /usr/aarch64-linux-gnu/lib/libc_nonshared.a  AS_NEEDED ( /usr/aarch64-linux-gnu/lib/ld-linux-aarch64.so.1 ) )*/
    GROUP ( libc.so.6 libc_nonshared.a  AS_NEEDED ( ld-linux-aarch64.so.1 ) )