Edit online

QT Cross Compile

Read time: 7 minute(s)

建立 git 仓库进行跟踪

因为在编译的时候会对 QT 进行部分的代码修改,建立仓库可以很好的跟踪修改记录

.gitignore 会把一些不需要的中间文件不进行跟踪
git init
git add *
vim .gitignore
git add .gitignore
git commit -m "init"

cat .gitignore
*.a
*.asn1.[ch]
*.bin
*.bz2
*.dwo
*.elf
*.gcno
*.gz
*.i
*.ko
*.lex.c
*.ll
*.lst
*.lz4
*.lzma
*.lzo
*.o
*.o.*
*.s
*.so
*.so.dbg

配置编译工具链

工具链的配置建议使用 qt 提供的 qmake 机制进行配置,配置文件在 mkspecs/qws目录下,通过两个文件完成配置
cd mkspecs/qws/
cp -r linux-arm-gnueabi-g++ linux-riscv-gnueabi-g++
cd linux-riscv-gnu-g++/
  1. qplatformdefs.h
    • QT 代码本身兼容 32 位和 64 位,因此对于 64 位 CPU,不需要进行过多的设置
    • qplatformdefs 进行一些基础的数据变量的定义,如 type,ipc 等,和 linux 平台的关联性更强,和 riscv 的关联性没有
      cat qplatformdefs.h
      #include "../../linux-g++-64/qplatformdefs.h"
      
      cat ../../linux-g++-64/qplatformdefs.h
      #include "../linux-g++/qplatformdefs.h"
  2. qmake.conf
    • qmake 配置了交叉编译的工具链信息,是交叉编译的主要
    • qmake 并没有指定工具链的路径,因此需要编译前把路径手工加入到 PATH 环境变量
    • export PATH=/xxx/d211/bin/:$PATH
    • 包含工具参数的定义:QMAKE_COPY = cp -f
    • qws.conf 中定义基础功能:QT += core gui network
    #
    # qmake configuration for building with arm-none-linux-gnueabi-g++
    #
    
    include(../../common/linux.conf)
    include(../../common/gcc-base-unix.conf)
    include(../../common/g++-unix.conf)
    include(../../common/qws.conf)
    
    # modifications to g++.conf
    QMAKE_CC                = riscv64-unknown-linux-gnu-gcc
    QMAKE_CXX               = riscv64-unknown-linux-gnu-g++
    QMAKE_LINK              = riscv64-unknown-linux-gnu-g++
    QMAKE_LINK_SHLIB        = riscv64-unknown-linux-gnu-g++
    
    # modifications to linux.conf
    QMAKE_AR                = riscv64-unknown-linux-gnu-ar cqs
    QMAKE_OBJCOPY           = riscv64-unknown-linux-gnu-objcopy
    QMAKE_STRIP             = riscv64-unknown-linux-gnu-strip
    
    load(qt_config)
  3. 环境变量

    和传统的交叉编译不同,QT 采用的是 QMake 进行系统编译,编译方案是先进行一些 Host 的工具编译(采用 CC),再进行交叉编译(采用 CC),因此在设置环境变量时, 只可以添加交叉编译工具链到 PATH,设置 CC, 绝对不能设置 CC 的传统的交叉编译变量,否则出现莫名的问题。

    如果需要 directfb 的支持,则需要明确指定一下 directfb 的路径,导如下两个环境变量
    export QT_CFLAGS_DIRECTFB="-I/xxx/install/include/directfb/"
    export QT_LIBS_DIRECTFB="-L/xxx/install/lib -ldirectfb -lfusion -ldirect -lpthread -lz"

