Cross-compile on WSL without building Qt from source
-
Hi all,
What I am trying to achieve is cross-compiling a simple QtWidget-application on an x86-64 platform (the host) for an emulated aarch64 target. Note that the target is not a Raspberry Pi, or any other single board computer. I am simply trying to get the cross-compile process to work, and run it via emulation.
I am aware of the various guides floating in the Internet, and on the Qt Group website regarding how to cross-compile the entire Qt from sources to a given target platform. I would like to avoid that since in my case both the host and target architecture libraries and tools are readily available from the package manager. There doesn't seem to be any rational reason for building everything from source.
What I have done so far:
- Windows 11 host system, running x86-64
- WSL (ver 2.2.4.0, WSLg 1.0.61, Kernel version 5.15.153.1-2)
- Ubuntu 22.04 distribution installed on WSL
I first installed the necessary packages for creating "native" Qt applications:
qtdeclarative5-dev:amd64g++-10:amd64make:amd64
After this I created the symlinks
/usr/bin/gccand/usr/bin/g++. I was then able to create a simple Qt application, invokeqmake -projectto create a project file andqmakeandmaketo build it. The binary runs fine, and shows a simple main window with a label widget inside it (hooray to the insidious RDP-wiring in WSL).I then made the Ubuntu system "arm64 aware" with
dpkg --add-architecture arm64and made the necessary modifications to theaptsources list. After this I was able to install the next set of tools for cross-compilation:qtdeclarative5-dev:arm64g++-10-aarch64-linux-gnu:amd64
I then created the necessary symlinks
/usr/bin/aarch64-linux-gnu-gccand/usr/bin/aarch64-linux-gnu-g++and attempted to invokeqmakewith the undocumentedxspecparameter:qmake -xspec linux-aarch64-gnu-g++.qmakegenerated a Makefile for me which uses the correct cross-compiler but theINCPATHandLIBSvariables in the Makefile point to/usr/include/x86_64-linux-gnu/qt5and/usr/lib/x86_64-linux-gnu. Needless to say if I invokemakethe source file is cross-compiled properly but the linker stage falls flat on its face, trying to combine an aarch64 binary with an amd64 library.I tried a brute-force hack by replacing the INCPATH and LIBS variables in the Makefile, and saving it but apparently on each invocation of
makethe originalqmakecommand is re-invoked, and overwrites my hand-made changes in the Makefile. Logical, yes, but also quite frustrating.How can I coax
qmaketo generating a Makefile that'd use INCPATH/usr/include/aarch64-linux-gnu/qt5/and LIBS/usr/lib/aarch64-linux-gnu/?My final goal in this little exercise is to run the cross-compiled executable using
qemu-user.Or is there potentially a flaw in my approach? Can there be a conflict between the C/C++ standard library that the cross-compiler uses and the standard (or other) libraries that the arm64 Qt5 libraries have originally been compiled against?
-
Thanks @SimonSchroeder, your hint led me down the right track. The rabbit hole was deep. Very, very deep.
It seems when I install
qtdeclarative5-dev:arm64I get not only the include and library directories mentioned in my first post but also a shell script into/usr/binfolder with the nameaarch64-linux-gnu-qmake.By default my PATH environment variable has
/usr/binfolder and in there theqmakeexecutable points toqtchooserwhich, in turn, points to the/usr/lib/x86_64-linux-gnu/qt5/binfolder which, again in turn has a symlink fileqmakewhich points to/usr/bin/x86_64-linux-gnu-qmakewhich is a shell script that contains just the right incantations to produce x86-64 binaries.Based on this discovery I checked if a file such as
/usr/bin/aarch64-linux-gnu-qmakeexists and, much to my surprise, it did.Long story short, to cross-compile with ready-made packages you invoke
/usr/bin/aarch64-linux-gnu-qmake -spec linux-aarch64-gnu-g++ <project file>directly. This results in a Makefile which uses not only the right cross-compiler but also sets the INCPATH and LIBS variables correctly.Tested it, and checked the final executable with
readelf. It was an aarch64 binary alright. -
As a side-track I also attempted the cross-compilation using
cmakeand had much, much better success.After creating an initial CMakeLists.txt and an
aarch64-linux-gnu.toolchain.cmakefile I was able to create a Makefile withcmake -DCMAKE_TOOLCHAIN_FILE=aarch64-linux-gnu.toolchain.cmakeand build it withmake.The resulting executable ran correctly with
qemu-aarch64.I continued then on this journey to run the same executable on real aarch64 hardware. After copying the executable over via SCP I ran it, only to face the error
./qt-test: /lib/aarch64-linux-gnu/libc.so.6: version 'GLIBC_2.34' not found (required by ./qt-test)I found out that the target platform only had
libcversion 2.31 so the error itself seemed clear. I solved the situation by installing the previous version of Ubuntu (20.04) to WSL, and retracing my steps. The new executable built with Ubuntu 20.04 ran correctly on the target hardware.For reference, here's the final "Bill of Materials" for cross-compiling a simple Qt application using Ubuntu 20.04 on x86-64 host for Debian Bullseye on aarch64:
- Install and update WSL to latest version
- Install Ubuntu-20.04 on WSL, and update its packages to latest versions
- Install
apt install g++-10-aarch64-linux-gnu cmake g++-(cross-compile tools) - Enable arm64 architecture (
dpkg --add-architecture arm64) and specifyaptsources (see attachment) - Install
apt install qtdeclarative5-dev:arm64 - Create CMakeLists.txt and CMake toolchain file (see attachment)
- Invoke
cmakewith the toolchain file, and finallymake
The original question still remains unanswered, though. How to coax
qmaketo do my bidding?


