diff --git a/.appveyor.yml b/.appveyor.yml
index 645c2256f..4d2cb81d2 100644
--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -7,10 +7,8 @@ init:
# Uncomment previous line to get RDP access during the build.
environment:
- X64_EXT: -x64
EXECUTABLE: python.exe
PIP_DIR: Scripts
- VENV: NO
TEST_OPTIONS:
DEPLOY: YES
matrix:
@@ -32,12 +30,11 @@ install:
- curl -fsSL -o pillow-depends.zip https://github.com/python-pillow/pillow-depends/archive/master.zip
- 7z x pillow-depends.zip -oc:\
- mv c:\pillow-depends-master c:\pillow-depends
-- mkdir c:\pillow\winbuild\depends
-- xcopy c:\pillow-depends\*.zip c:\pillow\winbuild\depends\
-- xcopy c:\pillow-depends\*.tar.gz c:\pillow\winbuild\depends\
- xcopy /s c:\pillow-depends\test_images\* c:\pillow\tests\images
- 7z x ..\pillow-depends\nasm-2.14.02-win64.zip -oc:\
-- path c:\nasm-2.14.02;%PATH%
+- curl -fsSL -o gs952.exe https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/download/gs952/gs952w32.exe
+- gs952.exe /S
+- path c:\nasm-2.14.02;C:\Program Files (x86)\gs\gs9.52\bin;%PATH%
- cd c:\pillow\winbuild\
- ps: |
if ($env:PYTHON -eq "c:/vp/pypy3")
@@ -51,14 +48,12 @@ install:
}
else
{
- $env:PILLOW_BIN = "c:\pillow\"
+ $env:PILLOW_DEPS = "C:\pillow-depends\"
c:\python37\python.exe c:\pillow\winbuild\build_prepare.py
c:\pillow\winbuild\build\build_dep_all.cmd
$host.SetShouldExit(0)
}
-- curl -fsSL -o gs952.exe https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/download/gs952/gs952w32.exe
-- gs952.exe /S
-- path %path%;C:\Program Files (x86)\gs\gs9.52\bin
+- path C:\pillow\winbuild\build\bin;%PATH%
build_script:
- ps: |
diff --git a/.github/workflows/test-windows.yml b/.github/workflows/test-windows.yml
index 7c1887745..fe958ad5a 100644
--- a/.github/workflows/test-windows.yml
+++ b/.github/workflows/test-windows.yml
@@ -66,9 +66,7 @@ jobs:
..\pillow-depends\gs950w32.exe /S
Write-Host "::add-path::C:\Program Files (x86)\gs\gs9.50\bin"
- mkdir $env:GITHUB_WORKSPACE\winbuild\depends\
- xcopy ..\pillow-depends\*.zip $env:GITHUB_WORKSPACE\winbuild\depends\
- xcopy ..\pillow-depends\*.tar.gz $env:GITHUB_WORKSPACE\winbuild\depends\
+ $env:PILLOW_DEPS = "$env:RUNNER_WORKSPACE\pillow-depends\"
xcopy /s ..\pillow-depends\test_images\* $env:GITHUB_WORKSPACE\tests\images\
$env:PYTHON=$env:pythonLocation
diff --git a/Tests/test_imageshow.py b/Tests/test_imageshow.py
index c8c247dc2..a9332bef4 100644
--- a/Tests/test_imageshow.py
+++ b/Tests/test_imageshow.py
@@ -1,7 +1,7 @@
import pytest
from PIL import Image, ImageShow
-from .helper import hopper, is_win32, on_ci, on_github_actions
+from .helper import hopper, is_win32, on_ci
def test_sanity():
diff --git a/winbuild/README.md b/winbuild/README.md
index 471b61a57..dabbc359a 100644
--- a/winbuild/README.md
+++ b/winbuild/README.md
@@ -1,18 +1,30 @@
-Quick README
-------------
-
-For more extensive info, see the [Windows build instructions](build.rst).
-
-* See https://github.com/python-pillow/Pillow/issues/553#issuecomment-37877416 and https://github.com/matplotlib/matplotlib/issues/1717#issuecomment-13343859
-
-* Works best with Python 3.4, due to virtualenv and pip batteries included. Python3+ required for fetch command.
-* Check config.py for virtual env paths, suffix for 64-bit releases. Defaults to `x64`, set `X64_EXT` to change.
-* When running in CI with one Python per invocation, set the `PYTHON` env variable to the Python folder. (e.g. `PYTHON`=`c:\Python27\`) This overrides the matrix in config.py and will just build and test for the specific Python.
-* `python get_pythons.py` downloads all the Python releases, and their signatures. (Manually) Install in `c:\PythonXX[x64]\`.
-* `python build_dep.py` downloads and creates a build script for all the dependencies, in 32 and 64-bit versions, and with both compiler versions.
-* (in powershell) `build_deps.cmd` invokes the dependency build.
-* `python build.py --clean` makes Pillow for the matrix of Pythons.
-* `python test.py` runs the tests on Pillow in all the virtual envs.
-* Currently working with zlib, libjpeg, freetype, and libtiff on Python 2.7, and 3.4, both 32 and 64-bit, on a local win7 pro machine and appveyor.com
-* WebP is built, not detected.
-* LCMS, OpenJPEG and libimagequant are not building.
+Quick README
+------------
+
+For more extensive info, see the [Windows build instructions](build.rst).
+
+* See [Current Windows Build/Testing process (Pillow#553)](https://github.com/python-pillow/Pillow/issues/553#issuecomment-37877416),
+ [Definitive docs for how to compile on Windows (matplotlib#1717)](https://github.com/matplotlib/matplotlib/issues/1717#issuecomment-13343859),
+ [Test Windows with GitHub Actions (Pillow#4084)](https://github.com/python-pillow/Pillow/pull/4084).
+
+
+* Requires Microsoft Visual Studio 2017 or newer with C++ component.
+* Requires NASM for libjpeg-turbo, a required dependency when using this script.
+* Requires CMake 3.13 or newer.
+* Python 3.6+ is required to generate valid scripts, but builds targeting Python 3.5+ are supported.
+* Tested on Windows Server 2016 with Visual Studio 2017 Community (AppVeyor).
+* Tested on Windows Server 2019 with Visual Studio 2019 Enterprise (GitHub Actions).
+
+The following is a simplified version of the script used on AppVeyor:
+```
+set PYTHON=C:\Python35\bin
+cd /D C:\Pillow\winbuild
+C:\Python37\bin\python.exe build_prepare.py
+build\build_dep_all.cmd
+build\build_pillow.cmd install
+cd ..
+path C:\Pillow\winbuild\build\bin;%PATH%
+%PYTHON%\python.exe selftest.py
+%PYTHON%\python.exe -m pytest -vx --cov PIL --cov Tests --cov-report term --cov-report xml Tests
+build\build_pillow.cmd bdist_wheel
+```
diff --git a/winbuild/build_prepare.py b/winbuild/build_prepare.py
index c772a580f..e56b71eb4 100644
--- a/winbuild/build_prepare.py
+++ b/winbuild/build_prepare.py
@@ -95,7 +95,6 @@ architectures = {
}
header = [
- cmd_set("BUILD", "{build_dir}"),
cmd_set("INCLUDE", "{inc_dir}"),
cmd_set("INCLIB", "{lib_dir}"),
cmd_set("LIB", "{lib_dir}"),
@@ -145,7 +144,7 @@ deps = {
"filename": "tiff-4.1.0.tar.gz",
"dir": "tiff-4.1.0",
"build": [
- cmd_copy(r"{script_dir}\tiff.opt", "nmake.opt"),
+ cmd_copy(r"{winbuild_dir}\tiff.opt", "nmake.opt"),
cmd_nmake("makefile.vc", "clean"),
cmd_nmake("makefile.vc", "lib"),
],
@@ -176,8 +175,7 @@ deps = {
"patch": {
r"builds\windows\vc2010\freetype.vcxproj": {
# freetype setting is /MD for .dll and /MT for .lib, we need /MD
- "MultiThreaded":
- "MultiThreadedDLL",
+ "MultiThreaded": "MultiThreadedDLL", # noqa E501
}
},
"build": [
@@ -200,14 +198,11 @@ deps = {
"patch": {
r"Projects\VC2017\lcms2_static\lcms2_static.vcxproj": {
# default is /MD for x86 and /MT for x64, we need /MD always
- "MultiThreaded":
- "MultiThreadedDLL",
+ "MultiThreaded": "MultiThreadedDLL", # noqa E501
# retarget to default toolset (selected by vcvarsall.bat)
- "v141":
- "$(DefaultPlatformToolset)",
+ "v141": "$(DefaultPlatformToolset)", # noqa E501
# retarget to latest (selected by vcvarsall.bat)
- "8.1":
- "$(WindowsSDKVersion)", # noqa E501
+ "8.1": "$(WindowsSDKVersion)", # noqa E501
}
},
"build": [
@@ -269,7 +264,7 @@ deps = {
"filename": "fribidi-1.0.7.zip",
"dir": "fribidi-1.0.7",
"build": [
- cmd_copy(r"{script_dir}\fribidi.cmake", r"CMakeLists.txt"),
+ cmd_copy(r"{winbuild_dir}\fribidi.cmake", r"CMakeLists.txt"),
cmd_cmake(),
cmd_nmake(target="clean"),
cmd_nmake(target="fribidi"),
@@ -282,7 +277,7 @@ deps = {
"filename": "libraqm-0.7.0.zip",
"dir": "libraqm-0.7.0",
"build": [
- cmd_copy(r"{script_dir}\raqm.cmake", r"CMakeLists.txt"),
+ cmd_copy(r"{winbuild_dir}\raqm.cmake", r"CMakeLists.txt"),
cmd_cmake(),
cmd_nmake(target="clean"),
cmd_nmake(target="libraqm"),
@@ -357,12 +352,6 @@ def find_msvs():
return vs
-def match(values, target):
- for key, value in values.items():
- if key in target:
- return {"name": key, **value}
-
-
def extract_dep(url, filename):
import urllib.request
import tarfile
@@ -455,51 +444,42 @@ def build_dep_all():
write_script("build_dep_all.cmd", lines)
-def build_pillow(wheel=False):
- lines = []
- if path_dir is not None and not wheel:
- lines.append(cmd_xcopy("{bin_dir}", path_dir))
- lines.extend(prefs["header"])
- lines.extend(
- [
- "@echo ---- Building Pillow (build_ext %*) ----",
- cmd_cd("{pillow_dir}"),
- cmd_append("LIB", r"{python_dir}\tcl"),
- cmd_set("MSSdk", "1"),
- cmd_set("DISTUTILS_USE_SDK", "1"),
- cmd_set("py_vcruntime_redist", "true"),
- r'"{python_dir}\python.exe" setup.py build_ext %*',
- ]
- )
+def build_pillow():
+ lines = [
+ "@echo ---- Building Pillow (build_ext %*) ----",
+ cmd_cd("{pillow_dir}"),
+ *prefs["header"],
+ cmd_set("DISTUTILS_USE_SDK", "1"), # use same compiler to build Pillow
+ cmd_set("MSSdk", "1"), # for Python 3.5 and PyPy3.6
+ cmd_set("py_vcruntime_redist", "true"), # use /MD, not /MT
+ r'"{python_dir}\{python_exe}" setup.py build_ext %*',
+ ]
write_script("build_pillow.cmd", lines)
if __name__ == "__main__":
# winbuild directory
- script_dir = os.path.dirname(os.path.realpath(__file__))
+ winbuild_dir = os.path.dirname(os.path.realpath(__file__))
# dependency cache directory
- depends_dir = os.path.join(script_dir, "depends")
+ depends_dir = os.environ.get("PILLOW_DEPS", os.path.join(winbuild_dir, "depends"))
+ os.makedirs(depends_dir, exist_ok=True)
print("Caching dependencies in:", depends_dir)
- # python bin directory
- python_dir = os.environ.get(
- "PYTHON", os.path.dirname(os.path.realpath(sys.executable))
+ # Python bin directory
+ python_dir = os.environ.get("PYTHON")
+ python_exe = os.environ.get("EXECUTABLE", "python.exe")
+ if python_dir is None:
+ python_dir = os.path.dirname(os.path.realpath(sys.executable))
+ python_exe = os.path.basename(sys.executable)
+ print("Target Python:", os.path.join(python_dir, python_exe))
+
+ # use ARCHITECTURE or PYTHON to select architecture
+ architecture = os.environ.get(
+ "ARCHITECTURE", "x64" if "x64" in python_dir else "x86"
)
- print("Target Python:", python_dir)
-
- # copy binaries to this directory
- path_dir = os.environ.get("PILLOW_BIN")
- print("Copying binary files to:", path_dir)
-
- # use PYTHON to select architecture
- arch_prefs = match(architectures, python_dir)
- if arch_prefs is None:
- architecture = "x86"
- arch_prefs = architectures[architecture]
- else:
- architecture = arch_prefs["name"]
+ arch_prefs = architectures[architecture]
print("Target Architecture:", architecture)
msvs = find_msvs()
@@ -510,7 +490,7 @@ if __name__ == "__main__":
print("Found Visual Studio at:", msvs["vs_dir"])
# build root directory
- build_dir = os.environ.get("PILLOW_BUILD", os.path.join(script_dir, "build"))
+ build_dir = os.environ.get("PILLOW_BUILD", os.path.join(winbuild_dir, "build"))
print("Using output directory:", build_dir)
# build directory for *.h files
@@ -523,25 +503,30 @@ if __name__ == "__main__":
bin_dir = os.path.join(build_dir, "bin")
shutil.rmtree(build_dir, ignore_errors=True)
- for path in [depends_dir, build_dir, lib_dir, inc_dir, bin_dir]:
- os.makedirs(path, exist_ok=True)
+ for path in [build_dir, inc_dir, lib_dir, bin_dir]:
+ os.makedirs(path)
prefs = {
- "architecture": architecture,
- "script_dir": script_dir,
- "depends_dir": depends_dir,
+ # Python paths / preferences
"python_dir": python_dir,
+ "python_exe": python_exe,
+ "architecture": architecture,
+ **arch_prefs,
+ # Pillow paths
+ "pillow_dir": os.path.realpath(os.path.join(winbuild_dir, "..")),
+ "winbuild_dir": winbuild_dir,
+ # Build paths
"build_dir": build_dir,
- "lib_dir": lib_dir,
"inc_dir": inc_dir,
+ "lib_dir": lib_dir,
"bin_dir": bin_dir,
- "pillow_dir": os.path.realpath(os.path.join(script_dir, "..")),
- # TODO auto find:
- "cmake": "cmake.exe",
+ # Compilers / Tools
+ **msvs,
+ "cmake": "cmake.exe", # TODO find CMAKE automatically
+ # TODO find NASM automatically
+ # script header
+ "header": sum([header, msvs["header"], ["@echo on"]], []),
}
- prefs.update(msvs)
- prefs.update(arch_prefs)
- prefs["header"] = sum([header, msvs["header"], ["@echo on"]], [])
build_dep_all()
build_pillow()
diff --git a/winbuild/commands.py b/winbuild/commands.py
deleted file mode 100644
index ea6e73b4e..000000000
--- a/winbuild/commands.py
+++ /dev/null
@@ -1,3 +0,0 @@
-# builtins
-
-