编译

  1. configure
    • 用最简单的编译方式编译,大部分功能先 disable,如果需要再打开

    • 通过-xplatform qws/linux-arm-gnueabi-g++指定交叉编译工具链

    • configure 完成后会生成 Makefile

    • make distclean 命令无效,无法清除生成的 Makefile

    ./configure -opensource -confirm-license -xplatform qws/linux-riscv-gnueabi-g++ \
    -prefix /xxx/install -plugin-gfx-directfb -no-qt3support \
    -nomake demos -nomake examples -no-glib -depths 8,16,32 -qt-gfx-linuxfb -no-gfx-transformed \
    -no-gfx-qvfb -no-gfx-vnc -no-gfx-multiscreen -no-mouse-pc -no-mouse-linuxtp -no-mouse-linuxinput \
    -no-mouse-tslib -no-mouse-qvfb -no-kbd-tty -no-kbd-linuxinput -no-kbd-qvfb -release -shared \
    -little-endian -embedded arm -no-gif -no-libmng -no-accessibility  -no-libjpeg -no-libtiff -no-freetype \
    -no-openssl -no-opengl -no-sql-sqlite -no-xmlpatterns -no-multimedia -no-audio-backend -no-phonon \
    -no-phonon-backend -no-svg -no-webkit -script -no-scripttools -no-stl -no-declarative -no-pch \
    -no-xinerama -no-cups -no-nis -no-separate-debug-info -fast -no-rpath
  2. swpb 汇编
    我们的工具链没有提供 swpb 汇编,需要直接使用 C 语言的交换方式完成
    ../../include/QtCore/../../src/corelib/arch/qatomic_armv5.h:128: Error: unrecognized opcode `swpb a3,a4,[s0]'
    
    diff --git a/src/corelib/arch/qatomic_armv5.h b/src/corelib/arch/qatomic_armv5.h
    index 27e23d9e..b265d149 100644
    --- a/src/corelib/arch/qatomic_armv5.h
    +++ b/src/corelib/arch/qatomic_armv5.h
    @@ -125,10 +125,12 @@ Q_CORE_EXPORT __asm char q_atomic_swp(volatile char *ptr, char newval);
    inline char q_atomic_swp(volatile char *ptr, char newval)
    {
        register char ret;
    -    asm volatile("swpb %0,%2,[%3]"
    -                 : "=&r"(ret), "=m" (*ptr)
    -                 : "r"(newval), "r"(ptr)
    -                 : "cc", "memory");
    +    //asm volatile("swpb %0,%2,[%3]"
    +    //             : "=&r"(ret), "=m" (*ptr)
    +    //             : "r"(newval), "r"(ptr)
    +    //             : "cc", "memory");
    +    ret = *ptr;
    +    *ptr = newval;
        return ret;
    }
    
    @@ -227,10 +229,12 @@ inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue)
    {
        int originalValue;
    #ifndef QT_NO_ARM_EABI
    -    asm volatile("swp %0,%2,[%3]"
    -                 : "=&r"(originalValue), "=m" (_q_value)
    -                 : "r"(newValue), "r"(&_q_value)
    -                 : "cc", "memory");
    +    //asm volatile("swp %0,%2,[%3]"
    +    //             : "=&r"(originalValue), "=m" (_q_value)
    +    //             : "r"(newValue), "r"(&_q_value)
    +    //             : "cc", "memory");
    +    originalVlaue = _q_value;
    +    _q_value = newValue;
  3. gnu 兼容
    工具链版本的不同,会使某些 C++ code 的兼容性会有差异,需要指定 gnu++98
    error: 'std::tr1' has not been declared
    
    --- a/mkspecs/common/g++-base.conf
    +++ b/mkspecs/common/g++-base.conf
    @@ -15,7 +15,7 @@ QMAKE_LINK_C_SHLIB = $$QMAKE_CC
    
    QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += -O2 -g
    
    -QMAKE_CXX = g++
    +QMAKE_CXX = g++ -std=gnu++98
    
    QMAKE_LINK       = $$QMAKE_CXX
    QMAKE_LINK_SHLIB = $$QMAKE_CXX
    
    --- a/mkspecs/common/gcc-base.conf
    +++ b/mkspecs/common/gcc-base.conf
    @@ -42,7 +42,7 @@ QMAKE_CFLAGS_STATIC_LIB     += -fPIC
    QMAKE_CFLAGS_YACC           += -Wno-unused -Wno-parentheses
    QMAKE_CFLAGS_HIDESYMS       += -fvisibility=hidden
    
    -QMAKE_CXXFLAGS            += $$QMAKE_CFLAGS
    +QMAKE_CXXFLAGS            += $$QMAKE_CFLAGS -std=gnu++98
    QMAKE_CXXFLAGS_DEPS       += $$QMAKE_CFLAGS_DEPS

Directfb 集成

configure 会优先使用 pkg_config, directfb-config 两个工具进行 directfb 的路径获取,会很容易的受到系统 directfb 的影响, 因此此处最简单的办法的绕开系统的变量,直接设置 DIRECTFB 和 QT_LIBS_DIRECTFB 的变量值
The DirectFB screen driver functionality test failed!

--- a/configure
+++ b/configure
@@ -6641,13 +6641,13 @@ if [ "$PLATFORM_QWS" = "yes" ]; then
fi

if [ "${screen}" = "directfb" ] && [ "${CFG_CONFIGURE_EXIT_ON_ERROR}" = "yes" ]; then
-           if test -n "$PKG_CONFIG" && "$PKG_CONFIG" --exists directfb 2>/dev/null; then
-               QT_CFLAGS_DIRECTFB=`$PKG_CONFIG --cflags directfb 2>/dev/null`
-               QT_LIBS_DIRECTFB=`$PKG_CONFIG --libs directfb 2>/dev/null`
-           elif directfb-config --version >/dev/null 2>&1; then
-               QT_CFLAGS_DIRECTFB=`directfb-config --cflags 2>/dev/null`
-               QT_LIBS_DIRECTFB=`directfb-config --libs 2>/dev/null`
-           fi
+           #if test -n "$PKG_CONFIG" && "$PKG_CONFIG" --exists directfb 2>/dev/null; then
+           #    QT_CFLAGS_DIRECTFB=`$PKG_CONFIG --cflags directfb 2>/dev/null`
+           #    QT_LIBS_DIRECTFB=`$PKG_CONFIG --libs directfb 2>/dev/null`
+           #elif directfb-config --version >/dev/null 2>&1; then
+           #    QT_CFLAGS_DIRECTFB=`directfb-config --cflags 2>/dev/null`
+           #    QT_LIBS_DIRECTFB=`directfb-config --libs 2>/dev/null`
+           #fi

config.test

config.tests 是 configure 的测试目录,其中有不少简单的 verify 示例,以 directfb 为例
config.tests/qws/directfb
directfb.cpp  directfb.o  directfb.pro  Makefile

cat Makefile
CC            = riscv64-unknown-linux-gnu-gcc
CXX           = riscv64-unknown-linux-gnu-g++
DEFINES       =
CFLAGS        = -pipe -O2 -Wall -W $(DEFINES)
CXXFLAGS      = -pipe -std=gnu++98 -D_REENTRANT -O2 -Wall -W $(DEFINES)
INCPATH       = -I../../../mkspecs/qws/linux-riscv-gnueabi-g++ -I. -I/usr/include/directfb
LINK          = riscv64-unknown-linux-gnu-g++
LFLAGS        = -Wl,-O1
LIBS          = $(SUBLIBS)   -L/usr/lib/x86_64-linux-gnu -ldirectfb -lfusion -ldirect -lpthread
AR            = riscv64-unknown-linux-gnu-ar cqs
  • 如果某一 test 没有过,可以通过查看 Makefile 确认相关参数是否正确,如上的 include 参数不正确
  • 如果参数正确,可以直接进入该目录执行 make 命令确认出错原因
  • 最初编译 directfb 是动态 zlib,因此需要明确 zlib,第一次仿照上面的 LIBS 设置,则在编译的时候报告 zlib 的错误