diff --git a/.github/workflows/test-android.yml b/.github/workflows/test-android.yml index 77bde40b..2afd90db 100644 --- a/.github/workflows/test-android.yml +++ b/.github/workflows/test-android.yml @@ -52,6 +52,22 @@ jobs: example-archives: ${{ matrix.qt.example-archives }} example-modules: ${{ matrix.qt.example-modules }} + - name: Test QT_HOST_PATH + if: ${{ startsWith(matrix.qt.version, '6.') }} + shell: pwsh + run: | + $qmakeHostPrefix = [string](Resolve-Path -Path (qmake -query QT_HOST_PREFIX)) + if ($env:QT_HOST_PATH -ne $qmakeHostPrefix) { + throw "QT_HOST_PATH should match qmake's QT_HOST_PREFIX." + } + if ($env:QT_HOST_PATH -eq $env:QT_ROOT_DIR) { + throw "QT_HOST_PATH and QT_ROOT_DIR should be different." + } + if ((Split-Path -Path $env:QT_HOST_PATH -Parent) -ne (Split-Path -Path $env:QT_ROOT_DIR -Parent)) { + throw "QT_HOST_PATH and QT_ROOT_DIR should have the same parent directory." + } + Write-Host "All tests passed!" + - name: Install Android NDK shell: bash # Links to NDK are at https://github.com/android/ndk/wiki/Unsupported-Downloads diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8b28d07f..3bd58beb 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -96,6 +96,11 @@ jobs: qt: tools-only-build: true add-tools-to-path: false + - os: ubuntu-24.04-arm + qt: + version: "6.8.1" + requested: "6.8.1" + modules: qtwebengine qtpositioning qtwebchannel steps: @@ -123,7 +128,7 @@ jobs: dir: ${{ matrix.dir }} modules: ${{ matrix.qt.modules }} version: ${{ matrix.qt.requested }} - tools: tools_ifw tools_qtcreator,qt.tools.qtcreator + tools: tools_ifw tools_qtcreator_gui,qt.tools.qtcreator_gui cache: ${{ matrix.cache == 'cached' }} - name: Install Qt with options and specified aqtversion @@ -134,7 +139,7 @@ jobs: dir: ${{ matrix.dir }} modules: ${{ matrix.qt.modules }} version: ${{ matrix.qt.requested }} - tools: tools_ifw tools_qtcreator,qt.tools.qtcreator + tools: tools_ifw tools_qtcreator_gui,qt.tools.qtcreator_gui cache: ${{ matrix.cache == 'cached' }} - name: Test QT_ROOT_DIR @@ -146,17 +151,14 @@ jobs: ls "${QT_ROOT_DIR}/bin/" | grep qmake - name: Switch macOS Xcode version with older Qt versions - if: ${{ matrix.qt.version && (startsWith(matrix.os, 'macos-13') || startsWith(matrix.os, 'macos-14')) }} + if: ${{ matrix.qt.version && startsWith(matrix.os, 'macos-13') }} shell: pwsh env: QT_VERSION: ${{ matrix.qt.version }} run: | - if ([version]$env:QT_VERSION -ge [version]"6.5.3") { - # GitHub macOS 13/14 runners use Xcode 15.0.x by default which has a known linker issue causing crashes if the artifact is run on macOS <= 12 - sudo xcode-select --switch /Applications/Xcode_15.2.app - } else { - # Keep older Qt versions on Xcode 14 due to concern over QTBUG-117484 - sudo xcode-select --switch /Applications/Xcode_14.3.1.app + if ([version]$env:QT_VERSION -lt [version]'6.5.3') { + # Workaround for QTBUG-117225 + sudo xcode-select --switch /Applications/Xcode_14.3.1.app } - name: Configure test project on windows @@ -231,7 +233,7 @@ jobs: with: dir: ${{ matrix.dir }} tools-only: true - tools: tools_ifw tools_qtcreator,qt.tools.qtcreator tools_cmake tools_ninja tools_conan + tools: tools_ifw tools_qtcreator_gui,qt.tools.qtcreator_gui tools_cmake tools_ninja tools_conan add-tools-to-path: ${{ matrix.qt.add-tools-to-path }} cache: ${{ matrix.cache == 'cached' }} @@ -243,7 +245,7 @@ jobs: set -x # tools_ifw: use `archivegen` to test that Tools/QtInstallerFramework/4.7/bin is added to path - # tools_qtcreator: use `qbs` to test that Tools/QtCreator/bin or "Qt Creator.app/Contents/MacOS/" is added to path + # tools_qtcreator_gui: use `qbs` to test that Tools/QtCreator/bin or "Qt Creator.app/Contents/MacOS/" is added to path # tools_cmake: test that Tools/CMake/bin or Tools/CMake/CMake.app/Contents/bin is added to path # tools_ninja: test that Tools/Ninja is added to path # tools_conan: test that Tools/Conan is added to path @@ -273,7 +275,7 @@ jobs: [[ -e "../Qt/Tools/Conan/conan" ]] # tools_ifw: use `archivegen` to test that Tools/QtInstallerFramework/4.7/bin is not added to path - # tools_qtcreator: use `qbs` to test that Tools/QtCreator/bin or "Qt Creator.app/Contents/MacOS/" is not added to path + # tools_qtcreator_gui: use `qbs` to test that Tools/QtCreator/bin or "Qt Creator.app/Contents/MacOS/" is not added to path # tools_cmake: test that Tools/CMake/bin or Tools/CMake/CMake.app/Contents/bin is not added to path # tools_ninja: test that Tools/Ninja is not added to path # tools_conan: test that Tools/Conan is not added to path diff --git a/README.md b/README.md index f613350b..a5acf843 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ This is the host platform of the Qt version you will be installing. It's unlikel For example, if you are building on Linux and targeting desktop, you would set host to `linux`. If you are building on Linux and targeting android, you would set host to `linux` also. The host platform is the platform that your application will build on, not its target platform. -Possible values: `windows`, `mac`, or `linux` +Possible values: `windows`, `windows_arm64`, `mac`, `linux` or `linux_arm64` Defaults to the current platform it is being run on. @@ -64,6 +64,8 @@ Windows w/ Qt >= 5.15 && Qt < 6.8: `win64_msvc2019_64` Windows w/ Qt >= 6.8: `win64_msvc2022_64` +Windows (ARM64) w/ Qt >= 6.8: `win64_msvc2022_arm64` + Android: `android_armv7` ### `dir` diff --git a/action/src/main.ts b/action/src/main.ts index 4aac05d2..6c28ceb5 100644 --- a/action/src/main.ts +++ b/action/src/main.ts @@ -71,29 +71,33 @@ const flaggedList = (flag: string, listArgs: readonly string[]): string[] => { return listArgs.length ? [flag, ...listArgs] : []; }; -const locateQtArchDir = (installDir: string): string => { +const locateQtArchDir = (installDir: string, host: string): [string, boolean] => { // For 6.4.2/gcc, qmake is at 'installDir/6.4.2/gcc_64/bin/qmake'. // This makes a list of all the viable arch directories that contain a qmake file. const qtArchDirs = glob .sync(`${installDir}/[0-9]*/*/bin/qmake*`) .map((s) => path.resolve(s, "..", "..")); - // For Qt6 mobile and wasm installations, and Qt6 Windows on ARM installations, + // For Qt6 mobile and wasm installations, and Qt6 Windows on ARM cross-compiled installations, // a standard desktop Qt installation must exist alongside the requested architecture. // In these cases, we must select the first item that ends with 'android*', 'ios', 'wasm*' or 'msvc*_arm64'. const requiresParallelDesktop = qtArchDirs.filter((archPath) => { const archDir = path.basename(archPath); const versionDir = path.basename(path.join(archPath, "..")); - return versionDir.match(/^6\.\d+\.\d+$/) && archDir.match(/^(android*|ios|wasm*|msvc*_arm64)$/); + return ( + versionDir.match(/^6\.\d+\.\d+$/) && + (archDir.match(/^(android.*|ios|wasm.*)$/) || + (archDir.match(/^msvc.*_arm64$/) && host !== "windows_arm64")) + ); }); if (requiresParallelDesktop.length) { // NOTE: if multiple mobile/wasm installations coexist, this may not select the desired directory - return requiresParallelDesktop[0]; + return [requiresParallelDesktop[0], true]; } else if (!qtArchDirs.length) { throw Error(`Failed to locate a Qt installation directory in ${installDir}`); } else { // NOTE: if multiple Qt installations exist, this may not select the desired directory - return qtArchDirs[0]; + return [qtArchDirs[0], false]; } }; @@ -104,7 +108,7 @@ const isAutodesktopSupported = async (): Promise => { }; class Inputs { - readonly host: "windows" | "mac" | "linux"; + readonly host: "windows" | "windows_arm64" | "mac" | "linux" | "linux_arm64"; readonly target: "desktop" | "android" | "ios"; readonly version: string; readonly arch: string; @@ -142,7 +146,7 @@ class Inputs { if (!host) { switch (process.platform) { case "win32": { - this.host = "windows"; + this.host = process.arch === "arm64" ? "windows_arm64" : "windows"; break; } case "darwin": { @@ -150,16 +154,24 @@ class Inputs { break; } default: { - this.host = "linux"; + this.host = process.arch === "arm64" ? "linux_arm64" : "linux"; break; } } } else { // Make sure host is one of the allowed values - if (host === "windows" || host === "mac" || host === "linux") { + if ( + host === "windows" || + host === "windows_arm64" || + host === "mac" || + host === "linux" || + host === "linux_arm64" + ) { this.host = host; } else { - throw TypeError(`host: "${host}" is not one of "windows" | "mac" | "linux"`); + throw TypeError( + `host: "${host}" is not one of "windows" | "windows_arm64" | "mac" | "linux" | "linux_arm64"` + ); } } @@ -198,6 +210,8 @@ class Inputs { } else { this.arch = "win64_msvc2017_64"; } + } else if (this.host === "windows_arm64") { + this.arch = "win64_msvc2022_arm64"; } } @@ -455,7 +469,7 @@ const run = async (): Promise => { } // Set environment variables/outputs for binaries if (inputs.isInstallQtBinaries) { - const qtPath = locateQtArchDir(inputs.dir); + const [qtPath, requiresParallelDesktop] = locateQtArchDir(inputs.dir, inputs.host); // Set outputs core.setOutput("qtPath", qtPath); @@ -474,6 +488,15 @@ const run = async (): Promise => { core.exportVariable("QT_ROOT_DIR", qtPath); core.exportVariable("QT_PLUGIN_PATH", path.resolve(qtPath, "plugins")); core.exportVariable("QML2_IMPORT_PATH", path.resolve(qtPath, "qml")); + if (requiresParallelDesktop) { + const hostPrefix = await fs.promises + .readFile(path.join(qtPath, "bin", "target_qt.conf"), "utf8") + .then((data) => data.match(/^HostPrefix=(.*)$/m)?.[1].trim() ?? "") + .catch(() => ""); + if (hostPrefix) { + core.exportVariable("QT_HOST_PATH", path.resolve(qtPath, "bin", hostPrefix)); + } + } core.addPath(path.resolve(qtPath, "bin")); } }