Test on Windows

This commit is contained in:
Andrew Murray 2025-12-27 18:26:36 +11:00
parent 7906f57589
commit 193ca321f4
4 changed files with 69 additions and 8 deletions

View File

@ -175,6 +175,14 @@ jobs:
if: steps.build-cache.outputs.cache-hit != 'true'
run: "& winbuild\\build\\build_dep_libimagequant.cmd"
- name: Build dependencies / highway
if: steps.build-cache.outputs.cache-hit != 'true'
run: "& winbuild\\build\\build_dep_highway.cmd"
- name: Build dependencies / libjxl
if: steps.build-cache.outputs.cache-hit != 'true'
run: "& winbuild\\build\\build_dep_libjxl.cmd"
# Raqm dependencies
- name: Build dependencies / HarfBuzz
if: steps.build-cache.outputs.cache-hit != 'true'

View File

@ -8,7 +8,15 @@ from PIL import features
def test_wheel_modules() -> None:
expected_modules = {"pil", "tkinter", "freetype2", "littlecms2", "webp", "avif"}
expected_modules = {
"pil",
"tkinter",
"freetype2",
"littlecms2",
"webp",
"avif",
"jpegxl",
}
if sys.platform == "win32":
# tkinter is not available in cibuildwheel installed CPython on Windows
@ -19,15 +27,17 @@ def test_wheel_modules() -> None:
except ImportError:
expected_modules.remove("tkinter")
expected_modules.remove("jpegxl")
# libavif is not available on Windows for ARM64 architectures
if platform.machine() == "ARM64":
expected_modules.remove("avif")
elif sys.platform == "ios":
# tkinter is not available on iOS
expected_modules.remove("tkinter")
elif os.environ.get("AUDITWHEEL_POLICY") != "manylinux2014":
expected_modules.add("jpegxl")
expected_modules -= {"tkinter", "jpegxl"}
elif os.environ.get("AUDITWHEEL_POLICY") == "manylinux2014":
expected_modules.remove("jpegxl")
assert set(features.get_supported_modules()) == expected_modules

View File

@ -445,6 +445,7 @@ class pil_build_ext(build_ext):
libraries: list[str] | list[str | bool | None],
define_macros: list[tuple[str, str | None]] | None = None,
sources: list[str] | None = None,
args: list[str] | None = None,
) -> None:
for extension in self.extensions:
if extension.name == name:
@ -453,6 +454,8 @@ class pil_build_ext(build_ext):
extension.define_macros += define_macros
if sources is not None:
extension.sources += sources
if args is not None:
extension.extra_compile_args += args
if FUZZING_BUILD:
extension.language = "c++"
extension.extra_link_args = ["--stdlib=libc++"]
@ -782,8 +785,8 @@ class pil_build_ext(build_ext):
if feature.want("jpegxl"):
_dbg("Looking for jpegxl")
if _find_include_file(self, "jxl/encode.h") and _find_include_file(
self, "jxl/decode.h"
if _find_include_file(self, "jxl/decode.h") and _find_include_file(
self, "jxl/thread_parallel_runner.h"
):
if _find_library_file(self, "jxl") and _find_library_file(
self, "jxl_threads"
@ -1017,7 +1020,11 @@ class pil_build_ext(build_ext):
jpegxl = feature.get("jpegxl")
if isinstance(jpegxl, str):
libs = [jpegxl, jpegxl + "_threads"]
self._update_extension("PIL._jpegxl", libs)
args: list[str] | None = None
if sys.platform == "win32":
libs.extend(["brotlicommon", "brotlidec", "brotlienc", "hwy"])
args = ["-DJXL_STATIC_DEFINE"]
self._update_extension("PIL._jpegxl", libs, args=args)
else:
self._remove_extension("PIL._jpegxl")

View File

@ -117,7 +117,9 @@ V = {
"FREETYPE": "2.14.1",
"FRIBIDI": "1.0.16",
"HARFBUZZ": "12.2.0",
"HIGHWAY": "1.3.0",
"JPEGTURBO": "3.1.3",
"JPEGXL": "0.11.1",
"LCMS2": "2.17",
"LIBAVIF": "1.3.0",
"LIBIMAGEQUANT": "4.4.1",
@ -255,7 +257,10 @@ DEPS: dict[str, dict[str, Any]] = {
"filename": f"brotli-{V['BROTLI']}.tar.gz",
"license": "LICENSE",
"build": [
*cmds_cmake(("brotlicommon", "brotlidec"), "-DBUILD_SHARED_LIBS:BOOL=OFF"),
*cmds_cmake(
("brotlicommon", "brotlidec", "brotlienc"),
"-DBUILD_SHARED_LIBS:BOOL=OFF",
),
cmd_xcopy(r"c\include", "{inc_dir}"),
],
"libs": ["*.lib"],
@ -332,6 +337,35 @@ DEPS: dict[str, dict[str, Any]] = {
],
"libs": [r"bin\*.lib"],
},
"highway": {
"url": f"https://github.com/google/highway/archive/{V['HIGHWAY']}.tar.gz",
"filename": f"highway-{V['HIGHWAY']}.tar.gz",
"license": "LICENSE",
"build": [*cmds_cmake("hwy")],
"libs": ["hwy.lib"],
},
"libjxl": {
"url": f"https://github.com/libjxl/libjxl/archive/v{V['JPEGXL']}.tar.gz",
"filename": f"libjxl-{V['JPEGXL']}.tar.gz",
"license": "LICENSE",
"build": [
*cmds_cmake(
"jxl",
rf"-DHWY_INCLUDE_DIR=..\highway-{V['HIGHWAY']}",
r"-DLCMS2_LIBRARY=..\..\lib\lcms2_static",
r"-DLCMS2_INCLUDE_DIR=..\..\inc",
"-DJPEGXL_ENABLE_SJPEG:BOOL=OFF",
"-DJPEGXL_ENABLE_SKCMS:BOOL=OFF",
"-DBUILD_TESTING:BOOL=OFF",
"-DBUILD_SHARED_LIBS:BOOL=OFF",
),
cmd_copy(r"lib\jxl.lib", "{lib_dir}"),
*cmds_cmake("jxl_threads"),
cmd_copy(r"lib\jxl_threads.lib", "{lib_dir}"),
cmd_mkdir(r"{inc_dir}\jxl"),
cmd_copy(r"lib\include\jxl\*.h", r"{inc_dir}\jxl"),
],
},
"libimagequant": {
"url": "https://github.com/ImageOptim/libimagequant/archive/{V['LIBIMAGEQUANT']}.tar.gz",
"filename": f"libimagequant-{V['LIBIMAGEQUANT']}.tar.gz",
@ -630,6 +664,8 @@ def build_dep_all(disabled: list[str], prefs: dict[str, str], verbose: bool) ->
print(f"Skipping disabled dependency {dep_name}")
continue
script = build_dep(dep_name, prefs, verbose)
if dep_name in ("highway", "libjxl"):
continue
if gha_groups:
lines.append(f"@echo ::group::Running {script}")
lines.append(rf'cmd.exe /c "{{build_dir}}\{script}"')