Skip to content

Instantly share code, notes, and snippets.

@tycho
Last active May 26, 2024 09:49
Show Gist options
  • 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
@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

@minnyres
Copy link

minnyres commented May 25, 2024

I tested that Qt 5.15.12 can be cross compiled in Developer PowerShell for VS 2022 without any patches:

./configure -opensource -confirm-license -nomake tests -nomake examples `
            -schannel -release -platform win32-msvc -xplatform win32-arm64-msvc2017 

You should not call vcvarsx86_arm64.bat or vcvarsamd64_arm64.bat, otherwise it will use the arm64 toolsets to build host tools like qmake, which are unexecutable on x64 systems.

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