diff --git a/.github/workflows/build_wheels_windows.yml b/.github/workflows/build_wheels_windows.yml index 1ee786a9..19bfdb57 100644 --- a/.github/workflows/build_wheels_windows.yml +++ b/.github/workflows/build_wheels_windows.yml @@ -8,6 +8,7 @@ on: paths-ignore: - '.github/workflows/build_wheels_linux*' - '.github/workflows/build_wheels_macos*' + - '.github/workflows/build_wheels_windows_arm.yml' release: types: [published, edited] schedule: diff --git a/.github/workflows/build_wheels_windows_arm.yml b/.github/workflows/build_wheels_windows_arm.yml new file mode 100644 index 00000000..8e570a4f --- /dev/null +++ b/.github/workflows/build_wheels_windows_arm.yml @@ -0,0 +1,209 @@ +name: Windows ARM64 + +on: + pull_request: + branches: + - 4.x + - 5.x + paths-ignore: + - '.github/workflows/build_wheels_linux*' + - '.github/workflows/build_wheels_macos*' + - '.github/workflows/build_wheels_windows.yml' + release: + types: [published, edited] + schedule: + - cron: '0 3 * * 6' + workflow_dispatch: + + +jobs: + Build: + runs-on: windows-11-arm + strategy: + fail-fast: false + matrix: + python-version: ['3.11'] + platform: [arm64] + with_contrib: [0, 1] + without_gui: [0, 1] + build_sdist: [0] + env: + ACTIONS_ALLOW_UNSECURE_COMMANDS: true + SDIST: ${{ matrix.build_sdist || 0 }} + ENABLE_HEADLESS: ${{ matrix.without_gui }} + ENABLE_CONTRIB: ${{ matrix.with_contrib }} + OPENCV_TEST_DATA_PATH: ${{ github.workspace }}\opencv_extra\testdata + steps: + - name: Cleanup + shell: bash + run: | + rm -rf ./* || true + rm -rf ./.??* || true + working-directory: ${{ github.workspace }} + - name: Setup environment + shell: bash + run: | + if [[ "${{ github.event_name }}" == "schedule" || "${{ github.event_name }}" == "workflow_dispatch" ]]; then + echo "ENABLE_ROLLING=1" >> $GITHUB_ENV + fi + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: false + fetch-depth: 0 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + architecture: ${{ matrix.platform }} + - name: Setup MSBuild.exe + uses: microsoft/setup-msbuild@v1.1 + with: + msbuild-architecture: arm64 + - name: Build a package + run: | + python --version + python -m pip install --upgrade pip + python -m pip install --upgrade setuptools + python -m pip install cmake==4.1.0 + 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 + set "CI_BUILD=1" && python setup.py bdist_wheel --py-limited-api=cp37 --dist-dir=%cd%\wheelhouse -v + shell: cmd + - name: Saving all wheels + uses: actions/upload-artifact@v4 + with: + name: wheel-${{ matrix.with_contrib }}-${{ matrix.without_gui }}-${{ matrix.build_sdist }}-${{ matrix.platform }} + path: wheelhouse/opencv* + + Test: + needs: [Build] + runs-on: windows-11-arm + defaults: + run: + shell: cmd + strategy: + fail-fast: false + matrix: + python-version: ['3.11', '3.12', '3.13'] + platform: [arm64] + with_contrib: [0, 1] + without_gui: [0, 1] + build_sdist: [0] + env: + ACTIONS_ALLOW_UNSECURE_COMMANDS: true + OPENCV_TEST_DATA_PATH: ${{ github.workspace }}\opencv_extra\testdata + PYLINT_TEST_FILE: ${{ github.workspace }}\opencv\samples\python\squares.py + PlatformToolset: v143 + steps: + - name: Cleanup + shell: bash + run: | + rm -rf ./* || true + rm -rf ./.??* || true + working-directory: ${{ github.workspace }} + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: true + fetch-depth: 0 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + architecture: ${{ matrix.platform }} + - name: Download a wheel accordingly to matrix + uses: actions/download-artifact@v4 + with: + name: wheel-${{ matrix.with_contrib }}-${{ matrix.without_gui }}-${{ matrix.build_sdist }}-${{ matrix.platform }} + path: wheelhouse/ + - name: Package installation + run: | + cd ${{ github.workspace }}/tests + &python -m pip install --user --no-warn-script-location (ls "../wheelhouse/opencv*.whl") + if ($LastExitCode -ne 0) {throw $LastExitCode} + python get_build_info.py + shell: powershell + - name: Run tests + run: | + cd ${{ github.workspace }}/opencv + python modules\python\test\test.py -v --repo . + - name: Pylint test + run: | + python -m pip install pylint==2.15.9 + cd ${{ github.workspace }}\tests + python -m pylint $PYLINT_TEST_FILE + + Release_rolling: + if: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} + needs: [Build, Test] + runs-on: ubuntu-22.04 + environment: opencv-python-rolling-release + defaults: + run: + shell: bash + steps: + - uses: actions/download-artifact@v4 + with: + path: wheelhouse/ + - name: Upload wheels for opencv_python_rolling + run: | + python -m pip install twine + python -m twine upload -u ${{ secrets.OPENCV_PYTHON_ROLLING_USERNAME }} -p ${{ secrets.OPENCV_PYTHON_ROLLING_PASSWORD }} --skip-existing wheelhouse/opencv_python_rolling-* + - name: Upload wheels for opencv_contrib_python_rolling + run: | + python -m pip install twine + 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-* + - name: Upload wheels for opencv_python_headless_rolling + run: | + python -m pip install twine + 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-* + - name: Upload wheels for opencv_contrib_python_headless_rolling + run: | + python -m pip install twine + 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-* + + Pre-release: + if: github.event_name == 'release' && github.event.release.prerelease + needs: [Build, Test] + runs-on: ubuntu-22.04 + environment: test-opencv-python-release + defaults: + run: + shell: bash + steps: + - uses: actions/download-artifact@v4 + with: + path: wheelhouse/ + - name: Upload all wheels + run: | + python -m pip install twine + python -m twine upload --repository testpypi -u ${{ secrets.PYPI_USERNAME }} -p ${{ secrets.PYPI_PASSWORD }} --skip-existing wheelhouse/opencv_* + + Release: + if: github.event_name == 'release' && !github.event.release.prerelease + needs: [Build, Test] + runs-on: ubuntu-22.04 + environment: opencv-python-release + defaults: + run: + shell: bash + steps: + - uses: actions/download-artifact@v4 + with: + path: wheelhouse/ + - name: Upload wheels for opencv_python + run: | + python -m pip install twine + python -m twine upload -u ${{ secrets.OPENCV_PYTHON_USERNAME }} -p ${{ secrets.OPENCV_PYTHON_PASSWORD }} --skip-existing wheelhouse/opencv_python-* + - name: Upload wheels for opencv_contrib_python + run: | + python -m pip install twine + python -m twine upload -u ${{ secrets.OPENCV_CONTRIB_PYTHON_USERNAME }} -p ${{ secrets.OPENCV_CONTRIB_PYTHON_PASSWORD }} --skip-existing wheelhouse/opencv_contrib_python-* + - name: Upload wheels for opencv_python_headless + run: | + python -m pip install twine + python -m twine upload -u ${{ secrets.OPENCV_PYTHON_HEADLESS_USERNAME }} -p ${{ secrets.OPENCV_PYTHON_HEADLESS_PASSWORD }} --skip-existing wheelhouse/opencv_python_headless-* + - name: Upload wheels for opencv_contrib_python_headless + run: | + python -m pip install twine + 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-* diff --git a/pyproject.toml b/pyproject.toml index 58fba213..2a7ccf67 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,8 +1,9 @@ [build-system] requires = [ "numpy<2.0; python_version<'3.9'", - "numpy==2.0.2; python_version>='3.9' and python_version<'3.13'", - "numpy==2.1.3; python_version=='3.13'", + "numpy==2.0.2; python_version >= '3.9' and python_version < '3.13' and (sys_platform != 'win32' or platform_machine != 'ARM64')", + "numpy==2.1.3; python_version == '3.13' and (sys_platform != 'win32' or platform_machine != 'ARM64')", + "numpy==2.3.1;sys_platform == 'win32' and platform_machine == 'ARM64'", "packaging", "pip", "scikit-build>=0.14.0", diff --git a/setup.py b/setup.py index 7c470824..803cf874 100755 --- a/setup.py +++ b/setup.py @@ -26,7 +26,7 @@ def main(): # see https://numpy.org/doc/stable/release/2.3.0-notes.html#numpy-2-3-0-release-notes install_requires = [ 'numpy<2.0; python_version<"3.9"', - 'numpy(>=2, <2.3.0); python_version>="3.9"', + 'numpy(>=2, <=2.3.1); python_version>="3.9"', ] python_version = cmaker.CMaker.get_python_version() @@ -258,6 +258,11 @@ def main(): cmake_args.append("-DWITH_LAPACK=ON") cmake_args.append("-DENABLE_PRECOMPILED_HEADERS=OFF") + if sys.platform.startswith('win') and platform.machine().lower() in ("arm64", "aarch64"): + # 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 + cmake_args.append("-DCPU_BASELINE=NEON") + cmake_args.append("-DCPU_DISPATCH=NEON") + # works via side effect RearrangeCMakeOutput( rearrange_cmake_output_data, files_outside_package_dir, package_data.keys()