This commit is contained in:
nulano 2020-01-01 01:48:13 +01:00 committed by Andrew Murray
parent aa4592c951
commit ae0c0f3d0a
3 changed files with 131 additions and 136 deletions

View File

@ -77,37 +77,37 @@ jobs:
shell: pwsh shell: pwsh
- name: Build dependencies / libjpeg - name: Build dependencies / libjpeg
run: "& .\\winbuild\\build_dep_libjpeg.cmd" run: "& .\\winbuild\\build\\build_dep_libjpeg.cmd"
- name: Build dependencies / zlib - name: Build dependencies / zlib
run: "& .\\winbuild\\build_dep_zlib.cmd" run: "& .\\winbuild\\build\\build_dep_zlib.cmd"
- name: Build dependencies / LibTiff - name: Build dependencies / LibTiff
run: "& .\\winbuild\\build_dep_libtiff.cmd" run: "& .\\winbuild\\build\\build_dep_libtiff.cmd"
- name: Build dependencies / WebP - name: Build dependencies / WebP
run: "& .\\winbuild\\build_dep_libwebp.cmd" run: "& .\\winbuild\\build\\build_dep_libwebp.cmd"
- name: Build dependencies / FreeType - name: Build dependencies / FreeType
run: "& .\\winbuild\\build_dep_freetype.cmd" run: "& .\\winbuild\\build\\build_dep_freetype.cmd"
- name: Build dependencies / LCMS2 - name: Build dependencies / LCMS2
run: "& .\\winbuild\\build_dep_lcms2.cmd" run: "& .\\winbuild\\build\\build_dep_lcms2.cmd"
- name: Build dependencies / OpenJPEG - name: Build dependencies / OpenJPEG
run: "& .\\winbuild\\build_dep_openjpeg.cmd" run: "& .\\winbuild\\build\\build_dep_openjpeg.cmd"
# GPL licensed; skip if building wheels # GPL licensed; skip if building wheels
- name: Build dependencies / libimagequant - name: Build dependencies / libimagequant
if: "github.event_name != 'push' || contains(matrix.python-version, 'pypy')" if: "github.event_name != 'push' || contains(matrix.python-version, 'pypy')"
run: "& .\\winbuild\\build_dep_libimagequant.cmd" run: "& .\\winbuild\\build\\build_dep_libimagequant.cmd"
# Raqm dependencies # Raqm dependencies
- name: Build dependencies / HarfBuzz - name: Build dependencies / HarfBuzz
run: "& .\\winbuild\\build_dep_harfbuzz.cmd" run: "& .\\winbuild\\build\\build_dep_harfbuzz.cmd"
- name: Build dependencies / FriBidi - name: Build dependencies / FriBidi
run: "& .\\winbuild\\build_dep_fribidi.cmd" run: "& .\\winbuild\\build\\build_dep_fribidi.cmd"
- name: Build dependencies / Raqm - name: Build dependencies / Raqm
run: "& .\\winbuild\\build_dep_libraqm.cmd" run: "& .\\winbuild\\build\\build_dep_libraqm.cmd"
- name: Build Pillow - name: Build Pillow
run: | run: |
cd $env:GITHUB_WORKSPACE cd $env:GITHUB_WORKSPACE
& winbuild\build_pillow.cmd install & winbuild\build\build_pillow.cmd install
& $env:pythonLocation\python.exe selftest.py --installed & $env:pythonLocation\python.exe selftest.py --installed
shell: pwsh shell: pwsh
@ -145,14 +145,14 @@ jobs:
with: with:
file: ./coverage.xml file: ./coverage.xml
flags: GHA_Windows flags: GHA_Windows
name: ${{ runner.os }} Python ${{ matrix.python-version }} name: ${{ runner.os }} Python ${{ matrix.python-version }} ${{ matrix.architecture }}
- name: Build wheel - name: Build wheel
id: wheel id: wheel
if: "github.event_name == 'push' && !contains(matrix.python-version, 'pypy')" if: "github.event_name == 'push' && !contains(matrix.python-version, 'pypy')"
run: | run: |
for /f "tokens=3 delims=/" %%a in ("${{ github.ref }}") do echo ::set-output name=dist::dist-%%a for /f "tokens=3 delims=/" %%a in ("${{ github.ref }}") do echo ::set-output name=dist::dist-%%a
%GITHUB_WORKSPACE%\\winbuild\\build_pillow.cmd bdist_wheel" %GITHUB_WORKSPACE%\\winbuild\\build\\build_pillow.cmd bdist_wheel"
shell: cmd shell: cmd
- uses: actions/upload-artifact@v1 - uses: actions/upload-artifact@v1
@ -160,9 +160,3 @@ jobs:
with: with:
name: ${{ steps.wheel.outputs.dist }} name: ${{ steps.wheel.outputs.dist }}
path: dist path: dist
# - uses: actions/upload-artifact@v1
# if: matrix.architecture == 'x86'
# with:
# name: lib
# path: "winbuild\\build\\3.x\\x86\\lib"

View File

@ -2,10 +2,90 @@ import os
import shutil import shutil
import subprocess import subprocess
import sys import sys
import winreg
from itertools import count
from commands import *
def cmd_cd(path):
return "cd /D {path}".format(**locals())
def cmd_set(name, value):
return "set {name}={value}".format(**locals())
def cmd_append(name, value):
op = "path " if name == "PATH" else "set {name}="
return (op + "%{name}%;{value}").format(**locals())
def cmd_copy(src, tgt):
return 'copy /Y /B "{src}" "{tgt}"'.format(**locals())
def cmd_xcopy(src, tgt):
return 'xcopy /Y /E "{src}" "{tgt}"'.format(**locals())
def cmd_mkdir(path):
return 'mkdir "{path}"'.format(**locals())
def cmd_rmdir(path):
return 'rmdir /S /Q "{path}"'.format(**locals())
def cmd_nmake(makefile=None, target="", params=None):
if params is None:
params = ""
elif isinstance(params, list) or isinstance(params, tuple):
params = " ".join(params)
else:
params = str(params)
return " ".join(
[
"{{nmake}}",
"-nologo",
'-f "{makefile}"' if makefile is not None else "",
"{params}",
'"{target}"',
]
).format(**locals())
def cmd_cmake(params=None, file="."):
if params is None:
params = ""
elif isinstance(params, list) or isinstance(params, tuple):
params = " ".join(params)
else:
params = str(params)
return " ".join(
[
"{{cmake}}",
"-DCMAKE_VERBOSE_MAKEFILE=ON",
"-DCMAKE_RULE_MESSAGES:BOOL=OFF",
"-DCMAKE_BUILD_TYPE=Release",
"{params}",
'-G "NMake Makefiles"',
'"{file}"',
]
).format(**locals())
def cmd_msbuild(
file, configuration="Release", target="Build", platform="{msbuild_arch}"
):
return " ".join(
[
"{{msbuild}}",
"{file}",
'/t:"{target}"',
'/p:Configuration="{configuration}"',
"/p:Platform={platform}",
"/m",
]
).format(**locals())
SF_MIRROR = "http://iweb.dl.sourceforge.net" SF_MIRROR = "http://iweb.dl.sourceforge.net"
@ -61,8 +141,7 @@ deps = {
"libs": [r"*.lib"], "libs": [r"*.lib"],
}, },
"libtiff": { "libtiff": {
# FIXME FTP timeout "url": "https://download.osgeo.org/libtiff/tiff-4.1.0.tar.gz",
"url": "ftp://download.osgeo.org/libtiff/tiff-4.1.0.tar.gz",
"filename": "tiff-4.1.0.tar.gz", "filename": "tiff-4.1.0.tar.gz",
"dir": "tiff-4.1.0", "dir": "tiff-4.1.0",
"build": [ "build": [
@ -147,7 +226,7 @@ deps = {
"build": [ "build": [
cmd_cmake(("-DBUILD_THIRDPARTY:BOOL=OFF", "-DBUILD_SHARED_LIBS:BOOL=OFF")), cmd_cmake(("-DBUILD_THIRDPARTY:BOOL=OFF", "-DBUILD_SHARED_LIBS:BOOL=OFF")),
cmd_nmake(target="clean"), cmd_nmake(target="clean"),
cmd_nmake(), cmd_nmake(target="openjp2"),
cmd_mkdir(r"{inc_dir}\openjpeg-2.3.1"), cmd_mkdir(r"{inc_dir}\openjpeg-2.3.1"),
cmd_copy(r"src\lib\openjp2\*.h", r"{inc_dir}\openjpeg-2.3.1"), cmd_copy(r"src\lib\openjp2\*.h", r"{inc_dir}\openjpeg-2.3.1"),
], ],
@ -303,6 +382,8 @@ def extract_dep(url, filename):
ex = e ex = e
else: else:
raise RuntimeError(ex) raise RuntimeError(ex)
print("Extracting " + filename)
if filename.endswith(".zip"): if filename.endswith(".zip"):
with zipfile.ZipFile(file) as zf: with zipfile.ZipFile(file) as zf:
zf.extractall(build_dir) zf.extractall(build_dir)
@ -314,7 +395,7 @@ def extract_dep(url, filename):
def write_script(name, lines): def write_script(name, lines):
name = os.path.join(script_dir, name) name = os.path.join(build_dir, name)
lines = [line.format(**prefs) for line in lines] lines = [line.format(**prefs) for line in lines]
print("Writing " + name) print("Writing " + name)
with open(name, "w") as f: with open(name, "w") as f:
@ -350,8 +431,11 @@ def build_dep(name):
with open(patch_file, "w") as f: with open(patch_file, "w") as f:
f.write(text) f.write(text)
banner = "Building {name} ({dir})".format(**locals())
lines = [ lines = [
"@echo ---- Building {name} ({dir}) ----".format(**locals()), "@echo " + ("=" * 70),
"@echo ==== {:<60} ====".format(banner),
"@echo " + ("=" * 70),
"cd /D %s" % os.path.join(build_dir, dir), "cd /D %s" % os.path.join(build_dir, dir),
*prefs["header"], *prefs["header"],
*dep.get("build", []), *dep.get("build", []),
@ -363,13 +447,12 @@ def build_dep(name):
def build_dep_all(): def build_dep_all():
lines = [ lines = ["@echo on"]
"$ErrorActionPreference = 'stop'",
"cd {script_dir}",
]
for dep_name in deps: for dep_name in deps:
lines.append('cmd.exe /c "%s"' % build_dep(dep_name)) lines.append(r'cmd.exe /c "{{build_dir}}\{}"'.format(build_dep(dep_name)))
write_script("build_dep_all.ps1", lines) lines.append("if errorlevel 1 echo Build failed! && exit /B 1")
lines.append("@echo All Pillow dependencies built successfully!")
write_script("build_dep_all.cmd", lines)
def build_pillow(wheel=False): def build_pillow(wheel=False):
@ -379,7 +462,7 @@ def build_pillow(wheel=False):
lines.extend(prefs["header"]) lines.extend(prefs["header"])
lines.extend( lines.extend(
[ [
"@echo ---- Building Pillow (%s) ----", "@echo ---- Building Pillow (build_ext %*) ----",
cmd_cd("{pillow_dir}"), cmd_cd("{pillow_dir}"),
cmd_append("LIB", r"{python_dir}\tcl"), cmd_append("LIB", r"{python_dir}\tcl"),
cmd_set("MSSdk", "1"), cmd_set("MSSdk", "1"),
@ -393,39 +476,50 @@ def build_pillow(wheel=False):
if __name__ == "__main__": if __name__ == "__main__":
# winbuild directory
script_dir = os.path.dirname(os.path.realpath(__file__)) script_dir = os.path.dirname(os.path.realpath(__file__))
# dependency cache directory
depends_dir = os.path.join(script_dir, "depends") depends_dir = os.path.join(script_dir, "depends")
print("Caching dependencies in:", depends_dir)
# python bin directory
python_dir = os.environ.get( python_dir = os.environ.get(
"PYTHON", os.path.dirname(os.path.realpath(sys.executable)) "PYTHON", os.path.dirname(os.path.realpath(sys.executable))
) )
print("Target Python:", python_dir)
print("Target Python: {}".format(python_dir))
# copy binaries to this directory # copy binaries to this directory
path_dir = os.environ.get("PILLOW_BIN") path_dir = os.environ.get("PILLOW_BIN")
print("Copying binary files to:", path_dir)
# use PYTHON to select architecture # use PYTHON to select architecture
arch_prefs = match(architectures, python_dir) arch_prefs = match(architectures, python_dir)
if arch_prefs is None: if arch_prefs is None:
architecture = "x86" architecture = "x86"
print("WARN: Could not determine architecture, guessing " + architecture)
arch_prefs = architectures[architecture] arch_prefs = architectures[architecture]
else: else:
architecture = arch_prefs["name"] architecture = arch_prefs["name"]
print("Target Architecture:", architecture)
print("Target Architecture: {}".format(architecture))
msvs = find_msvs() msvs = find_msvs()
if msvs is None: if msvs is None:
raise RuntimeError( raise RuntimeError(
"Visual Studio not found. Please install Visual Studio 2017 or newer." "Visual Studio not found. Please install Visual Studio 2017 or newer."
) )
print("Found Visual Studio at:", msvs["vs_dir"])
print("Found Visual Studio at: {}".format(msvs["vs_dir"])) # build root directory
build_dir = os.environ.get("PILLOW_BUILD", os.path.join(script_dir, "build"))
print("Using output directory:", build_dir)
build_dir = os.path.join(script_dir, "build", architecture) # build directory for *.h files
lib_dir = os.path.join(build_dir, "lib")
inc_dir = os.path.join(build_dir, "inc") inc_dir = os.path.join(build_dir, "inc")
# build directory for *.lib files
lib_dir = os.path.join(build_dir, "lib")
# build directory for *.bin files
bin_dir = os.path.join(build_dir, "bin") bin_dir = os.path.join(build_dir, "bin")
shutil.rmtree(build_dir, ignore_errors=True) shutil.rmtree(build_dir, ignore_errors=True)

View File

@ -1,96 +1,3 @@
# builtins # builtins
def cmd_cd(path):
return "cd /D {path}".format(**locals())
def cmd_set(name, value):
return "set {name}={value}".format(**locals())
def cmd_prepend(name, value):
op = "path " if name == "PATH" else "set {name}="
return (op + "{value};%{name}%").format(**locals())
def cmd_append(name, value):
op = "path " if name == "PATH" else "set {name}="
return (op + "%{name}%;{value}").format(**locals())
def cmd_copy(src, tgt):
return 'copy /Y /B "{src}" "{tgt}"'.format(**locals())
def cmd_xcopy(src, tgt):
return 'xcopy /Y /E "{src}" "{tgt}"'.format(**locals())
def cmd_mkdir(path):
return 'mkdir "{path}"'.format(**locals())
def cmd_rmdir(path):
return 'rmdir /S /Q "{path}"'.format(**locals())
def cmd_if_eq(a, b, cmd):
return 'if "{a}"=="{b}" {cmd}'.format(**locals())
# tools
def cmd_nmake(makefile=None, target="", params=None):
if params is None:
params = ""
elif isinstance(params, list) or isinstance(params, tuple):
params = " ".join(params)
else:
params = str(params)
return " ".join(
[
"{{nmake}}",
"-nologo",
'-f "{makefile}"' if makefile is not None else "",
"{params}",
'"{target}"',
]
).format(**locals())
def cmd_cmake(params=None, file="."):
if params is None:
params = ""
elif isinstance(params, list) or isinstance(params, tuple):
params = " ".join(params)
else:
params = str(params)
return " ".join(
[
"{{cmake}}",
"-DCMAKE_VERBOSE_MAKEFILE=ON",
"-DCMAKE_RULE_MESSAGES:BOOL=OFF",
"-DCMAKE_BUILD_TYPE=Release",
"{params}",
'-G "NMake Makefiles"',
'"{file}"',
]
).format(**locals())
def cmd_msbuild(
file, configuration="Release", target="Build", platform="{msbuild_arch}"
):
return " ".join(
[
"{{msbuild}}",
"{file}",
'/t:"{target}"',
'/p:Configuration="{configuration}"',
"/p:Platform={platform}",
"/m",
]
).format(**locals())