-
Hi all,
What I am trying to achieve is cross-compiling a simple QtWidget-application on an x86-64 platform (the host) for an emulated aarch64 target. Note that the target is not a Raspberry Pi, or any other single board computer. I am simply trying to get the cross-compile process to work, and run it via emulation.
I am aware of the various guides floating in the Internet, and on the Qt Group website regarding how to cross-compile the entire Qt from sources to a given target platform. I would like to avoid that since in my case both the host and target architecture libraries and tools are readily available from the package manager. There doesn't seem to be any rational reason for building everything from source.
What I have done so far:
- Windows 11 host system, running x86-64
- WSL (ver 2.2.4.0, WSLg 1.0.61, Kernel version 5.15.153.1-2)
- Ubuntu 22.04 distribution installed on WSL
I first installed the necessary packages for creating "native" Qt applications:
qtdeclarative5-dev:amd64g++-10:amd64make:amd64
After this I created the symlinks
/usr/bin/gccand/usr/bin/g++. I was then able to create a simple Qt application, invokeqmake -projectto create a project file andqmakeandmaketo build it. The binary runs fine, and shows a simple main window with a label widget inside it (hooray to the insidious RDP-wiring in WSL).I then made the Ubuntu system "arm64 aware" with
dpkg --add-architecture arm64and made the necessary modifications to theaptsources list. After this I was able to install the next set of tools for cross-compilation:qtdeclarative5-dev:arm64g++-10-aarch64-linux-gnu:amd64
I then created the necessary symlinks
/usr/bin/aarch64-linux-gnu-gccand/usr/bin/aarch64-linux-gnu-g++and attempted to invokeqmakewith the undocumentedxspecparameter:qmake -xspec linux-aarch64-gnu-g++.qmakegenerated a Makefile for me which uses the correct cross-compiler but theINCPATHandLIBSvariables in the Makefile point to/usr/include/x86_64-linux-gnu/qt5and/usr/lib/x86_64-linux-gnu. Needless to say if I invokemakethe source file is cross-compiled properly but the linker stage falls flat on its face, trying to combine an aarch64 binary with an amd64 library.I tried a brute-force hack by replacing the INCPATH and LIBS variables in the Makefile, and saving it but apparently on each invocation of
makethe originalqmakecommand is re-invoked, and overwrites my hand-made changes in the Makefile. Logical, yes, but also quite frustrating.How can I coax
qmaketo generating a Makefile that'd use INCPATH/usr/include/aarch64-linux-gnu/qt5/and LIBS/usr/lib/aarch64-linux-gnu/?My final goal in this little exercise is to run the cross-compiled executable using
qemu-user.Or is there potentially a flaw in my approach? Can there be a conflict between the C/C++ standard library that the cross-compiler uses and the standard (or other) libraries that the arm64 Qt5 libraries have originally been compiled against?
@AnttiK said in Cross-compile on WSL without building Qt from source:
How can I coax qmake to generating a Makefile
Even though you have found an answer using CMake, I'd like to give a hint what to do when using qmake. You just have to use the correct qmake. Each Qt installation has its own qmake and will use the includes and libs from the same path. So, you'd have to explicitly call the qmake located in the installation path for arm64 cross compilation.
-
Thanks @SimonSchroeder, your hint led me down the right track. The rabbit hole was deep. Very, very deep.
It seems when I install
qtdeclarative5-dev:arm64I get not only the include and library directories mentioned in my first post but also a shell script into/usr/binfolder with the nameaarch64-linux-gnu-qmake.By default my PATH environment variable has
/usr/binfolder and in there theqmakeexecutable points toqtchooserwhich, in turn, points to the/usr/lib/x86_64-linux-gnu/qt5/binfolder which, again in turn has a symlink fileqmakewhich points to/usr/bin/x86_64-linux-gnu-qmakewhich is a shell script that contains just the right incantations to produce x86-64 binaries.Based on this discovery I checked if a file such as
/usr/bin/aarch64-linux-gnu-qmakeexists and, much to my surprise, it did.Long story short, to cross-compile with ready-made packages you invoke
/usr/bin/aarch64-linux-gnu-qmake -spec linux-aarch64-gnu-g++ <project file>directly. This results in a Makefile which uses not only the right cross-compiler but also sets the INCPATH and LIBS variables correctly.Tested it, and checked the final executable with
readelf. It was an aarch64 binary alright. -
A AnttiK has marked this topic as solved on
-
As a convenience to future readers, I've created a simple GitHub repo which has the bells & whistles to do cross-compilation of Qt apps both with CMake and with qmake.