Skip to content

Commit c54e4d7

Browse files
committed
Add CI support for building Windows on ARM wheels
1 parent 4924e6b commit c54e4d7

File tree

4 files changed

+219
-3
lines changed

4 files changed

+219
-3
lines changed

.github/workflows/build_wheels_windows.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ on:
88
paths-ignore:
99
- '.github/workflows/build_wheels_linux*'
1010
- '.github/workflows/build_wheels_macos*'
11+
- '.github/workflows/build_wheels_windows_arm.yml'
1112
release:
1213
types: [published, edited]
1314
schedule:
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
name: Windows ARM64
2+
3+
on:
4+
pull_request:
5+
branches:
6+
- 4.x
7+
- 5.x
8+
paths-ignore:
9+
- '.github/workflows/build_wheels_linux*'
10+
- '.github/workflows/build_wheels_macos*'
11+
- '.github/workflows/build_wheels_windows.yml'
12+
release:
13+
types: [published, edited]
14+
schedule:
15+
- cron: '0 3 * * 6'
16+
workflow_dispatch:
17+
18+
19+
jobs:
20+
Build:
21+
runs-on: windows-11-arm
22+
strategy:
23+
fail-fast: false
24+
matrix:
25+
python-version: ['3.11']
26+
platform: [arm64]
27+
with_contrib: [0, 1]
28+
without_gui: [0, 1]
29+
build_sdist: [0]
30+
env:
31+
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
32+
SDIST: ${{ matrix.build_sdist || 0 }}
33+
ENABLE_HEADLESS: ${{ matrix.without_gui }}
34+
ENABLE_CONTRIB: ${{ matrix.with_contrib }}
35+
OPENCV_TEST_DATA_PATH: ${{ github.workspace }}\opencv_extra\testdata
36+
steps:
37+
- name: Cleanup
38+
shell: bash
39+
run: |
40+
rm -rf ./* || true
41+
rm -rf ./.??* || true
42+
working-directory: ${{ github.workspace }}
43+
- name: Setup environment
44+
shell: bash
45+
run: |
46+
if [[ "${{ github.event_name }}" == "schedule" || "${{ github.event_name }}" == "workflow_dispatch" ]]; then
47+
echo "ENABLE_ROLLING=1" >> $GITHUB_ENV
48+
fi
49+
- name: Checkout
50+
uses: actions/checkout@v4
51+
with:
52+
submodules: false
53+
fetch-depth: 0
54+
- name: Set up Python ${{ matrix.python-version }}
55+
uses: actions/setup-python@v4
56+
with:
57+
python-version: ${{ matrix.python-version }}
58+
architecture: ${{ matrix.platform }}
59+
- name: Setup MSBuild.exe
60+
uses: microsoft/[email protected]
61+
with:
62+
msbuild-architecture: arm64
63+
- name: Build a package
64+
run: |
65+
python --version
66+
python -m pip install --upgrade pip
67+
python -m pip install --upgrade setuptools
68+
python -m pip install cmake==4.1.0
69+
python -m pip install toml && python -c "import toml; c = toml.load('pyproject.toml'); print('\n'.join(c['build-system']['requires']))" >> requirements.txt | python -m pip install -r requirements.txt
70+
set "CI_BUILD=1" && python setup.py bdist_wheel --py-limited-api=cp37 --dist-dir=%cd%\wheelhouse -v
71+
shell: cmd
72+
- name: Saving all wheels
73+
uses: actions/upload-artifact@v4
74+
with:
75+
name: wheel-${{ matrix.with_contrib }}-${{ matrix.without_gui }}-${{ matrix.build_sdist }}-${{ matrix.platform }}
76+
path: wheelhouse/opencv*
77+
78+
Test:
79+
needs: [Build]
80+
runs-on: windows-11-arm
81+
defaults:
82+
run:
83+
shell: cmd
84+
strategy:
85+
fail-fast: false
86+
matrix:
87+
python-version: ['3.11', '3.12', '3.13']
88+
platform: [arm64]
89+
with_contrib: [0, 1]
90+
without_gui: [0, 1]
91+
build_sdist: [0]
92+
env:
93+
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
94+
OPENCV_TEST_DATA_PATH: ${{ github.workspace }}\opencv_extra\testdata
95+
PYLINT_TEST_FILE: ${{ github.workspace }}\opencv\samples\python\squares.py
96+
PlatformToolset: v143
97+
steps:
98+
- name: Cleanup
99+
shell: bash
100+
run: |
101+
rm -rf ./* || true
102+
rm -rf ./.??* || true
103+
working-directory: ${{ github.workspace }}
104+
- name: Checkout
105+
uses: actions/checkout@v4
106+
with:
107+
submodules: true
108+
fetch-depth: 0
109+
- name: Set up Python ${{ matrix.python-version }}
110+
uses: actions/setup-python@v4
111+
with:
112+
python-version: ${{ matrix.python-version }}
113+
architecture: ${{ matrix.platform }}
114+
- name: Download a wheel accordingly to matrix
115+
uses: actions/download-artifact@v4
116+
with:
117+
name: wheel-${{ matrix.with_contrib }}-${{ matrix.without_gui }}-${{ matrix.build_sdist }}-${{ matrix.platform }}
118+
path: wheelhouse/
119+
- name: Package installation
120+
run: |
121+
cd ${{ github.workspace }}/tests
122+
&python -m pip install --user --no-warn-script-location (ls "../wheelhouse/opencv*.whl")
123+
if ($LastExitCode -ne 0) {throw $LastExitCode}
124+
python get_build_info.py
125+
shell: powershell
126+
- name: Run tests
127+
run: |
128+
cd ${{ github.workspace }}/opencv
129+
python modules\python\test\test.py -v --repo .
130+
- name: Pylint test
131+
run: |
132+
python -m pip install pylint==2.15.9
133+
cd ${{ github.workspace }}\tests
134+
python -m pylint $PYLINT_TEST_FILE
135+
136+
Release_rolling:
137+
if: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }}
138+
needs: [Build, Test]
139+
runs-on: ubuntu-22.04
140+
environment: opencv-python-rolling-release
141+
defaults:
142+
run:
143+
shell: bash
144+
steps:
145+
- uses: actions/download-artifact@v4
146+
with:
147+
path: wheelhouse/
148+
- name: Upload wheels for opencv_python_rolling
149+
run: |
150+
python -m pip install twine
151+
python -m twine upload -u ${{ secrets.OPENCV_PYTHON_ROLLING_USERNAME }} -p ${{ secrets.OPENCV_PYTHON_ROLLING_PASSWORD }} --skip-existing wheelhouse/opencv_python_rolling-*
152+
- name: Upload wheels for opencv_contrib_python_rolling
153+
run: |
154+
python -m pip install twine
155+
python -m twine upload -u ${{ secrets.OPENCV_CONTRIB_PYTHON_ROLLING_USERNAME }} -p ${{ secrets.OPENCV_CONTRIB_PYTHON_ROLLING_PASSWORD }} --skip-existing wheelhouse/opencv_contrib_python_rolling-*
156+
- name: Upload wheels for opencv_python_headless_rolling
157+
run: |
158+
python -m pip install twine
159+
python -m twine upload -u ${{ secrets.OPENCV_PYTHON_HEADLESS_ROLLING_USERNAME }} -p ${{ secrets.OPENCV_PYTHON_HEADLESS_ROLLING_PASSWORD }} --skip-existing wheelhouse/opencv_python_headless_rolling-*
160+
- name: Upload wheels for opencv_contrib_python_headless_rolling
161+
run: |
162+
python -m pip install twine
163+
python -m twine upload -u ${{ secrets.OPENCV_CONTRIB_PYTHON_HEADLESS_ROLLING_USERNAME }} -p ${{ secrets.OPENCV_CONTRIB_PYTHON_HEADLESS_ROLLING_PASSWORD }} --skip-existing wheelhouse/opencv_contrib_python_headless_rolling-*
164+
165+
Pre-release:
166+
if: github.event_name == 'release' && github.event.release.prerelease
167+
needs: [Build, Test]
168+
runs-on: ubuntu-22.04
169+
environment: test-opencv-python-release
170+
defaults:
171+
run:
172+
shell: bash
173+
steps:
174+
- uses: actions/download-artifact@v4
175+
with:
176+
path: wheelhouse/
177+
- name: Upload all wheels
178+
run: |
179+
python -m pip install twine
180+
python -m twine upload --repository testpypi -u ${{ secrets.PYPI_USERNAME }} -p ${{ secrets.PYPI_PASSWORD }} --skip-existing wheelhouse/opencv_*
181+
182+
Release:
183+
if: github.event_name == 'release' && !github.event.release.prerelease
184+
needs: [Build, Test]
185+
runs-on: ubuntu-22.04
186+
environment: opencv-python-release
187+
defaults:
188+
run:
189+
shell: bash
190+
steps:
191+
- uses: actions/download-artifact@v4
192+
with:
193+
path: wheelhouse/
194+
- name: Upload wheels for opencv_python
195+
run: |
196+
python -m pip install twine
197+
python -m twine upload -u ${{ secrets.OPENCV_PYTHON_USERNAME }} -p ${{ secrets.OPENCV_PYTHON_PASSWORD }} --skip-existing wheelhouse/opencv_python-*
198+
- name: Upload wheels for opencv_contrib_python
199+
run: |
200+
python -m pip install twine
201+
python -m twine upload -u ${{ secrets.OPENCV_CONTRIB_PYTHON_USERNAME }} -p ${{ secrets.OPENCV_CONTRIB_PYTHON_PASSWORD }} --skip-existing wheelhouse/opencv_contrib_python-*
202+
- name: Upload wheels for opencv_python_headless
203+
run: |
204+
python -m pip install twine
205+
python -m twine upload -u ${{ secrets.OPENCV_PYTHON_HEADLESS_USERNAME }} -p ${{ secrets.OPENCV_PYTHON_HEADLESS_PASSWORD }} --skip-existing wheelhouse/opencv_python_headless-*
206+
- name: Upload wheels for opencv_contrib_python_headless
207+
run: |
208+
python -m pip install twine
209+
python -m twine upload -u ${{ secrets.OPENCV_CONTRIB_PYTHON_HEADLESS_USERNAME }} -p ${{ secrets.OPENCV_CONTRIB_PYTHON_HEADLESS_PASSWORD }} --skip-existing wheelhouse/opencv_contrib_python_headless-*

pyproject.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
[build-system]
22
requires = [
33
"numpy<2.0; python_version<'3.9'",
4-
"numpy==2.0.2; python_version>='3.9' and python_version<'3.13'",
5-
"numpy==2.1.3; python_version=='3.13'",
4+
"numpy==2.0.2; python_version >= '3.9' and python_version < '3.13' and (sys_platform != 'win32' or platform_machine != 'ARM64')",
5+
"numpy==2.1.3; python_version == '3.13' and (sys_platform != 'win32' or platform_machine != 'ARM64')",
6+
"numpy==2.3.1;sys_platform == 'win32' and platform_machine == 'ARM64'",
67
"packaging",
78
"pip",
89
"scikit-build>=0.14.0",

setup.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def main():
2626
# see https://numpy.org/doc/stable/release/2.3.0-notes.html#numpy-2-3-0-release-notes
2727
install_requires = [
2828
'numpy<2.0; python_version<"3.9"',
29-
'numpy(>=2, <2.3.0); python_version>="3.9"',
29+
'numpy(>=2, <=2.3.1); python_version>="3.9"',
3030
]
3131

3232
python_version = cmaker.CMaker.get_python_version()
@@ -258,6 +258,11 @@ def main():
258258
cmake_args.append("-DWITH_LAPACK=ON")
259259
cmake_args.append("-DENABLE_PRECOMPILED_HEADERS=OFF")
260260

261+
if sys.platform.startswith('win') and platform.machine().lower() in ("arm64", "aarch64"):
262+
# MSVC does not support OpenCV dispatch features such as NEON_FP16, NEON_BF16 and NEON_DOTPROD. So use NEON as both baseline and dispatch units
263+
cmake_args.append("-DCPU_BASELINE=NEON")
264+
cmake_args.append("-DCPU_DISPATCH=NEON")
265+
261266
# works via side effect
262267
RearrangeCMakeOutput(
263268
rearrange_cmake_output_data, files_outside_package_dir, package_data.keys()

0 commit comments

Comments
 (0)