Skip to content

Commit dcafb9d

Browse files
committed
ci: install Qt dev tools on Linux, verify qmake, export QMAKE; fix PyQt6 sipbuild qmake error across build and release
1 parent b0e5445 commit dcafb9d

3 files changed

Lines changed: 216 additions & 0 deletions

File tree

.github/workflows/build.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,37 @@ jobs:
3535
with:
3636
python-version: ${{ matrix.python-version }}
3737

38+
- name: Install Qt dev tools (Linux only)
39+
if: runner.os == 'Linux'
40+
shell: bash
41+
run: |
42+
set -euo pipefail
43+
if command -v apt-get >/dev/null 2>&1; then
44+
sudo apt-get update
45+
# Try Qt6 first (qmake6 provided by qt6-base-dev-tools on Debian/Ubuntu)
46+
sudo apt-get install -y --no-install-recommends \
47+
build-essential \
48+
qt6-base-dev qt6-base-dev-tools || true
49+
# Fallback to Qt5 packages if Qt6 not available on the image
50+
sudo apt-get install -y --no-install-recommends \
51+
qtbase5-dev qtbase5-dev-tools qtchooser qt5-qmake || true
52+
# Useful runtime libs sometimes needed by PyInstaller apps
53+
sudo apt-get install -y --no-install-recommends libgl1 libglib2.0-0 || true
54+
fi
55+
56+
- name: Check qmake (Linux only)
57+
if: runner.os == 'Linux'
58+
shell: bash
59+
run: |
60+
set -euo pipefail
61+
which qmake6 || true
62+
which qmake || true
63+
qmake6 --version || true
64+
qmake --version || true
65+
# Export QMAKE for downstream build tooling if present
66+
if command -v qmake6 >/dev/null 2>&1; then echo "QMAKE=$(which qmake6)" >> $GITHUB_ENV;
67+
elif command -v qmake >/dev/null 2>&1; then echo "QMAKE=$(which qmake)" >> $GITHUB_ENV; fi
68+
3869
- name: Install dependencies
3970
shell: bash
4071
run: |
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
name: build-and-release-template
2+
3+
# How to use:
4+
# 1) Copy this file to .github/workflows/build-and-release.yml in your repo.
5+
# 2) Set APP_ENTRY_FILES to your Python entry points (space-separated).
6+
# 3) Optionally adjust APP_NAMES to control output binary names.
7+
# 4) Push to default branch to build; create a tag vX.Y.Z to publish a Release with assets.
8+
9+
on:
10+
push:
11+
branches: [ master, main ]
12+
paths:
13+
- '**/*.py'
14+
- '.github/workflows/**'
15+
- 'requirements.txt'
16+
pull_request:
17+
branches: [ master, main ]
18+
paths:
19+
- '**/*.py'
20+
- '.github/workflows/**'
21+
- 'requirements.txt'
22+
workflow_dispatch: {}
23+
24+
env:
25+
# Space-separated list of Python entry-point files to build
26+
APP_ENTRY_FILES: "app_gui_qt.py app_gui_tk.py" # CHANGE ME
27+
# Matching space-separated list of output app names (no extension)
28+
APP_NAMES: "MyApp-PyQt MyApp-Tkinter" # CHANGE ME
29+
30+
jobs:
31+
build:
32+
name: Build binaries (${{ matrix.os }} / py ${{ matrix.python-version }})
33+
runs-on: ${{ matrix.os }}
34+
strategy:
35+
fail-fast: false
36+
matrix:
37+
os: [windows-latest, windows-11-arm, macos-13, macos-14, ubuntu-latest, ubuntu-22.04-arm]
38+
python-version: ['3.11']
39+
steps:
40+
- name: Checkout
41+
uses: actions/checkout@v4
42+
43+
- name: Set up Python
44+
uses: actions/setup-python@v5
45+
with:
46+
python-version: ${{ matrix.python-version }}
47+
48+
- name: Install dependencies
49+
shell: bash
50+
run: |
51+
python -m pip install --upgrade pip
52+
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
53+
pip install pyinstaller
54+
55+
- name: Install Qt dev tools (Linux only)
56+
if: runner.os == 'Linux'
57+
shell: bash
58+
run: |
59+
set -euo pipefail
60+
if command -v apt-get >/dev/null 2>&1; then
61+
sudo apt-get update
62+
sudo apt-get install -y --no-install-recommends \
63+
build-essential \
64+
qt6-base-dev qt6-base-dev-tools || true
65+
sudo apt-get install -y --no-install-recommends \
66+
qtbase5-dev qtbase5-dev-tools qtchooser qt5-qmake || true
67+
sudo apt-get install -y --no-install-recommends libgl1 libglib2.0-0 || true
68+
fi
69+
70+
- name: Check qmake (Linux only)
71+
if: runner.os == 'Linux'
72+
shell: bash
73+
run: |
74+
set -euo pipefail
75+
which qmake6 || true
76+
which qmake || true
77+
qmake6 --version || true
78+
qmake --version || true
79+
if command -v qmake6 >/dev/null 2>&1; then echo "QMAKE=$(which qmake6)" >> $GITHUB_ENV;
80+
elif command -v qmake >/dev/null 2>&1; then echo "QMAKE=$(which qmake)" >> $GITHUB_ENV; fi
81+
82+
- name: Install Linux extras (patchelf)
83+
if: runner.os == 'Linux'
84+
shell: bash
85+
run: |
86+
if command -v apt-get >/dev/null 2>&1; then
87+
sudo apt-get update && sudo apt-get install -y patchelf
88+
fi
89+
90+
- name: Build apps with PyInstaller
91+
shell: bash
92+
run: |
93+
set -euo pipefail
94+
read -ra ENTRIES <<<"$APP_ENTRY_FILES"
95+
read -ra NAMES <<<"$APP_NAMES"
96+
if [ ${#ENTRIES[@]} -ne ${#NAMES[@]} ]; then
97+
echo "APP_ENTRY_FILES and APP_NAMES length mismatch" >&2
98+
exit 1
99+
fi
100+
for i in "${!ENTRIES[@]}"; do
101+
entry=${ENTRIES[$i]}
102+
name=${NAMES[$i]}
103+
echo "Building $entry -> $name"
104+
pyinstaller --name "$name" --noconfirm --onefile --windowed "$entry"
105+
done
106+
107+
- name: Package artifacts (OS+arch suffixed)
108+
shell: bash
109+
run: |
110+
set -euo pipefail
111+
mkdir -p artifacts
112+
arch_lc=$(echo "${{ runner.arch }}" | tr '[:upper:]' '[:lower:]')
113+
if [[ "$RUNNER_OS" == "Windows" ]]; then
114+
for f in dist/*.exe; do
115+
base=$(basename "$f" .exe)
116+
cp "$f" "artifacts/${base}-win-${arch_lc}.exe"
117+
done
118+
elif [[ "$RUNNER_OS" == "macOS" ]]; then
119+
cd dist
120+
for app in *.app; do
121+
base=${app%.app}
122+
zip -r "../artifacts/${base}-macos-${arch_lc}.app.zip" "$app"
123+
done
124+
cd -
125+
else
126+
for f in dist/*; do
127+
base=$(basename "$f")
128+
cp "$f" "artifacts/${base}-linux-${arch_lc}"
129+
done
130+
fi
131+
132+
- name: Upload artifacts
133+
uses: actions/upload-artifact@v4
134+
with:
135+
name: ${{ runner.os }}-${{ runner.arch }}-binaries
136+
path: artifacts/*
137+
138+
release:
139+
name: Release on tag push
140+
if: startsWith(github.ref, 'refs/tags/v')
141+
needs: build
142+
runs-on: ubuntu-latest
143+
permissions:
144+
contents: write
145+
steps:
146+
- name: Download all build artifacts
147+
uses: actions/download-artifact@v4
148+
with:
149+
pattern: "*-binaries"
150+
merge-multiple: true
151+
path: release-assets
152+
153+
- name: Create GitHub Release
154+
uses: softprops/action-gh-release@v2
155+
with:
156+
files: release-assets/*
157+
env:
158+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.github/workflows/release.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,33 @@ jobs:
2626
with:
2727
python-version: ${{ matrix.python-version }}
2828

29+
- name: Install Qt dev tools (Linux only)
30+
if: runner.os == 'Linux'
31+
shell: bash
32+
run: |
33+
set -euo pipefail
34+
if command -v apt-get >/dev/null 2>&1; then
35+
sudo apt-get update
36+
sudo apt-get install -y --no-install-recommends \
37+
build-essential \
38+
qt6-base-dev qt6-base-dev-tools || true
39+
sudo apt-get install -y --no-install-recommends \
40+
qtbase5-dev qtbase5-dev-tools qtchooser qt5-qmake || true
41+
sudo apt-get install -y --no-install-recommends libgl1 libglib2.0-0 || true
42+
fi
43+
44+
- name: Check qmake (Linux only)
45+
if: runner.os == 'Linux'
46+
shell: bash
47+
run: |
48+
set -euo pipefail
49+
which qmake6 || true
50+
which qmake || true
51+
qmake6 --version || true
52+
qmake --version || true
53+
if command -v qmake6 >/dev/null 2>&1; then echo "QMAKE=$(which qmake6)" >> $GITHUB_ENV;
54+
elif command -v qmake >/dev/null 2>&1; then echo "QMAKE=$(which qmake)" >> $GITHUB_ENV; fi
55+
2956
- name: Install dependencies
3057
shell: bash
3158
run: |

0 commit comments

Comments
 (0)