Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add commercial support, fix WASM and issues with Qt 6.7.+ #272

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
40 changes: 33 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ The desired version of Qt to install.

You can also pass in SimpleSpec version numbers, for example `6.2.*`.

Default: `5.15.2` (Last Qt 5 LTS)
Default: `6.8.1` (Last Qt 6 LTS)

**Please note that for Linux builds, Qt 6+ requires Ubuntu 20.04 or later.**

Expand All @@ -32,14 +32,14 @@ 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`, `mac`, `linux` or `all_os`

Defaults to the current platform it is being run on.

### `target`
This is the target platform that you will be building for. You will want to set this if you are building for iOS or Android. Please note that iOS builds are supported only on macOS hosts and Win RT builds are only supported on Windows hosts.

Possible values: `desktop`, `android`, `ios`, or `winrt`
Possible values: `desktop`, `android`, `ios`, `winrt` or `wasm`

Default: `desktop`

Expand Down Expand Up @@ -74,6 +74,32 @@ When possible, access your Qt directory through the `QT_ROOT_DIR` environment va

Default: `$RUNNER_WORKSPACE` (this is one folder above the starting directory)

### `use-official` (since `v4.3.0`)
Whether or not to use `aqtinstall` to install Qt using its official online installer (enabling the commercial versions
for those owning a license).
The parameter `host` will then be ignored, as you can only install commercial Qt versions on the OS running the installer.
Example:
```yml
- name: Install Qt
uses: jurplel/install-qt-action@v4
with:
version: '5.15.3'
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update this bit of docs with new default settings

target: 'desktop'
arch: 'win64_msvc2019_64'
aqtsource: 'git+https://github.com/Kidev/aqtinstall.git@install_qt_commercial'
use-official: true
email: '****@gmail.com'
pw: '****'
Comment on lines +91 to +92
Copy link
Contributor

@jdpurcell jdpurcell Feb 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Kidev Or perhaps (to prevent any unfortunate mistakes 😅):

Suggested change
email: '****@gmail.com'
pw: '****'
email: ${{ secrets.QT_EMAIL }}
pw: ${{ secrets.QT_PW }}

