Skip to content

Instantly share code, notes, and snippets.

@tycho
Last active October 19, 2023 12:36
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tycho/3ce679850a03a39d8c174ac05af56214 to your computer and use it in GitHub Desktop.
Save tycho/3ce679850a03a39d8c174ac05af56214 to your computer and use it in GitHub Desktop.
Diff for Qt 5.10.1 for Windows 10 ARM64
This patch implements numerous changes to make the Qt 5.10.1 build work for the new ARM64 target in
Visual Studio 2017. This change also includes a couple of new batch scripts, in case you want to build
on the target machine itself (very slow) or build on an x86/x86_64 host (much faster).
You can build with something like this:
> configure_src_on_x86_host.bat
> jom -f Makefile Debug Release
diff --git a/configure_src_on_target.bat b/configure_src_on_target.bat
new file mode 100644
index 000000000..d23e7e295
--- /dev/null
+++ b/configure_src_on_target.bat
@@ -0,0 +1,3 @@
+call vcvarsall.bat x86_arm64
+set PATH=%PATH%;C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Redist\MSVC\14.13.26020\onecore\arm64\Microsoft.VC141.CRT
+configure -opensource -confirm-license -prefix c:/Qt/5.10.1/msvc2017_arm64 -nomake examples -nomake tests -skip webengine -opengl es2 -angle -no-pch
diff --git a/configure_src_on_x86_host.bat b/configure_src_on_x86_host.bat
new file mode 100644
index 000000000..40e3bed3e
--- /dev/null
+++ b/configure_src_on_x86_host.bat
@@ -0,0 +1,2 @@
+call vcvarsall.bat x86_arm64
+configure -opensource -confirm-license -prefix c:/Qt/5.10.1/msvc2017_arm64 -debug-and-release -nomake examples -nomake tests -skip webengine -opengl es2 -angle -platform win32-msvc -xplatform win32-arm64-msvc -external-hostbindir c:/Qt/5.10.1/msvc2017_64/bin
diff --git a/qt3d/src/3rdparty/assimp/contrib/rapidjson/include/rapidjson/rapidjson.h b/qt3d/src/3rdparty/assimp/contrib/rapidjson/include/rapidjson/rapidjson.h
index 4c4d983d1..81a997df2 100755
--- a/qt3d/src/3rdparty/assimp/contrib/rapidjson/include/rapidjson/rapidjson.h
+++ b/qt3d/src/3rdparty/assimp/contrib/rapidjson/include/rapidjson/rapidjson.h
@@ -209,7 +209,7 @@
// Detect with architecture macros
# elif defined(__sparc) || defined(__sparc__) || defined(_POWER) || defined(__powerpc__) || defined(__ppc__) || defined(__hpux) || defined(__hppa) || defined(_MIPSEB) || defined(_POWER) || defined(__s390__)
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
-# elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__)
+# elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__) || defined(_M_ARM64)
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
# elif defined(RAPIDJSON_DOXYGEN_RUNNING)
# define RAPIDJSON_ENDIAN
diff --git a/qtbase/configure.bat b/qtbase/configure.bat
index 35bfdf5e3..e9034a4cd 100755
--- a/qtbase/configure.bat
+++ b/qtbase/configure.bat
@@ -96,6 +96,9 @@ goto doneargs
if /i "%~1" == "-make-tool" goto maketool
if /i "%~1" == "--make-tool" goto maketool
+ if /i "%~1" == "-external-hostbindir" goto hosttools
+ if /i "%~1" == "--external-hostbindir" goto hosttools
+
:nextarg
shift
goto doargs
@@ -147,6 +150,11 @@ goto doneargs
set MAKE=%~1
goto nextarg
+:hosttools
+ shift
+ set CFG_HOST_QT_TOOLS_PATH=%~1
+ goto nextarg
+
:doneargs
rem Find various executables
@@ -277,7 +285,9 @@ cd ..
rem Generate qt.conf
-> "%QTDIR%\bin\qt.conf" (
+set QTCONFFILE=%QTDIR%\bin\qt.conf
+
+> "%QTCONFFILE%" (
@echo [EffectivePaths]
@echo Prefix=..
@echo [Paths]
@@ -285,7 +295,7 @@ rem Generate qt.conf
@echo HostSpec=%PLATFORM%
)
if not "%QTDIR%" == "%QTSRC%" (
- >> "%QTDIR%\bin\qt.conf" (
+ >> "%QTCONFFILE%" (
@echo [EffectiveSourcePaths]
@echo Prefix=%QTSRC:\=/%
)
@@ -294,4 +304,8 @@ if not "%QTDIR%" == "%QTSRC%" (
rem Launch qmake-based configure
cd "%TOPQTDIR%"
-"%QTDIR%\bin\qmake.exe" "%TOPQTSRC%" -- %ARGS%
+if "%CFG_HOST_QT_TOOLS_PATH%" == "" (
+ "%QTDIR%\bin\qmake.exe" "%TOPQTSRC%" -- %ARGS%
+) else (
+ "%CFG_HOST_QT_TOOLS_PATH%\qmake.exe" -qtconf "%QTCONFFILE%" "%TOPQTSRC%" -- %ARGS%
+)
diff --git a/qtbase/mkspecs/common/msvc-desktop.conf b/qtbase/mkspecs/common/msvc-desktop.conf
index 626662463..b1e4a29ff 100755
--- a/qtbase/mkspecs/common/msvc-desktop.conf
+++ b/qtbase/mkspecs/common/msvc-desktop.conf
@@ -22,6 +22,10 @@ contains(QMAKE_TARGET.arch, x86_64) {
DEFINES += WIN64
QMAKE_COMPILER_DEFINES += _WIN64
}
+contains(QMAKE_TARGET.arch, arm64) {
+ DEFINES += WIN64
+ QMAKE_COMPILER_DEFINES += _WIN64
+}
QMAKE_CFLAGS_OPTIMIZE_DEBUG = -Od
QMAKE_CFLAGS_OPTIMIZE = -O2
diff --git a/qtbase/mkspecs/win32-arm64-msvc/qmake.conf b/qtbase/mkspecs/win32-arm64-msvc/qmake.conf
new file mode 100644
index 000000000..b8900a828
--- /dev/null
+++ b/qtbase/mkspecs/win32-arm64-msvc/qmake.conf
@@ -0,0 +1,12 @@
+#
+# qmake configuration for win32-msvc
+#
+# Written for Microsoft C/C++ Optimizing Compiler (all desktop versions)
+#
+
+QMAKE_TARGET.arch = arm64
+QMAKE_MSC_VER = 1910
+QT_HOST_BINS = C:\Qt\5.10.1\msvc2017_64\bin
+
+include(../common/msvc-desktop.conf)
+load(qt_config)
diff --git a/qtbase/mkspecs/win32-arm64-msvc/qplatformdefs.h b/qtbase/mkspecs/win32-arm64-msvc/qplatformdefs.h
new file mode 100644
index 000000000..c2cfe4fac
--- /dev/null
+++ b/qtbase/mkspecs/win32-arm64-msvc/qplatformdefs.h
@@ -0,0 +1,140 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the qmake spec of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPLATFORMDEFS_H
+#define QPLATFORMDEFS_H
+
+#ifdef UNICODE
+#ifndef _UNICODE
+#define _UNICODE
+#endif
+#endif
+
+// Get Qt defines/settings
+
+#include <QtCore/qglobal.h>
+
+#define _POSIX_
+#include <limits.h>
+#undef _POSIX_
+
+#include <tchar.h>
+#include <io.h>
+#include <direct.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+
+#ifdef QT_LARGEFILE_SUPPORT
+#define QT_STATBUF struct _stati64 // non-ANSI defs
+#define QT_STATBUF4TSTAT struct _stati64 // non-ANSI defs
+#define QT_STAT ::_stati64
+#define QT_FSTAT ::_fstati64
+#else
+#define QT_STATBUF struct _stat // non-ANSI defs
+#define QT_STATBUF4TSTAT struct _stat // non-ANSI defs
+#define QT_STAT ::_stat
+#define QT_FSTAT ::_fstat
+#endif
+#define QT_STAT_REG _S_IFREG
+#define QT_STAT_DIR _S_IFDIR
+#define QT_STAT_MASK _S_IFMT
+#if defined(_S_IFLNK)
+# define QT_STAT_LNK _S_IFLNK
+#else
+# define QT_STAT_LNK 0120000
+#endif
+#define QT_FILENO _fileno
+#define QT_OPEN ::_open
+#define QT_CLOSE ::_close
+#ifdef QT_LARGEFILE_SUPPORT
+#define QT_LSEEK ::_lseeki64
+#define QT_TSTAT ::_tstati64
+#else
+#define QT_LSEEK ::_lseek
+#define QT_TSTAT ::_tstat
+#endif
+#define QT_READ ::_read
+#define QT_WRITE ::_write
+#define QT_ACCESS ::_access
+#define QT_GETCWD ::_getcwd
+#define QT_CHDIR ::_chdir
+#define QT_MKDIR ::_mkdir
+#define QT_RMDIR ::_rmdir
+#define QT_OPEN_LARGEFILE 0
+#define QT_OPEN_RDONLY _O_RDONLY
+#define QT_OPEN_WRONLY _O_WRONLY
+#define QT_OPEN_RDWR _O_RDWR
+#define QT_OPEN_CREAT _O_CREAT
+#define QT_OPEN_TRUNC _O_TRUNC
+#define QT_OPEN_APPEND _O_APPEND
+#if defined(O_TEXT)
+# define QT_OPEN_TEXT _O_TEXT
+# define QT_OPEN_BINARY _O_BINARY
+#endif
+
+#include "../common/c89/qplatformdefs.h"
+
+#ifdef QT_LARGEFILE_SUPPORT
+#undef QT_FSEEK
+#undef QT_FTELL
+#undef QT_OFF_T
+
+#define QT_FSEEK ::_fseeki64
+#define QT_FTELL ::_ftelli64
+#define QT_OFF_T __int64
+#endif
+
+#define QT_SIGNAL_ARGS int
+
+#define QT_VSNPRINTF(buffer, count, format, arg) \
+ vsnprintf_s(buffer, count, count-1, format, arg)
+
+#define QT_SNPRINTF ::_snprintf
+
+# define F_OK 0
+# define X_OK 1
+# define W_OK 2
+# define R_OK 4
+
+typedef int mode_t;
+
+#endif // QPLATFORMDEFS_H
diff --git a/qtbase/src/3rdparty/angle/src/common/mathutil.h b/qtbase/src/3rdparty/angle/src/common/mathutil.h
index 59bf7e771..b35389aaf 100755
--- a/qtbase/src/3rdparty/angle/src/common/mathutil.h
+++ b/qtbase/src/3rdparty/angle/src/common/mathutil.h
@@ -127,7 +127,7 @@ inline unsigned int unorm(float x)
inline bool supportsSSE2()
{
-#if defined(ANGLE_PLATFORM_WINDOWS) && !defined(_M_ARM)
+#if defined(ANGLE_PLATFORM_WINDOWS) && !defined(_M_ARM) && !defined(_M_ARM64)
static bool checked = false;
static bool supports = false;
diff --git a/qtbase/src/3rdparty/angle/src/common/platform.h b/qtbase/src/3rdparty/angle/src/common/platform.h
index d273a7b90..f0480a9b0 100755
--- a/qtbase/src/3rdparty/angle/src/common/platform.h
+++ b/qtbase/src/3rdparty/angle/src/common/platform.h
@@ -87,7 +87,7 @@
# undef far
#endif
-#if !defined(_M_ARM) && !defined(ANGLE_PLATFORM_ANDROID)
+#if !defined(_M_ARM) && !defined(_M_ARM64) && !defined(ANGLE_PLATFORM_ANDROID)
# define ANGLE_USE_SSE
#endif
diff --git a/qtbase/src/3rdparty/double-conversion/include/double-conversion/utils.h b/qtbase/src/3rdparty/double-conversion/include/double-conversion/utils.h
index 2a8301d35..d0dcba503 100755
--- a/qtbase/src/3rdparty/double-conversion/include/double-conversion/utils.h
+++ b/qtbase/src/3rdparty/double-conversion/include/double-conversion/utils.h
@@ -58,7 +58,7 @@
// disabled.)
// On Linux,x86 89255e-22 != Div_double(89255.0/1e22)
#if defined(_M_X64) || defined(__x86_64__) || \
- defined(__ARMEL__) || defined(__avr32__) || _M_ARM_FP || \
+ defined(__ARMEL__) || defined(__avr32__) || _M_ARM_FP || defined(_M_ARM64) || \
defined(__hppa__) || defined(__ia64__) || \
defined(__mips__) || \
defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__) || \
diff --git a/qtbase/src/angle/src/common/gles_common.pri b/qtbase/src/angle/src/common/gles_common.pri
index 01fc36bd4..0f7f5922b 100755
--- a/qtbase/src/angle/src/common/gles_common.pri
+++ b/qtbase/src/angle/src/common/gles_common.pri
@@ -237,9 +237,8 @@ SOURCES += \
$$ANGLE_DIR/src/libGLESv2/entry_points_gles_3_0.cpp \
$$ANGLE_DIR/src/libGLESv2/entry_points_gles_3_0_ext.cpp \
$$ANGLE_DIR/src/libGLESv2/global_state.cpp \
- $$ANGLE_DIR/src/libGLESv2/libGLESv2.cpp
-
-SSE2_SOURCES += $$ANGLE_DIR/src/libANGLE/renderer/d3d/loadimageSSE2.cpp
+ $$ANGLE_DIR/src/libGLESv2/libGLESv2.cpp \
+ $$ANGLE_DIR/src/libANGLE/renderer/d3d/loadimageSSE2.cpp
DEBUG_SOURCE = $$ANGLE_DIR/src/libANGLE/Debug.cpp
debug_copy.input = DEBUG_SOURCE
diff --git a/qtbase/src/corelib/global/qprocessordetection.h b/qtbase/src/corelib/global/qprocessordetection.h
index 89b0c96f9..ac0908873 100755
--- a/qtbase/src/corelib/global/qprocessordetection.h
+++ b/qtbase/src/corelib/global/qprocessordetection.h
@@ -94,8 +94,8 @@
ARM is bi-endian, detect using __ARMEL__ or __ARMEB__, falling back to
auto-detection implemented below.
*/
-#if defined(__arm__) || defined(__TARGET_ARCH_ARM) || defined(_M_ARM) || defined(__aarch64__) || defined(__ARM64__)
-# if defined(__aarch64__) || defined(__ARM64__)
+#if defined(__arm__) || defined(__TARGET_ARCH_ARM) || defined(_M_ARM) || defined(_M_ARM64) || defined(__aarch64__) || defined(__ARM64__)
+# if defined(__aarch64__) || defined(__ARM64__) || defined(_M_ARM64)
# define Q_PROCESSOR_ARM_64
# define Q_PROCESSOR_WORDSIZE 8
# else
@@ -110,7 +110,8 @@
# elif defined(__ARM64_ARCH_8__) \
|| defined(__aarch64__) \
|| defined(__ARMv8__) \
- || defined(__ARMv8_A__)
+ || defined(__ARMv8_A__) \
+ || defined(_M_ARM64)
# define Q_PROCESSOR_ARM 8
# elif defined(__ARM_ARCH_7__) \
|| defined(__ARM_ARCH_7A__) \
@@ -148,7 +149,7 @@
# else
# error "ARM architecture too old"
# endif
-# if defined(__ARMEL__)
+# if defined(__ARMEL__) || defined(_M_ARM64)
# define Q_BYTE_ORDER Q_LITTLE_ENDIAN
# elif defined(__ARMEB__)
# define Q_BYTE_ORDER Q_BIG_ENDIAN
diff --git a/qtbase/src/gui/opengl/qopenglversionfunctions.h b/qtbase/src/gui/opengl/qopenglversionfunctions.h
index 3ac0bbd07..f4c5452d8 100755
--- a/qtbase/src/gui/opengl/qopenglversionfunctions.h
+++ b/qtbase/src/gui/opengl/qopenglversionfunctions.h
@@ -61,6 +61,12 @@
#include <QtCore/qpair.h>
#include <QtGui/qopengl.h>
+// Windows had the smart idea of using a #define MemoryBarrier
+// https://msdn.microsoft.com/en-us/library/windows/desktop/ms684208(v=vs.85).aspx
+#if defined(Q_OS_WIN) && defined(MemoryBarrier)
+#undef MemoryBarrier
+#endif
+
QT_BEGIN_NAMESPACE
class QOpenGLContext;
diff --git a/qtscript/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Collector.cpp b/qtscript/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Collector.cpp
index bcd6374ff..dad5e3ead 100755
--- a/qtscript/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Collector.cpp
+++ b/qtscript/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Collector.cpp
@@ -601,7 +601,7 @@ static inline void* currentThreadStackBase()
MOV pTib, EAX
}
return static_cast<void*>(pTib->StackBase);
-#elif OS(WINDOWS) && CPU(X86_64) && (COMPILER(MSVC) || COMPILER(GCC))
+#elif OS(WINDOWS) && (CPU(X86_64) || CPU(AARCH64)) && (COMPILER(MSVC) || COMPILER(GCC))
// FIXME: why only for MSVC?
PNT_TIB64 pTib = reinterpret_cast<PNT_TIB64>(NtCurrentTeb());
return reinterpret_cast<void*>(pTib->StackBase);
diff --git a/qtscript/src/3rdparty/javascriptcore/JavaScriptCore/wtf/Platform.h b/qtscript/src/3rdparty/javascriptcore/JavaScriptCore/wtf/Platform.h
index 9bd28f041..bb4ab64d7 100755
--- a/qtscript/src/3rdparty/javascriptcore/JavaScriptCore/wtf/Platform.h
+++ b/qtscript/src/3rdparty/javascriptcore/JavaScriptCore/wtf/Platform.h
@@ -252,7 +252,7 @@
#endif
/* CPU(AARCH64) - AArch64 */
-#if defined(__aarch64__)
+#if defined(__aarch64__) || defined(_M_ARM64)
#define WTF_CPU_AARCH64 1
#if defined(__AARCH64EB__)
#define WTF_CPU_BIG_ENDIAN 1
diff --git a/qtxmlpatterns/src/xmlpatterns/xmlpatterns.pro b/qtxmlpatterns/src/xmlpatterns/xmlpatterns.pro
index 66853c9be..0bda6a7c0 100755
--- a/qtxmlpatterns/src/xmlpatterns/xmlpatterns.pro
+++ b/qtxmlpatterns/src/xmlpatterns/xmlpatterns.pro
@@ -3,7 +3,7 @@ CONFIG += exceptions
QT = core-private network
DEFINES += QT_NO_USING_NAMESPACE QT_ENABLE_QEXPLICITLYSHAREDDATAPOINTER_STATICCAST
-win32-msvc*|win32-icc:QMAKE_LFLAGS += /BASE:0x61000000
+msvc:equals(QT_ARCH, i386):QMAKE_LFLAGS += /BASE:0x61000000
QMAKE_DOCS = $$PWD/doc/qtxmlpatterns.qdocconf
@lvw5264
Copy link

lvw5264 commented Sep 14, 2020

Hey there, did you ever get this to compile on a Windows on ARM64 device and how did it go?

I'm wondering about how to port this patch to Qt 5.15, and I wonder how it went in the past and what changes might be necessary to get this patch to work on newer codebases, if any.

In particular when I compile Qt from vcpkg for arm64-windows (cross compiling from x86_64 of course successfully on other C++ libraries) with the following command:

.\vcpkg install --triplet arm64-windows qt5

It hits an error compiling freeglut, because Windows on ARM64 has no OpenGL32 support at the moment. I'm wondering if that package is really a dependency though if you managed to get your stuff to work.

microsoft/vcpkg#11822

@tycho
Copy link
Author

tycho commented Sep 14, 2020

Hey there, did you ever get this to compile on a Windows on ARM64 device and how did it go?

Yeah, this patch did work at one point, @lvw5264. I built an ARM64-native version of KeePassXC with it. I haven't tried building anything for Windows ARM64 for quite a while though. I might have to revisit this patch and see if I can get it going with a more recent Qt version.

@tycho
Copy link
Author

tycho commented Sep 14, 2020

It looks like upstream Qt did add some support for building ARM64 Windows stuff, but hasn't distributed any binaries:

https://code.qt.io/cgit/qt/qtbase.git/commit/?id=fbbe8aba9d70a3c13d1cd7797eb4dbbd1f05ade5

So that looks somewhat promising at least.

@tycho
Copy link
Author

tycho commented Sep 14, 2020

I cross-compiled Qt 5.15.1 for Windows ARM64 successfully (on a Windows x86_64 host with Visual Studio 2019 installed) with a fairly minimal patch:

diff --git a/qtbase/configure.bat b/qtbase/configure.bat
index 75ec1b1690..a433e9b5e1 100755
--- a/qtbase/configure.bat
+++ b/qtbase/configure.bat
@@ -96,6 +96,9 @@ goto doneargs
     if /i "%~1" == "-make-tool" goto maketool
     if /i "%~1" == "--make-tool" goto maketool

+    if /i "%~1" == "-external-hostbindir" goto hosttools
+    if /i "%~1" == "--external-hostbindir" goto hosttools
+
 :nextarg
     shift
     goto doargs
@@ -144,6 +147,11 @@ goto doneargs
     set MAKE=%~1
     goto nextarg

+:hosttools
+    shift
+    set CFG_HOST_QT_TOOLS_PATH=%~1
+    goto nextarg
+
 :doneargs

 rem Find various executables
@@ -276,7 +284,9 @@ cd ..

 rem Generate qt.conf

-> "%QTDIR%\bin\qt.conf" (
+set QTCONFFILE=%QTDIR%\bin\qt.conf
+
+> "%QTCONFFILE%" (
     @echo [EffectivePaths]
     @echo Prefix=..
     @echo [Paths]
@@ -284,7 +294,7 @@ rem Generate qt.conf
     @echo HostSpec=%PLATFORM%
 )
 if not "%QTDIR%" == "%QTSRC%" (
-    >> "%QTDIR%\bin\qt.conf" (
+    >> "%QTCONFFILE%" (
         @echo [EffectiveSourcePaths]
         @echo Prefix=%QTSRC:\=/%
     )
@@ -293,4 +303,8 @@ if not "%QTDIR%" == "%QTSRC%" (
 rem Launch qmake-based configure

 cd "%TOPQTDIR%"
-"%QTDIR%\bin\qmake.exe" "%TOPQTSRC%" -- %ARGS%
+if "%CFG_HOST_QT_TOOLS_PATH%" == "" (
+       "%QTDIR%\bin\qmake.exe" "%TOPQTSRC%" -- %ARGS%
+) else (
+       "%CFG_HOST_QT_TOOLS_PATH%\qmake.exe" -qtconf "%QTCONFFILE%" "%TOPQTSRC%" -- %ARGS%
+)
diff --git a/qtbase/mkspecs/common/msvc-desktop.conf b/qtbase/mkspecs/common/msvc-desktop.conf
index 488df8a7e4..3c719f4d9a 100755
--- a/qtbase/mkspecs/common/msvc-desktop.conf
+++ b/qtbase/mkspecs/common/msvc-desktop.conf
@@ -25,6 +25,10 @@ contains(QMAKE_TARGET.arch, x86_64) {
     DEFINES += WIN64
     QMAKE_COMPILER_DEFINES += _WIN64
 }
+contains(QMAKE_TARGET.arch, arm64) {
+    DEFINES += WIN64
+    QMAKE_COMPILER_DEFINES += _WIN64
+}

 QMAKE_CFLAGS_OPTIMIZE_DEBUG = -Od
 QMAKE_CFLAGS_OPTIMIZE      = -O2
diff --git a/qtxmlpatterns/src/xmlpatterns/xmlpatterns.pro b/qtxmlpatterns/src/xmlpatterns/xmlpatterns.pro
index 66853c9be4..0bda6a7c09 100755
--- a/qtxmlpatterns/src/xmlpatterns/xmlpatterns.pro
+++ b/qtxmlpatterns/src/xmlpatterns/xmlpatterns.pro
@@ -3,7 +3,7 @@ CONFIG += exceptions
 QT = core-private network

 DEFINES += QT_NO_USING_NAMESPACE QT_ENABLE_QEXPLICITLYSHAREDDATAPOINTER_STATICCAST
-win32-msvc*|win32-icc:QMAKE_LFLAGS += /BASE:0x61000000
+msvc:equals(QT_ARCH, i386):QMAKE_LFLAGS += /BASE:0x61000000

 QMAKE_DOCS = $$PWD/doc/qtxmlpatterns.qdocconf

And my batch script for configuring/building:

call vcvarsall.bat x86_arm64
set QT_VERSION=5.15.1
configure -opensource -confirm-license -prefix c:/Qt/%QT_VERSION%/msvc2019_arm64 -debug-and-release -nomake examples -nomake tests -skip webengine -opengl es2 -angle -platform win32-msvc -xplatform win32-arm64-msvc2017 -external-hostbindir c:/Qt/%QT_VERSION%/msvc2019_64/bin
jom
jom install

I haven't tested the binaries on an ARM64 device yet, but compiling/linking is a pretty good first step.

@lvw5264
Copy link

lvw5264 commented Sep 16, 2020

Thanks for the help, I was able to compile Qt for Windows on ARM64 using cross compilation.

After making sure to install the Visual C++ Redistributables for ARM64, I was able to run qml.exe -h and qmake -h, at least it does demonstrates that the builds run on the target device, so that's the first step.

https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads

I plan to start figuring out how to get PySide2 running, as Python 3.8.5 is buildable on ARM64 with a generated binary here, but Python itself may be a rough road as all the more advanced python modules need their C libraries recompiled too...

https://github.com/jay0lee/CPython-Windows-ARM64

https://bugs.python.org/issue33125

@tycho
Copy link
Author

tycho commented Sep 16, 2020

Hah, Python issue 33125 was filed by me. It looks like they got it mostly fixed.

@twessman
Copy link

I too seem to have built 15.1 although have not tested yet. Thank you sooooooo much! The version coming out of this seems to be the arm version which would require building on an arm device.

Any idea what would be needed to build a cross compiler version so I could integrate into my existing build server? (amd64 host building for arm64 target)

@tycho
Copy link
Author

tycho commented Sep 28, 2020

You should be able to run vcvarsx86_arm64.bat (or vcvarsamd64_arm64.bat) from Visual Studio's install and then build as usual.

You'll run into trouble with it not being able to execute the qmake.exe it just built during that process (because it's an arm64 build of it). So you'll need to use the x86_64 tools for e.g. qmake.exe and the like. I haven't hacked that into the build system in my patches though, so you might have to experiment to figure out how to get it to use the x86_64-native ones while cross-compiling.

@osarguel
Copy link

@tycho did you successfully build qt5.15 for arm64 and then used it in a native arm64 win app?
I used your patch and was succesful on getting qt for arm64, then I cross-compiled my app with arm64 as a target using moc and qmlcachegen but then it's having issues finding the resources (note that it works if compiled with amd64 as a target)

Qt [Warning] (qrc:/MyWindow.qml, $function): qrc:/MyWindow.qml:226:5: MyDialog is not a type

Note: MyDialog is defined under the qrc file.

Anything else you had to do after this patch?

@kafeg
Copy link

kafeg commented Feb 10, 2022

@tycho thank you very much for your code sample and patch! It was veeery helpful and i added patch to build for arm64-windows to the vcpkg. Details there:

microsoft/vcpkg#16922 (comment)

Or full patch is in this fork and branch (all my last commits, I squash them from time to time): https://github.com/ptyio/vcpkg/commits/ptyio

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment