From ad20856738abe54c0fca65c51eeddf7e5fbf1f99 Mon Sep 17 00:00:00 2001 From: David Dalcino Date: Sun, 3 Apr 2022 22:22:13 -0700 Subject: [PATCH] Fix patching of Qt6.2.2-ios (#510) * Add tests for proper patching of Qt6.2.2-ios * Add a build target for ios installations * Add test coverage for mobile patching on linux This change folds in some refactoring as well, in an attempt to reduce repetitive logic, and make sure that this logic is used everywhere appropriate. --- aqt/updater.py | 70 +++++++-------- ci/generate_azure_pipelines_matrices.py | 1 + ci/steps.yml | 18 +++- tests/test_install.py | 112 +++++++++++++++++++++++- 4 files changed, 163 insertions(+), 38 deletions(-) diff --git a/aqt/updater.py b/aqt/updater.py index 23920223..86f78b9c 100644 --- a/aqt/updater.py +++ b/aqt/updater.py @@ -24,6 +24,7 @@ import re import subprocess from logging import getLogger +from typing import Union import patch @@ -33,6 +34,26 @@ from aqt.metadata import SimpleSpec, Version +def default_desktop_arch_dir(host: str, version: Union[Version, str]) -> str: + version: Version = version if isinstance(version, Version) else Version(version) + if host == "linux": + return "gcc_64" + elif host == "mac": + return "macos" if version in SimpleSpec(">=6.1.2") else "clang_64" + else: # Windows + # This is a temporary solution. This arch directory cannot exist for many versions of Qt. + # TODO: determine this dynamically + return "mingw81_64" + + +def dir_for_version(ver: Version) -> str: + return "5.9" if ver == Version("5.9.0") else f"{ver.major}.{ver.minor}.{ver.patch}" + + +def unpatched_path(os_name: str, final_component: str) -> str: + return ("/home/qt/work/install" if os_name == "linux" else "/Users/qt/work/install") + "/" + final_component + + class Updater: def __init__(self, prefix: pathlib.Path, logger): self.logger = logger @@ -160,30 +181,14 @@ def patch_qmake(self): newpath=bytes(str(self.prefix), "UTF-8"), ) - def patch_qmake_script(self, base_dir, qt_version, os_name): - if os_name == "linux": - self.logger.info("Patching {}/bin/qmake".format(self.prefix)) - self._patch_textfile( - self.prefix / "bin" / "qmake", - "/home/qt/work/install/bin", - "{}/{}/{}/bin".format(base_dir, qt_version, "gcc_64"), - ) - elif os_name == "mac": - self.logger.info("Patching {}/bin/qmake".format(self.prefix)) - self._patch_textfile( - self.prefix / "bin" / "qmake", - "/Users/qt/work/install/bin", - "{}/{}/{}/bin".format(base_dir, qt_version, "clang_64"), - ) - elif os_name == "windows": - self.logger.info("Patching {}/bin/qmake.bat".format(self.prefix)) - self._patch_textfile( - self.prefix / "bin" / "qmake.bat", - "/Users/qt/work/install/bin", - "{}\\{}\\{}\\bin".format(base_dir, qt_version, "mingw81_64"), - ) - else: - pass + def patch_qmake_script(self, base_dir, qt_version: str, os_name): + arch_dir = default_desktop_arch_dir(os_name, qt_version) + sep = "\\" if os_name == "windows" else "/" + patched = sep.join([base_dir, qt_version, arch_dir, "bin"]) + unpatched = unpatched_path(os_name, "bin") + qmake_path = self.prefix / "bin" / ("qmake.bat" if os_name == "windows" else "qmake") + self.logger.info(f"Patching {qmake_path}") + self._patch_textfile(qmake_path, unpatched, patched) def patch_qtcore(self, target): """patch to QtCore""" @@ -235,15 +240,8 @@ def set_license(self, base_dir, qt_version, arch_dir): def patch_target_qt_conf(self, base_dir, qt_version, arch_dir, os_name): target_qt_conf = self.prefix / "bin" / "target_qt.conf" - if os_name == "linux": - old_targetprefix = "Prefix=/home/qt/work/install/target" - new_hostprefix = "HostPrefix=../../gcc_64" - elif os_name == "mac": - old_targetprefix = "Prefix=/Users/qt/work/install/target" - new_hostprefix = "HostPrefix=../../clang_64" - else: - old_targetprefix = "Prefix=/Users/qt/work/install/target" - new_hostprefix = "HostPrefix=../../mingw81_64" + old_targetprefix = f'Prefix={unpatched_path(os_name, "target")}' + new_hostprefix = f"HostPrefix=../../{default_desktop_arch_dir(os_name, qt_version)}" new_targetprefix = "Prefix={}".format(str(pathlib.Path(base_dir).joinpath(qt_version, arch_dir, "target"))) new_hostdata = "HostData=../{}".format(arch_dir) self._patch_textfile(target_qt_conf, old_targetprefix, new_targetprefix) @@ -260,7 +258,7 @@ def update(cls, target: TargetConfig, base_dir: str): arch = target.arch version = Version(target.version) os_name = target.os_name - version_dir = "5.9" if version == Version("5.9.0") else target.version + version_dir = dir_for_version(version) if arch is None: arch_dir = "" elif arch.startswith("win64_mingw"): @@ -274,8 +272,8 @@ def update(cls, target: TargetConfig, base_dir: str): arch_dir = b + "_" + a else: arch_dir = arch[6:] - elif version in SimpleSpec(">=6.1.2") and os_name == "mac" and arch == "clang_64": - arch_dir = "macos" + elif os_name == "mac" and arch == "clang_64": + arch_dir = default_desktop_arch_dir(os_name, version) else: arch_dir = arch try: diff --git a/ci/generate_azure_pipelines_matrices.py b/ci/generate_azure_pipelines_matrices.py index ce7879b4..b6bd5456 100644 --- a/ci/generate_azure_pipelines_matrices.py +++ b/ci/generate_azure_pipelines_matrices.py @@ -269,6 +269,7 @@ def __init__(self, platform, build_jobs): mac_build_jobs.extend( [ BuildJob("install-qt", "5.15.2", "mac", "ios", "ios", "ios"), + BuildJob("install-qt", "6.2.2", "mac", "ios", "ios", "ios", module="qtsensors"), BuildJob( "install-qt", "6.1.0", "mac", "android", "android_armv7", "android_armv7" ), diff --git a/ci/steps.yml b/ci/steps.yml index 8eb16d01..aaa0d58a 100644 --- a/ci/steps.yml +++ b/ci/steps.yml @@ -54,7 +54,8 @@ steps: if [[ "$(HOST)" == "windows" ]]; then python -m aqt install-qt $(HOST) desktop $(QT_VERSION) mingw81_64 --archives qtbase else - python -m aqt install-qt $(HOST) desktop $(QT_VERSION) --archives qtbase + # qtdeclarative contains `qmlimportscanner`: necessary for ios builds, Qt6+ + python -m aqt install-qt $(HOST) desktop $(QT_VERSION) --archives qtbase qtdeclarative fi fi if [[ "$(OUTPUT_DIR)" != "" ]]; then @@ -174,6 +175,21 @@ steps: condition: and(eq(variables['TARGET'], 'android'), or(eq(variables['Agent.OS'], 'Linux'), eq(variables['Agent.OS'], 'Darwin')), ne(variables['SUBCOMMAND'], 'list'), ne(variables['SUBCOMMAND'], 'install-tool')) displayName: Build accelbubble example application to test for android + ##---------------------------------------------------- + # for iOS target + - bash: | + set -ex + mkdir $(Build.BinariesDirectory)/tests + (cd $(Build.BinariesDirectory)/tests; 7zr x $(Build.SourcesDirectory)/ci/accelbubble.7z) + export PATH=$(QT_BINDIR):$PATH + qmake $(Build.BinariesDirectory)/tests/accelbubble + make + condition: | + and(eq(variables['TARGET'], 'ios'), + ne(variables['SUBCOMMAND'], 'list'), + ne(variables['SUBCOMMAND'], 'install-tool')) + displayName: Build accelbubble example application to test for ios + ##---------------------------------------------------- # Cache Powershell Modules in $MODULES_FOLDER - task: Cache@2 diff --git a/tests/test_install.py b/tests/test_install.py index a1abb93b..64478f20 100644 --- a/tests/test_install.py +++ b/tests/test_install.py @@ -574,7 +574,117 @@ def tool_archive(host: str, tool_name: str, variant: str, date: datetime = datet r"^aqtinstall\(aqt\) v.* on Python 3.*\n" r"Downloading qtbase...\n" r"Finished installation of qtbase-windows-android_armv7.7z in .*\n" - r"Patching .*/bin/qmake.bat\n" + r"Patching .*6\.1\.0[/\\]android_armv7[/\\]bin[/\\]qmake.bat\n" + r"Finished installation\n" + r"Time elapsed: .* second" + ), + ), + ( + "install-qt linux android 6.3.0 android_arm64_v8a".split(), + "linux", + "android", + "6.3.0", + "android_arm64_v8a", + "android_arm64_v8a", + "linux_x64/android/qt6_630_arm64_v8a/Updates.xml", + [ + MockArchive( + filename_7z="qtbase-linux-android_arm64_v8a.7z", + update_xml_name="qt.qt6.630.android_arm64_v8a", + contents=( + # Qt 6 non-desktop should patch qconfig.pri, qmake script and target_qt.conf + PatchedFile( + filename="mkspecs/qconfig.pri", + unpatched_content="... blah blah blah ...\n" + "QT_EDITION = Not OpenSource\n" + "QT_LICHECK = Not Empty\n" + "... blah blah blah ...\n", + patched_content="... blah blah blah ...\n" + "QT_EDITION = OpenSource\n" + "QT_LICHECK =\n" + "... blah blah blah ...\n", + ), + PatchedFile( + filename="bin/target_qt.conf", + unpatched_content="Prefix=/home/qt/work/install/target\n" + "HostPrefix=../../\n" + "HostData=target\n", + patched_content="Prefix={base_dir}{sep}6.3.0{sep}android_arm64_v8a{sep}target\n" + "HostPrefix=../../gcc_64\n" + "HostData=../android_arm64_v8a\n", + ), + PatchedFile( + filename="bin/qmake", + unpatched_content="... blah blah blah ...\n" + "/home/qt/work/install/bin\n" + "... blah blah blah ...\n", + patched_content="... blah blah blah ...\n" + "{base_dir}/6.3.0/gcc_64/bin\n" + "... blah blah blah ...\n", + ), + ), + ), + ], + re.compile( + r"^aqtinstall\(aqt\) v.* on Python 3.*\n" + r"Downloading qtbase...\n" + r"Finished installation of qtbase-linux-android_arm64_v8a.7z in .*\n" + r"Patching .*6\.3\.0[/\\]android_arm64_v8a[/\\]bin[/\\]qmake\n" + r"Finished installation\n" + r"Time elapsed: .* second" + ), + ), + ( + "install-qt mac ios 6.1.2".split(), + "mac", + "ios", + "6.1.2", + "ios", + "ios", + "mac_x64/ios/qt6_612/Updates.xml", + [ + MockArchive( + filename_7z="qtbase-mac-ios.7z", + update_xml_name="qt.qt6.612.ios", + contents=( + # Qt 6 non-desktop should patch qconfig.pri, qmake script and target_qt.conf + PatchedFile( + filename="mkspecs/qconfig.pri", + unpatched_content="... blah blah blah ...\n" + "QT_EDITION = Not OpenSource\n" + "QT_LICHECK = Not Empty\n" + "... blah blah blah ...\n", + patched_content="... blah blah blah ...\n" + "QT_EDITION = OpenSource\n" + "QT_LICHECK =\n" + "... blah blah blah ...\n", + ), + PatchedFile( + filename="bin/target_qt.conf", + unpatched_content="Prefix=/Users/qt/work/install/target\n" + "HostPrefix=../../\n" + "HostData=target\n", + patched_content="Prefix={base_dir}{sep}6.1.2{sep}ios{sep}target\n" + "HostPrefix=../../macos\n" + "HostData=../ios\n", + ), + PatchedFile( + filename="bin/qmake", + unpatched_content="... blah blah blah ...\n" + "/Users/qt/work/install/bin\n" + "... blah blah blah ...\n", + patched_content="... blah blah blah ...\n" + "{base_dir}/6.1.2/macos/bin\n" + "... blah blah blah ...\n", + ), + ), + ), + ], + re.compile( + r"^aqtinstall\(aqt\) v.* on Python 3.*\n" + r"Downloading qtbase...\n" + r"Finished installation of qtbase-mac-ios.7z in .*\n" + r"Patching .*6\.1\.2[/\\]ios[/\\]bin[/\\]qmake\n" r"Finished installation\n" r"Time elapsed: .* second" ),