```

Default: `false`

#### `email`
If `use-official` is true, will use this username/email to authenticate with Qt servers

#### `pw`
If `use-official` is true, will use this password to authenticate with Qt servers

### `install-deps`
Whether or not to automatically install Qt dependencies on Linux through `apt`.

Expand Down Expand Up @@ -246,7 +272,7 @@ By default this is unset and ignored.

Version of [aqtinstall](https://github.com/miurahr/aqtinstall) to use, given in the format used by pip, for example: `==0.7.1`, `>=0.7.1`, `==0.7.*`. This is intended to be used to troubleshoot any bugs that might be caused or fixed by certain versions of aqtinstall.

Default: `==3.1.*`
Default: `==3.2.*`

### `py7zrversion`
Version of py7zr in the same style as the aqtversion and intended to be used for the same purpose.
Expand All @@ -264,10 +290,10 @@ Example value: `--external 7z`
- name: Install Qt
uses: jurplel/install-qt-action@v4
with:
version: '5.15.2'
version: '6.8.1'
host: 'windows'
target: 'desktop'
arch: 'win64_msvc2019_64'
arch: 'win64_msvc2022_64'
dir: '${{ github.workspace }}/example/'
install-deps: 'true'
modules: 'qtcharts qtwebengine'
Expand All @@ -278,7 +304,7 @@ Example value: `--external 7z`
tools: 'tools_ifw tools_qtcreator,qt.tools.qtcreator'
set-env: 'true'
tools-only: 'false'
aqtversion: '==3.1.*'
aqtversion: '==3.2.*'
py7zrversion: '==0.20.*'
extra: '--external 7z'
```
Expand Down
20 changes: 16 additions & 4 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ inputs:
description: Directory to install Qt
version:
description: Version of Qt to install
default: "5.15.2"
default: "6.8.1"
host:
description: Host platform
target:
Expand Down Expand Up @@ -55,10 +55,10 @@ inputs:
description: Location to source aqtinstall from in case of issues
aqtversion:
description: Version of aqtinstall to use in case of issues
default: ==3.1.*
default: ==3.2.*
py7zrversion:
description: Version of py7zr to use in case of issues
default: ==0.20.*
default: ==0.22.*
extra:
description: Any extra arguments to append to the back
source:
Expand All @@ -80,6 +80,15 @@ inputs:
description: Space-separated list of .7z example archives to install. Used to reduce download/image sizes.
example-modules:
description: Space-separated list of additional example modules to install.
use-official:
default: false
description: Whether to use aqtinstall to install Qt using the official installer, requires email & pw
email:
default: ''
description: Your Qt email
pw:
default: ''
description: Your Qt password
runs:
using: "composite"
steps:
Expand Down Expand Up @@ -118,4 +127,7 @@ runs:
examples: ${{ inputs.examples }}
example-archives: ${{ inputs.example-archives }}
example-modules: ${{ inputs.example-modules }}
extra: ${{ inputs.extra }}
extra: ${{ inputs.extra }}
use-official: ${{ inputs.use-official }}
email: ${{ inputs.email }}
pw: ${{ inputs.pw }}
15 changes: 12 additions & 3 deletions action/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ inputs:
description: Directory to install Qt
version:
description: Version of Qt to install
default: "5.15.2"
default: "6.8.1"
host:
description: Host platform
target:
Expand Down Expand Up @@ -52,10 +52,10 @@ inputs:
description: Location to source aqtinstall from in case of issues
aqtversion:
description: Version of aqtinstall to use in case of issues
default: ==3.1.*
default: ==3.2.*
py7zrversion:
description: Version of py7zr to use in case of issues
default: ==0.20.*
default: ==0.22.*
extra:
description: Any extra arguments to append to the back
source:
Expand All @@ -77,6 +77,15 @@ inputs:
description: Space-separated list of .7z example archives to install. Used to reduce download/image sizes.
example-modules:
description: Space-separated list of additional example modules to install.
use-official:
default: false
description: Whether to use aqtinstall to install Qt using the official installer, requires email & pw
email:
default: ''
description: Your Qt email
pw:
default: ''
description: Your Qt password
runs:
using: node20
main: lib/main.js
122 changes: 102 additions & 20 deletions action/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ const pythonCommand = (command: string, args: readonly string[]): string => {
const python = process.platform === "win32" ? "python" : "python3";
return `${python} -m ${command} ${args.join(" ")}`;
};

const execPython = async (command: string, args: readonly string[]): Promise<number> => {
return exec(pythonCommand(command, args));
};
Expand Down Expand Up @@ -99,15 +100,67 @@ const locateQtArchDir = (installDir: string): [string, boolean] => {
}
};

const locateQtWasmHostArchDir = (
installDir: string,
hostType: "windows" | "mac" | "linux" | "all_os",
target: "desktop" | "android" | "ios" | "wasm",
version: string
): [string, boolean] => {
// For WASM in all_os mode, use the host builder directory
if (hostType === "all_os" && target === "wasm") {
const versionDir = path.join(installDir, version);

switch (process.platform) {
case "win32": {
// Find mingw directories
const mingwPattern = /^win\d+_mingw\d+$/;
const mingwArches = glob
.sync(`${versionDir}/*/`)
.map((dir) => path.basename(dir))
.filter((dir) => mingwPattern.test(dir))
.sort((a, b) => {
const [aBits, aVer] = a
.match(/win(\d+)_mingw(\d+)/)
?.slice(1)
.map(Number) ?? [0, 0];
const [bBits, bVer] = b
.match(/win(\d+)_mingw(\d+)/)
?.slice(1)
.map(Number) ?? [0, 0];
if (aBits !== bBits) return bBits - aBits;
return bVer - aVer;
});

if (!mingwArches.length) {
throw Error(`Failed to locate a MinGW directory for WASM host in ${versionDir}`);
}
return [path.join(versionDir, mingwArches[0]), false];
}
case "darwin":
return [path.join(versionDir, "clang_64"), false];
default:
return [
path.join(
versionDir,
compareVersions(version, ">=", "6.7.0") ? "linux_gcc_64" : "gcc_64"
),
false,
];
}
}

return locateQtArchDir(installDir);
};

const isAutodesktopSupported = async (): Promise<boolean> => {
const rawOutput = await getPythonOutput("aqt", ["version"]);
const match = rawOutput.match(/aqtinstall\(aqt\)\s+v(\d+\.\d+\.\d+)/);
return match ? compareVersions(match[1], ">=", "3.0.0") : false;
};

class Inputs {
readonly host: "windows" | "mac" | "linux";
readonly target: "desktop" | "android" | "ios";
readonly host: "windows" | "mac" | "linux" | "all_os";
readonly target: "desktop" | "android" | "ios" | "wasm";
readonly version: string;
readonly arch: string;
readonly dir: string;
Expand Down Expand Up @@ -138,6 +191,10 @@ class Inputs {
readonly aqtVersion: string;
readonly py7zrVersion: string;

readonly useOfficial: boolean;
readonly email: string;
readonly pw: string;

constructor() {
const host = core.getInput("host");
// Set host automatically if omitted
Expand All @@ -158,19 +215,19 @@ class Inputs {
}
} else {
// Make sure host is one of the allowed values
if (host === "windows" || host === "mac" || host === "linux") {
if (host === "windows" || host === "mac" || host === "linux" || host === "all_os") {
this.host = host;
} else {
throw TypeError(`host: "${host}" is not one of "windows" | "mac" | "linux"`);
throw TypeError(`host: "${host}" is not one of "windows" | "mac" | "linux" | "all_os"`);
}
}

const target = core.getInput("target");
// Make sure target is one of the allowed values
if (target === "desktop" || target === "android" || target === "ios") {
if (target === "desktop" || target === "android" || target === "ios" || target === "wasm") {
this.target = target;
} else {
throw TypeError(`target: "${target}" is not one of "desktop" | "android" | "ios"`);
throw TypeError(`target: "${target}" is not one of "desktop" | "android" | "ios" | "wasm"`);
}

// An attempt to sanitize non-straightforward version number input
Expand Down Expand Up @@ -244,6 +301,10 @@ class Inputs {

this.py7zrVersion = core.getInput("py7zrversion");

this.useOfficial = Inputs.getBoolInput("use-official");
this.email = core.getInput("email");
this.pw = core.getInput("pw");

this.src = Inputs.getBoolInput("source");
this.srcArchives = Inputs.getStringArrayInput("src-archives");

Expand All @@ -269,6 +330,7 @@ class Inputs {
this.py7zrVersion,
this.aqtSource,
this.aqtVersion,
this.useOfficial ? "official" : "",
],
this.modules,
this.archives,
Expand Down Expand Up @@ -388,19 +450,34 @@ const run = async (): Promise<void> => {

// Install Qt
if (inputs.isInstallQtBinaries) {
const qtArgs = [
inputs.host,
inputs.target,
inputs.version,
...(inputs.arch ? [inputs.arch] : []),
...autodesktop,
...["--outputdir", inputs.dir],
...flaggedList("--modules", inputs.modules),
...flaggedList("--archives", inputs.archives),
...inputs.extra,
];

await execPython("aqt install-qt", qtArgs);
if (inputs.useOfficial && inputs.email && inputs.pw) {
const qtArgs = [
"install-qt-official",
inputs.target,
...(inputs.arch ? [inputs.arch] : []),
inputs.version,
...["--outputdir", inputs.dir],
...["--email", inputs.email],
...["--pw", inputs.pw],
...flaggedList("--modules", inputs.modules),
...inputs.extra,
];
await execPython("aqt", qtArgs);
} else {
const qtArgs = [
"install-qt",
inputs.host,
inputs.target,
inputs.version,
...(inputs.arch ? [inputs.arch] : []),
...autodesktop,
...["--outputdir", inputs.dir],
...flaggedList("--modules", inputs.modules),
...flaggedList("--archives", inputs.archives),
...inputs.extra,
];
await execPython("aqt", qtArgs);
}
}

const installSrcDocExamples = async (
Expand Down Expand Up @@ -457,7 +534,12 @@ const run = async (): Promise<void> => {
}
// Set environment variables/outputs for binaries
if (inputs.isInstallQtBinaries) {
const [qtPath, requiresParallelDesktop] = locateQtArchDir(inputs.dir);
const [qtPath, requiresParallelDesktop] = locateQtWasmHostArchDir(
inputs.dir,
inputs.host,
inputs.target,
inputs.version
);
// Set outputs
core.setOutput("qtPath", qtPath);

Expand Down