mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-11-10 19:56:47 +03:00
Merge pull request #7580 from nulano/cibuildwheel-docker
Build Windows wheels using cibuildwheel
This commit is contained in:
commit
316f39702c
48
.github/workflows/test-windows.yml
vendored
48
.github/workflows/test-windows.yml
vendored
|
@ -72,10 +72,10 @@ jobs:
|
|||
- name: Install dependencies
|
||||
id: install
|
||||
run: |
|
||||
7z x winbuild\depends\nasm-2.16.01-win64.zip "-o$env:RUNNER_WORKSPACE\"
|
||||
echo "$env:RUNNER_WORKSPACE\nasm-2.16.01" >> $env:GITHUB_PATH
|
||||
choco install nasm --no-progress
|
||||
echo "C:\Program Files\NASM" >> $env:GITHUB_PATH
|
||||
|
||||
choco install ghostscript --version=10.0.0.20230317
|
||||
choco install ghostscript --version=10.0.0.20230317 --no-progress
|
||||
echo "C:\Program Files\gs\gs10.00.0\bin" >> $env:GITHUB_PATH
|
||||
|
||||
# Install extra test images
|
||||
|
@ -167,7 +167,6 @@ jobs:
|
|||
- name: Build Pillow
|
||||
run: |
|
||||
$FLAGS="-C raqm=vendor -C fribidi=vendor"
|
||||
if ('${{ github.event_name }}' -ne 'pull_request') { $FLAGS+=" -C imagequant=disable" }
|
||||
cmd /c "winbuild\build\build_env.cmd && $env:pythonLocation\python.exe -m pip install -v $FLAGS ."
|
||||
& $env:pythonLocation\python.exe selftest.py --installed
|
||||
shell: pwsh
|
||||
|
@ -209,47 +208,6 @@ jobs:
|
|||
flags: GHA_Windows
|
||||
name: ${{ runner.os }} Python ${{ matrix.python-version }}
|
||||
|
||||
- name: Build wheel
|
||||
id: wheel
|
||||
if: "github.event_name != 'pull_request'"
|
||||
run: |
|
||||
mkdir fribidi
|
||||
copy winbuild\build\bin\fribidi* fribidi
|
||||
setlocal EnableDelayedExpansion
|
||||
for %%f in (winbuild\build\license\*) do (
|
||||
set x=%%~nf
|
||||
rem Skip FriBiDi license, it is not included in the wheel.
|
||||
set fribidi=!x:~0,7!
|
||||
if NOT !fribidi!==fribidi (
|
||||
rem Skip imagequant license, it is not included in the wheel.
|
||||
set libimagequant=!x:~0,13!
|
||||
if NOT !libimagequant!==libimagequant (
|
||||
echo. >> LICENSE
|
||||
echo ===== %%~nf ===== >> LICENSE
|
||||
echo. >> LICENSE
|
||||
type %%f >> LICENSE
|
||||
)
|
||||
)
|
||||
)
|
||||
for /f "tokens=3 delims=/" %%a in ("${{ github.ref }}") do echo dist=dist-%%a >> %GITHUB_OUTPUT%
|
||||
call winbuild\\build\\build_env.cmd
|
||||
%pythonLocation%\python.exe -m pip wheel -v -C raqm=vendor -C fribidi=vendor -C imagequant=disable .
|
||||
shell: cmd
|
||||
|
||||
- name: Upload wheel
|
||||
uses: actions/upload-artifact@v3
|
||||
if: "github.event_name != 'pull_request'"
|
||||
with:
|
||||
name: ${{ steps.wheel.outputs.dist }}
|
||||
path: "*.whl"
|
||||
|
||||
- name: Upload fribidi.dll
|
||||
if: "github.event_name != 'pull_request' && matrix.python-version == 3.11"
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: fribidi
|
||||
path: fribidi\*
|
||||
|
||||
success:
|
||||
permissions:
|
||||
contents: none
|
||||
|
|
22
.github/workflows/wheels-test.ps1
vendored
Normal file
22
.github/workflows/wheels-test.ps1
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
param ([string]$venv, [string]$pillow="C:\pillow")
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$ProgressPreference = 'SilentlyContinue'
|
||||
Set-PSDebug -Trace 1
|
||||
if ("$venv" -like "*\cibw-run-*\pp*-win_amd64\*") {
|
||||
# unlike CPython, PyPy requires Visual C++ Redistributable to be installed
|
||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||
Invoke-WebRequest -Uri 'https://aka.ms/vs/15/release/vc_redist.x64.exe' -OutFile 'vc_redist.x64.exe'
|
||||
C:\vc_redist.x64.exe /install /quiet /norestart | Out-Null
|
||||
}
|
||||
$env:path += ";$pillow\winbuild\build\bin\"
|
||||
& "$venv\Scripts\activate.ps1"
|
||||
& reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\python.exe" /v "GlobalFlag" /t REG_SZ /d "0x02000000" /f
|
||||
cd $pillow
|
||||
& python -VV
|
||||
if (!$?) { exit $LASTEXITCODE }
|
||||
& python selftest.py
|
||||
if (!$?) { exit $LASTEXITCODE }
|
||||
& python -m pytest -vx Tests\check_wheel.py
|
||||
if (!$?) { exit $LASTEXITCODE }
|
||||
& python -m pytest -vx Tests
|
||||
if (!$?) { exit $LASTEXITCODE }
|
22
.github/workflows/wheels-test.sh
vendored
22
.github/workflows/wheels-test.sh
vendored
|
@ -1,10 +1,6 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
EXP_CODECS="jpg jpg_2000 libtiff zlib"
|
||||
EXP_MODULES="freetype2 littlecms2 pil tkinter webp"
|
||||
EXP_FEATURES="fribidi harfbuzz libjpeg_turbo raqm transp_webp webp_anim webp_mux xcb"
|
||||
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
brew install fribidi
|
||||
export PKG_CONFIG_PATH="/usr/local/opt/openblas/lib/pkgconfig"
|
||||
|
@ -25,21 +21,5 @@ fi
|
|||
|
||||
# Runs tests
|
||||
python3 selftest.py
|
||||
python3 -m pytest Tests/check_wheel.py
|
||||
python3 -m pytest
|
||||
|
||||
# Test against expected codecs, modules and features
|
||||
codecs=$(python3 -c 'from PIL.features import *; print(" ".join(sorted(get_supported_codecs())))')
|
||||
if [ "$codecs" != "$EXP_CODECS" ]; then
|
||||
echo "Codecs should be: '$EXP_CODECS'; but are '$codecs'"
|
||||
exit 1
|
||||
fi
|
||||
modules=$(python3 -c 'from PIL.features import *; print(" ".join(sorted(get_supported_modules())))')
|
||||
if [ "$modules" != "$EXP_MODULES" ]; then
|
||||
echo "Modules should be: '$EXP_MODULES'; but are '$modules'"
|
||||
exit 1
|
||||
fi
|
||||
features=$(python3 -c 'from PIL.features import *; print(" ".join(sorted(get_supported_features())))')
|
||||
if [ "$features" != "$EXP_FEATURES" ]; then
|
||||
echo "Features should be: '$EXP_FEATURES'; but are '$features'"
|
||||
exit 1
|
||||
fi
|
||||
|
|
109
.github/workflows/wheels.yml
vendored
109
.github/workflows/wheels.yml
vendored
|
@ -3,14 +3,20 @@ name: Wheels
|
|||
on:
|
||||
push:
|
||||
paths:
|
||||
- ".github/workflows/wheels*.yml"
|
||||
- ".ci/requirements-cibw.txt"
|
||||
- ".github/workflows/wheel*"
|
||||
- "wheels/*"
|
||||
- "winbuild/build_prepare.py"
|
||||
- "winbuild/fribidi.cmake"
|
||||
tags:
|
||||
- "*"
|
||||
pull_request:
|
||||
paths:
|
||||
- ".github/workflows/wheels*.yml"
|
||||
- ".ci/requirements-cibw.txt"
|
||||
- ".github/workflows/wheel*"
|
||||
- "wheels/*"
|
||||
- "winbuild/build_prepare.py"
|
||||
- "winbuild/fribidi.cmake"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
|
@ -63,7 +69,6 @@ jobs:
|
|||
env:
|
||||
CIBW_ARCHS: ${{ matrix.archs }}
|
||||
CIBW_BUILD: ${{ matrix.build }}
|
||||
CIBW_CONFIG_SETTINGS: raqm=enable raqm=vendor fribidi=vendor
|
||||
CIBW_MANYLINUX_PYPY_X86_64_IMAGE: ${{ matrix.manylinux }}
|
||||
CIBW_MANYLINUX_X86_64_IMAGE: ${{ matrix.manylinux }}
|
||||
CIBW_SKIP: pp38-*
|
||||
|
@ -75,6 +80,102 @@ jobs:
|
|||
name: dist
|
||||
path: ./wheelhouse/*.whl
|
||||
|
||||
windows:
|
||||
name: Windows ${{ matrix.arch }}
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- arch: x86
|
||||
cibw_arch: x86
|
||||
- arch: x64
|
||||
cibw_arch: AMD64
|
||||
- arch: ARM64
|
||||
cibw_arch: ARM64
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Checkout extra test images
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: python-pillow/test-images
|
||||
path: Tests\test-images
|
||||
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.x"
|
||||
|
||||
- name: Prepare for build
|
||||
run: |
|
||||
choco install nasm --no-progress
|
||||
echo "C:\Program Files\NASM" >> $env:GITHUB_PATH
|
||||
|
||||
# Install extra test images
|
||||
xcopy /S /Y Tests\test-images\* Tests\images
|
||||
|
||||
& python.exe -m pip install -r .ci/requirements-cibw.txt
|
||||
|
||||
# Cannot cross-compile FriBiDi (only used for tests)
|
||||
$FLAGS = ("--no-imagequant", "--architecture=${{ matrix.arch }}")
|
||||
if ('${{ matrix.arch }}' -eq 'ARM64') { $FLAGS += "--no-fribidi" }
|
||||
& python.exe winbuild\build_prepare.py -v @FLAGS
|
||||
shell: pwsh
|
||||
|
||||
- name: Build wheels
|
||||
run: |
|
||||
setlocal EnableDelayedExpansion
|
||||
for %%f in (winbuild\build\license\*) do (
|
||||
set x=%%~nf
|
||||
rem Skip FriBiDi license, it is not included in the wheel.
|
||||
set fribidi=!x:~0,7!
|
||||
if NOT !fribidi!==fribidi (
|
||||
rem Skip imagequant license, it is not included in the wheel.
|
||||
set libimagequant=!x:~0,13!
|
||||
if NOT !libimagequant!==libimagequant (
|
||||
echo. >> LICENSE
|
||||
echo ===== %%~nf ===== >> LICENSE
|
||||
echo. >> LICENSE
|
||||
type %%f >> LICENSE
|
||||
)
|
||||
)
|
||||
)
|
||||
call winbuild\\build\\build_env.cmd
|
||||
%pythonLocation%\python.exe -m cibuildwheel . --output-dir wheelhouse
|
||||
env:
|
||||
CIBW_ARCHS: ${{ matrix.cibw_arch }}
|
||||
CIBW_BEFORE_ALL: "{package}\\winbuild\\build\\build_dep_all.cmd"
|
||||
CIBW_CACHE_PATH: "C:\\cibw"
|
||||
CIBW_TEST_SKIP: "*-win_arm64"
|
||||
CIBW_TEST_COMMAND: 'docker run --rm
|
||||
-v {project}:C:\pillow
|
||||
-v C:\cibw:C:\cibw
|
||||
-v %CD%\..\venv-test:%CD%\..\venv-test
|
||||
-e CI -e GITHUB_ACTIONS
|
||||
mcr.microsoft.com/windows/servercore:ltsc2022
|
||||
powershell C:\pillow\.github\workflows\wheels-test.ps1 %CD%\..\venv-test'
|
||||
shell: cmd
|
||||
|
||||
- name: Upload wheels
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: dist
|
||||
path: ./wheelhouse/*.whl
|
||||
|
||||
- name: Prepare to upload FriBiDi
|
||||
if: "matrix.arch != 'ARM64'"
|
||||
run: |
|
||||
mkdir fribidi\${{ matrix.arch }}
|
||||
copy winbuild\build\bin\fribidi* fribidi\${{ matrix.arch }}
|
||||
shell: cmd
|
||||
|
||||
- name: Upload fribidi.dll
|
||||
if: "matrix.arch != 'ARM64'"
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: fribidi
|
||||
path: fribidi\*
|
||||
|
||||
sdist:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
@ -97,7 +198,7 @@ jobs:
|
|||
success:
|
||||
permissions:
|
||||
contents: none
|
||||
needs: [build, sdist]
|
||||
needs: [build, windows, sdist]
|
||||
runs-on: ubuntu-latest
|
||||
name: Wheels Successful
|
||||
steps:
|
||||
|
|
|
@ -3,7 +3,6 @@ if: tag IS present OR type = api
|
|||
env:
|
||||
global:
|
||||
- CIBW_ARCHS=aarch64
|
||||
- CIBW_CONFIG_SETTINGS="raqm=enable raqm=vendor fribidi=vendor"
|
||||
- CIBW_SKIP=pp38-*
|
||||
|
||||
language: python
|
||||
|
|
41
Tests/check_wheel.py
Normal file
41
Tests/check_wheel.py
Normal file
|
@ -0,0 +1,41 @@
|
|||
import sys
|
||||
|
||||
from PIL import features
|
||||
|
||||
|
||||
def test_wheel_modules():
|
||||
expected_modules = {"pil", "tkinter", "freetype2", "littlecms2", "webp"}
|
||||
|
||||
# tkinter is not available in cibuildwheel installed CPython on Windows
|
||||
try:
|
||||
import tkinter
|
||||
|
||||
assert tkinter
|
||||
except ImportError:
|
||||
expected_modules.remove("tkinter")
|
||||
|
||||
assert set(features.get_supported_modules()) == expected_modules
|
||||
|
||||
|
||||
def test_wheel_codecs():
|
||||
expected_codecs = {"jpg", "jpg_2000", "zlib", "libtiff"}
|
||||
|
||||
assert set(features.get_supported_codecs()) == expected_codecs
|
||||
|
||||
|
||||
def test_wheel_features():
|
||||
expected_features = {
|
||||
"webp_anim",
|
||||
"webp_mux",
|
||||
"transp_webp",
|
||||
"raqm",
|
||||
"fribidi",
|
||||
"harfbuzz",
|
||||
"libjpeg_turbo",
|
||||
"xcb",
|
||||
}
|
||||
|
||||
if sys.platform == "win32":
|
||||
expected_features.remove("xcb")
|
||||
|
||||
assert set(features.get_supported_features()) == expected_features
|
|
@ -5,6 +5,7 @@ Helper functions.
|
|||
import logging
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import sysconfig
|
||||
import tempfile
|
||||
|
@ -258,11 +259,21 @@ def hopper(mode=None, cache={}):
|
|||
|
||||
|
||||
def djpeg_available():
|
||||
return bool(shutil.which("djpeg"))
|
||||
if shutil.which("djpeg"):
|
||||
try:
|
||||
subprocess.check_call(["djpeg", "-version"])
|
||||
return True
|
||||
except subprocess.CalledProcessError: # pragma: no cover
|
||||
return False
|
||||
|
||||
|
||||
def cjpeg_available():
|
||||
return bool(shutil.which("cjpeg"))
|
||||
if shutil.which("cjpeg"):
|
||||
try:
|
||||
subprocess.check_call(["cjpeg", "-version"])
|
||||
return True
|
||||
except subprocess.CalledProcessError: # pragma: no cover
|
||||
return False
|
||||
|
||||
|
||||
def netpbm_available():
|
||||
|
|
|
@ -11,6 +11,10 @@ from .helper import assert_image_equal_tofile, skip_unless_feature
|
|||
|
||||
|
||||
class TestImageGrab:
|
||||
@pytest.mark.skipif(
|
||||
os.environ.get("USERNAME") == "ContainerAdministrator",
|
||||
reason="can't grab screen when running in Docker",
|
||||
)
|
||||
@pytest.mark.skipif(
|
||||
sys.platform not in ("win32", "darwin"), reason="requires Windows or macOS"
|
||||
)
|
||||
|
|
|
@ -88,6 +88,8 @@ version = {attr = "PIL.__version__"}
|
|||
|
||||
[tool.cibuildwheel]
|
||||
before-all = ".github/workflows/wheels-dependencies.sh"
|
||||
build-verbosity = 1
|
||||
config-settings = "raqm=enable raqm=vendor fribidi=vendor imagequant=disable"
|
||||
test-command = "cd {project} && .github/workflows/wheels-test.sh"
|
||||
test-extras = "tests"
|
||||
|
||||
|
|
|
@ -586,14 +586,19 @@ def build_dep(name: str) -> str:
|
|||
|
||||
def build_dep_all() -> None:
|
||||
lines = [r'call "{build_dir}\build_env.cmd"']
|
||||
gha_groups = "GITHUB_ACTIONS" in os.environ
|
||||
for dep_name in DEPS:
|
||||
print()
|
||||
if dep_name in disabled:
|
||||
print(f"Skipping disabled dependency {dep_name}")
|
||||
continue
|
||||
script = build_dep(dep_name)
|
||||
if gha_groups:
|
||||
lines.append(f"@echo ::group::Running {script}")
|
||||
lines.append(rf'cmd.exe /c "{{build_dir}}\{script}"')
|
||||
lines.append("if errorlevel 1 echo Build failed! && exit /B 1")
|
||||
if gha_groups:
|
||||
lines.append("@echo ::endgroup::")
|
||||
print()
|
||||
lines.append("@echo All Pillow dependencies built successfully!")
|
||||
write_script("build_dep_all.cmd", lines)
|
||||
|
|
Loading…
Reference in New Issue
Block a user