Cross compiling a Qt application for arm but the target rcc and moc executables are used instead of the host versions

I am using Debian 10 running on AMD64 and trying to setup a cross compilation environment for an aarch64 target. I have used the following command:

sbuild-createchroot --debootstrap=qemu-debootstrap --arch=arm64 --chroot-mode=schroot --keep-sbuild-chroot-dir buster /srv/chroots/buster

to create a chroot environment under /srv/chroots/buster which has been populated with aarch64 files. Using schroot I can actually build inside the chroot environment, but because it is using qemu to emulate aarch64 on AMD64 it is painfully slow. I would like to use the native gcc cross compilers to get better speed.

I ran the following cmake command:

cmake -G “CodeBlocks - Unix Makefiles” -DCMAKE_TOOLCHAIN_FILE=/home/glenn/arm64.cmake -DCMAKE_BUILD_TYPE=Release …

where the toolchain file looks like this:

set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR aarch64)
set(CMAKE_SYSTEM_VERSION 4.14.98-2.3.0+)

set(CMAKE_C_FLAGS “-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Os ${CMAKE_C_FLAGS}” CACHE STRING “Cross compile CFLAGS”)
set(CMAKE_CXX_FLAGS “-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Os ${CMAKE_CXX_FLAGS}” CACHE STRING “Cross compile CXXFLAGS”)
set(CMAKE_EXE_LINKER_FLAGS " ${CMAKE_EXE_LINKER_FLAGS}" CACHE STRING “Cross compile LDFLAGS”)
set(CMAKE_INSTALL_SO_NO_EXE 0)

set(CMAKE_PROGRAM_PATH “/usr/bin”)
set(CMAKE_SYSROOT “/srv/chroots/buster”)
set(CMAKE_FIND_ROOT_PATH “/srv/chroots/buster”)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(ENV{PKG_CONFIG_SYSROOT_DIR} “/srv/chroots/buster/”)

set(CMAKE_C_COMPILER “/usr/bin/aarch64-linux-gnu-gcc”)
set(CMAKE_CXX_COMPILER “/usr/bin/aarch64-linux-gnu-g++”)

and I get the following error:

– The C compiler identification is GNU 8.3.0
– The CXX compiler identification is GNU 8.3.0
– Check for working C compiler: /usr/bin/aarch64-linux-gnu-gcc
– Check for working C compiler: /usr/bin/aarch64-linux-gnu-gcc – works
– Detecting C compiler ABI info
– Detecting C compiler ABI info - done
– Detecting C compile features
– Detecting C compile features - done
– Check for working CXX compiler: /usr/bin/aarch64-linux-gnu-g++
– Check for working CXX compiler: /usr/bin/aarch64-linux-gnu-g++ – works
– Detecting CXX compiler ABI info
– Detecting CXX compiler ABI info - done
– Detecting CXX compile features
– Detecting CXX compile features - done
– Found Qt version 5.11.3
– Configuring done
CMake Error: rcc list process failed for:
“/home/glenn/liarail/master/PsDemo/PsDemo_Controller/res.qrc”

/lib/ld-linux-aarch64.so.1: No such file or directory

The cause of this error seems to be because cmake is trying to run rcc from the schroot environment:

/srv/chroots/buster/usr/lib/qt5/bin/rcc

instead of using the host version located here:

/usr/lib/qt5/bin/rcc

If I delete the schroot rcc and replace it with a symbolic link to the host rcc then cmake runs successfuly and generates the Makefiles. I get a similar problem when I try to build but this time it is the moc executable that is wrong. If I use the same symbolic link hack then I can finally get the build to run.

Obviously, my symbolic link hack is not the correct way to solve this problem. I’m not sure if this is a cmake problem or a Qt problem. If it is a cmake problem, is there a cleaner solution than my current ugly hack ? Even if it is a Qt problem, is there a way to work around it in cmake ?

The Qt5 config files do this (see Qt5CoreConfigExtras.cmake). OpenEmbedded has done patches to work around this with the CMake variable OE_QMAKE_PATH_EXTERNAL_HOST_BINS. You can achieve similar by predefining the Qt5::qmake, Qt5::moc and Qt5::rcc targets in your toolchain file.

Hendrik, thanks for the pointer to the Qt5CoreConfigExtras.cmake file. I have added the following lines to the end of my toolchain file:

macro(_add_imported_target target_name file)
    if (NOT EXISTS "${file}")
        message(FATAL_ERROR "The imported target \"${target_name}\" references the file \"${file}\" but this file does not exist.")
    endif()

    if (NOT TARGET ${target_name})
        add_executable(${target_name} IMPORTED)
        set_target_properties(${target_name} PROPERTIES IMPORTED_LOCATION ${file})
    endif()
endmacro()

# use the host versions of these executables
_add_imported_target(Qt5::moc   "/usr/lib/qt5/bin/moc")
_add_imported_target(Qt5::rcc   "/usr/lib/qt5/bin/rcc")
_add_imported_target(Qt5::qmake "/usr/lib/qt5/bin/qmake")

and everything now works as expected, even with the target versions of the tools not hacked to be symbolic links pointing to the host versions.

Should there be mention of this somewhere in the cmake documentation on toolchain files and cross compilation ? Or have Qt modified the Qt5CoreConfigExtras.cmake file on the latest release to avoid this problem ?

You can use CMAKE_IGNORE_PATH in your toolchain file to remove some paths that should not be picked by CMake for the find_program calls.

You can use QT_HOST_PATH to point to the host tools, so that the Qt CMake build system doesn’t try to use the target’s tools.

Ah, you are trying to build an App and not Qt itself. :slight_smile: