mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-13 18:56:17 +03:00
windows: parse build configuration with argparse
This commit is contained in:
parent
57260d4924
commit
eeb7c7c647
2
.github/workflows/test-windows.yml
vendored
2
.github/workflows/test-windows.yml
vendored
|
@ -88,7 +88,7 @@ jobs:
|
||||||
- name: Prepare build
|
- name: Prepare build
|
||||||
if: steps.build-cache.outputs.cache-hit != 'true'
|
if: steps.build-cache.outputs.cache-hit != 'true'
|
||||||
run: |
|
run: |
|
||||||
& python.exe winbuild\build_prepare.py -v --python=$env:pythonLocation --srcdir
|
& python.exe winbuild\build_prepare.py -v --python $env:pythonLocation
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
|
|
||||||
- name: Build dependencies / libjpeg-turbo
|
- name: Build dependencies / libjpeg-turbo
|
||||||
|
|
|
@ -38,42 +38,50 @@ Visual Studio is found automatically with ``vswhere.exe``.
|
||||||
Build configuration
|
Build configuration
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
The following environment variables, if set, will override the default
|
Run ``build_prepare.py`` to configure the build::
|
||||||
behaviour of ``build_prepare.py``:
|
|
||||||
|
|
||||||
* ``PYTHON`` + ``EXECUTABLE`` point to the target version of Python.
|
usage: winbuild\build_prepare.py [-h] [-v] [-d PILLOW_BUILD]
|
||||||
If ``PYTHON`` is unset, the version of Python used to run
|
[--depends PILLOW_DEPS]
|
||||||
``build_prepare.py`` will be used. If only ``PYTHON`` is set,
|
[--architecture {x86,x64,ARM64}]
|
||||||
``EXECUTABLE`` defaults to ``python.exe``.
|
[--python PYTHON] [--executable EXECUTABLE]
|
||||||
* ``ARCHITECTURE`` is used to select a ``x86``, ``x64`` or ``ARM64`` build.
|
[--nmake] [--no-imagequant] [--no-fribidi]
|
||||||
By default, uses same architecture as the version of Python used to run ``build_prepare.py``.
|
|
||||||
* ``PILLOW_BUILD`` can be used to override the ``winbuild\build`` directory
|
|
||||||
path, used to store generated build scripts and compiled libraries.
|
|
||||||
**Warning:** This directory is wiped when ``build_prepare.py`` is run.
|
|
||||||
* ``PILLOW_DEPS`` points to the directory used to store downloaded
|
|
||||||
dependencies. By default ``winbuild\depends`` is used.
|
|
||||||
|
|
||||||
``build_prepare.py`` also supports the following command line parameters:
|
Download dependencies and generate build scripts for Pillow.
|
||||||
|
|
||||||
* ``-v`` will print generated scripts.
|
options:
|
||||||
* ``--nmake`` will use NMake instead of Ninja for CMake dependencies
|
-h, --help show this help message and exit
|
||||||
* ``--no-imagequant`` will skip GPL-licensed ``libimagequant`` optional dependency
|
-v, --verbose print generated scripts
|
||||||
* ``--no-fribidi`` or ``--no-raqm`` will skip optional LGPL-licensed dependency FriBiDi
|
-d PILLOW_BUILD, --dir PILLOW_BUILD, --build-dir PILLOW_BUILD
|
||||||
(required for Raqm text shaping).
|
build directory (default: 'winbuild\build')
|
||||||
* ``--python=<path>`` and ``--executable=<exe>`` override ``PYTHON`` and ``EXECUTABLE``.
|
--depends PILLOW_DEPS
|
||||||
* ``--architecture=<arch>`` overrides ``ARCHITECTURE``.
|
directory used to store cached dependencies (default:
|
||||||
* ``--dir=<path>`` and ``--depends=<path>`` override ``PILLOW_BUILD``
|
'winbuild\depends')
|
||||||
and ``PILLOW_DEPS``.
|
--architecture {x86,x64,ARM64}
|
||||||
|
build architecture (default: same as host python)
|
||||||
|
--python PYTHON Python install directory (default: use host python)
|
||||||
|
--executable EXECUTABLE
|
||||||
|
Python executable (default: use host python)
|
||||||
|
--nmake build dependencies using NMake instead of Ninja
|
||||||
|
--no-imagequant skip GPL-licensed optional dependency libimagequant
|
||||||
|
--no-fribidi, --no-raqm
|
||||||
|
skip LGPL-licensed optional dependency FriBiDi
|
||||||
|
|
||||||
|
Arguments can also be supplied using the environment variables PILLOW_BUILD,
|
||||||
|
PILLOW_DEPS, ARCHITECTURE, PYTHON, EXECUTABLE. See winbuild\build.rst for more
|
||||||
|
information.
|
||||||
|
|
||||||
|
**Warning:** The build directory is wiped when ``build_prepare.py`` is run.
|
||||||
|
|
||||||
Dependencies
|
Dependencies
|
||||||
------------
|
------------
|
||||||
|
|
||||||
Dependencies will be automatically downloaded by ``build_prepare.py``.
|
Dependencies will be automatically downloaded by ``build_prepare.py``.
|
||||||
By default, downloaded dependencies are stored in ``winbuild\depends``;
|
By default, downloaded dependencies are stored in ``winbuild\depends``;
|
||||||
set the ``PILLOW_DEPS`` environment variable to override this location.
|
use the ``--depends`` argument or ``PILLOW_DEPS`` environment variable
|
||||||
|
to override this location.
|
||||||
|
|
||||||
To build all dependencies, run ``winbuild\build\build_dep_all.cmd``,
|
To build all dependencies, run ``winbuild\build\build_dep_all.cmd``,
|
||||||
or run the individual scripts to build each dependency separately.
|
or run the individual scripts in order to build each dependency separately.
|
||||||
|
|
||||||
Building Pillow
|
Building Pillow
|
||||||
---------------
|
---------------
|
||||||
|
@ -106,7 +114,7 @@ The following is a simplified version of the script used on AppVeyor:
|
||||||
|
|
||||||
set PYTHON=C:\Python38\bin
|
set PYTHON=C:\Python38\bin
|
||||||
cd /D C:\Pillow\winbuild
|
cd /D C:\Pillow\winbuild
|
||||||
C:\Python37\bin\python.exe build_prepare.py -v --depends=C:\pillow-depends
|
C:\Python37\bin\python.exe build_prepare.py -v --depends C:\pillow-depends
|
||||||
build\build_dep_all.cmd
|
build\build_dep_all.cmd
|
||||||
build\build_pillow.cmd install
|
build\build_pillow.cmd install
|
||||||
cd ..
|
cd ..
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import argparse
|
||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
import re
|
import re
|
||||||
|
@ -434,7 +435,7 @@ def extract_dep(url, filename):
|
||||||
import urllib.request
|
import urllib.request
|
||||||
import zipfile
|
import zipfile
|
||||||
|
|
||||||
file = os.path.join(depends_dir, filename)
|
file = os.path.join(args.depends_dir, filename)
|
||||||
if not os.path.exists(file):
|
if not os.path.exists(file):
|
||||||
ex = None
|
ex = None
|
||||||
for i in range(3):
|
for i in range(3):
|
||||||
|
@ -475,12 +476,12 @@ def extract_dep(url, filename):
|
||||||
|
|
||||||
|
|
||||||
def write_script(name, lines):
|
def write_script(name, lines):
|
||||||
name = os.path.join(build_dir, name)
|
name = os.path.join(args.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", newline="") as f:
|
with open(name, "w", newline="") as f:
|
||||||
f.write(os.linesep.join(lines))
|
f.write(os.linesep.join(lines))
|
||||||
if verbose:
|
if args.verbose:
|
||||||
for line in lines:
|
for line in lines:
|
||||||
print(" " + line)
|
print(" " + line)
|
||||||
|
|
||||||
|
@ -549,11 +550,14 @@ def build_dep(name):
|
||||||
def build_dep_all():
|
def build_dep_all():
|
||||||
lines = ["@echo on"]
|
lines = ["@echo on"]
|
||||||
for dep_name in deps:
|
for dep_name in deps:
|
||||||
|
print()
|
||||||
if dep_name in disabled:
|
if dep_name in disabled:
|
||||||
|
print(f"Skipping disabled dependency {dep_name}")
|
||||||
continue
|
continue
|
||||||
script = build_dep(dep_name)
|
script = build_dep(dep_name)
|
||||||
lines.append(rf'cmd.exe /c "{{build_dir}}\{script}"')
|
lines.append(rf'cmd.exe /c "{{build_dir}}\{script}"')
|
||||||
lines.append("if errorlevel 1 echo Build failed! && exit /B 1")
|
lines.append("if errorlevel 1 echo Build failed! && exit /B 1")
|
||||||
|
print()
|
||||||
lines.append("@echo All Pillow dependencies built successfully!")
|
lines.append("@echo All Pillow dependencies built successfully!")
|
||||||
write_script("build_dep_all.cmd", lines)
|
write_script("build_dep_all.cmd", lines)
|
||||||
|
|
||||||
|
@ -572,59 +576,90 @@ def build_pillow():
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# winbuild directory
|
|
||||||
winbuild_dir = os.path.dirname(os.path.realpath(__file__))
|
winbuild_dir = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
pillow_dir = os.path.realpath(os.path.join(winbuild_dir, ".."))
|
||||||
|
|
||||||
verbose = False
|
parser = argparse.ArgumentParser(
|
||||||
disabled = []
|
prog="winbuild\\build_prepare.py",
|
||||||
depends_dir = os.environ.get("PILLOW_DEPS", os.path.join(winbuild_dir, "depends"))
|
description="Download dependencies and generate build scripts for Pillow.",
|
||||||
python_dir = os.environ.get("PYTHON")
|
epilog="""Arguments can also be supplied using the environment variables
|
||||||
python_exe = os.environ.get("EXECUTABLE", "python.exe")
|
PILLOW_BUILD, PILLOW_DEPS, ARCHITECTURE, PYTHON, EXECUTABLE.
|
||||||
architecture = os.environ.get(
|
See winbuild\\build.rst for more information.""",
|
||||||
"ARCHITECTURE",
|
|
||||||
"ARM64"
|
|
||||||
if platform.machine() == "ARM64"
|
|
||||||
else ("x86" if struct.calcsize("P") == 4 else "x64"),
|
|
||||||
)
|
)
|
||||||
build_dir = os.environ.get("PILLOW_BUILD", os.path.join(winbuild_dir, "build"))
|
parser.add_argument(
|
||||||
cmake_generator = "Ninja"
|
"-v", "--verbose", action="store_true", help="print generated scripts"
|
||||||
sources_dir = ""
|
)
|
||||||
for arg in sys.argv[1:]:
|
parser.add_argument(
|
||||||
if arg == "-v":
|
"-d",
|
||||||
verbose = True
|
"--dir",
|
||||||
elif arg == "--nmake":
|
"--build-dir",
|
||||||
cmake_generator = "NMake Makefiles"
|
dest="build_dir",
|
||||||
elif arg == "--no-imagequant":
|
metavar="PILLOW_BUILD",
|
||||||
disabled += ["libimagequant"]
|
default=os.environ.get("PILLOW_BUILD", os.path.join(winbuild_dir, "build")),
|
||||||
elif arg == "--no-raqm" or arg == "--no-fribidi":
|
help="build directory (default: 'winbuild\\build')",
|
||||||
disabled += ["fribidi"]
|
)
|
||||||
elif arg.startswith("--depends="):
|
parser.add_argument(
|
||||||
depends_dir = arg[10:]
|
"--depends",
|
||||||
elif arg.startswith("--python="):
|
dest="depends_dir",
|
||||||
python_dir = arg[9:]
|
metavar="PILLOW_DEPS",
|
||||||
elif arg.startswith("--executable="):
|
default=os.environ.get("PILLOW_DEPS", os.path.join(winbuild_dir, "depends")),
|
||||||
python_exe = arg[13:]
|
help="directory used to store cached dependencies (default: 'winbuild\\depends')", # noqa: E501
|
||||||
elif arg.startswith("--architecture="):
|
)
|
||||||
architecture = arg[15:]
|
parser.add_argument(
|
||||||
elif arg.startswith("--dir="):
|
"--architecture",
|
||||||
build_dir = arg[6:]
|
choices=architectures,
|
||||||
elif arg == "--srcdir":
|
default=os.environ.get(
|
||||||
sources_dir = os.path.sep + "src"
|
"ARCHITECTURE",
|
||||||
else:
|
(
|
||||||
msg = "Unknown parameter: " + arg
|
"ARM64"
|
||||||
raise ValueError(msg)
|
if platform.machine() == "ARM64"
|
||||||
|
else ("x86" if struct.calcsize("P") == 4 else "x64")
|
||||||
|
),
|
||||||
|
),
|
||||||
|
help="build architecture (default: same as host python)",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--python",
|
||||||
|
dest="python_dir",
|
||||||
|
metavar="PYTHON",
|
||||||
|
default=os.environ.get("PYTHON"),
|
||||||
|
help="Python install directory (default: use host python)",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--executable",
|
||||||
|
dest="python_exe",
|
||||||
|
metavar="EXECUTABLE",
|
||||||
|
default=os.environ.get("EXECUTABLE", "python.exe"),
|
||||||
|
help="Python executable (default: use host python)",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--nmake",
|
||||||
|
dest="cmake_generator",
|
||||||
|
action="store_const",
|
||||||
|
const="NMake Makefiles",
|
||||||
|
default="Ninja",
|
||||||
|
help="build dependencies using NMake instead of Ninja",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--no-imagequant",
|
||||||
|
action="store_true",
|
||||||
|
help="skip GPL-licensed optional dependency libimagequant",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--no-fribidi",
|
||||||
|
"--no-raqm",
|
||||||
|
action="store_true",
|
||||||
|
help="skip LGPL-licensed optional dependency FriBiDi",
|
||||||
|
)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
# dependency cache directory
|
arch_prefs = architectures[args.architecture]
|
||||||
os.makedirs(depends_dir, exist_ok=True)
|
print("Target Architecture:", args.architecture)
|
||||||
print("Caching dependencies in:", depends_dir)
|
|
||||||
|
|
||||||
if python_dir is None:
|
if args.python_dir is None:
|
||||||
python_dir = os.path.dirname(os.path.realpath(sys.executable))
|
args.python_dir = os.path.dirname(os.path.realpath(sys.executable))
|
||||||
python_exe = os.path.basename(sys.executable)
|
args.python_exe = os.path.basename(sys.executable)
|
||||||
print("Target Python:", os.path.join(python_dir, python_exe))
|
print("Target Python:", os.path.join(args.python_dir, args.python_exe))
|
||||||
|
|
||||||
arch_prefs = architectures[architecture]
|
|
||||||
print("Target Architecture:", architecture)
|
|
||||||
|
|
||||||
msvs = find_msvs()
|
msvs = find_msvs()
|
||||||
if msvs is None:
|
if msvs is None:
|
||||||
|
@ -632,35 +667,47 @@ if __name__ == "__main__":
|
||||||
raise RuntimeError(msg)
|
raise RuntimeError(msg)
|
||||||
print("Found Visual Studio at:", msvs["vs_dir"])
|
print("Found Visual Studio at:", msvs["vs_dir"])
|
||||||
|
|
||||||
print("Using output directory:", build_dir)
|
# dependency cache directory
|
||||||
|
args.depends_dir = os.path.abspath(args.depends_dir)
|
||||||
|
os.makedirs(args.depends_dir, exist_ok=True)
|
||||||
|
print("Caching dependencies in:", args.depends_dir)
|
||||||
|
|
||||||
|
args.build_dir = os.path.abspath(args.build_dir)
|
||||||
|
print("Using output directory:", args.build_dir)
|
||||||
|
|
||||||
# build directory for *.h files
|
# build directory for *.h files
|
||||||
inc_dir = os.path.join(build_dir, "inc")
|
inc_dir = os.path.join(args.build_dir, "inc")
|
||||||
# build directory for *.lib files
|
# build directory for *.lib files
|
||||||
lib_dir = os.path.join(build_dir, "lib")
|
lib_dir = os.path.join(args.build_dir, "lib")
|
||||||
# build directory for *.bin files
|
# build directory for *.bin files
|
||||||
bin_dir = os.path.join(build_dir, "bin")
|
bin_dir = os.path.join(args.build_dir, "bin")
|
||||||
# directory for storing project files
|
# directory for storing project files
|
||||||
sources_dir = build_dir + sources_dir
|
sources_dir = os.path.join(args.build_dir, "src")
|
||||||
# copy dependency licenses to this directory
|
# copy dependency licenses to this directory
|
||||||
license_dir = os.path.join(build_dir, "license")
|
license_dir = os.path.join(args.build_dir, "license")
|
||||||
|
|
||||||
shutil.rmtree(build_dir, ignore_errors=True)
|
shutil.rmtree(args.build_dir, ignore_errors=True)
|
||||||
os.makedirs(build_dir, exist_ok=False)
|
os.makedirs(args.build_dir, exist_ok=False)
|
||||||
for path in [inc_dir, lib_dir, bin_dir, sources_dir, license_dir]:
|
for path in [inc_dir, lib_dir, bin_dir, sources_dir, license_dir]:
|
||||||
os.makedirs(path, exist_ok=True)
|
os.makedirs(path, exist_ok=True)
|
||||||
|
|
||||||
|
disabled = []
|
||||||
|
if args.no_imagequant:
|
||||||
|
disabled += ["libimagequant"]
|
||||||
|
if args.no_fribidi:
|
||||||
|
disabled += ["fribidi"]
|
||||||
|
|
||||||
prefs = {
|
prefs = {
|
||||||
# Python paths / preferences
|
# Python paths / preferences
|
||||||
"python_dir": python_dir,
|
"python_dir": args.python_dir,
|
||||||
"python_exe": python_exe,
|
"python_exe": args.python_exe,
|
||||||
"architecture": architecture,
|
"architecture": args.architecture,
|
||||||
**arch_prefs,
|
**arch_prefs,
|
||||||
# Pillow paths
|
# Pillow paths
|
||||||
"pillow_dir": os.path.realpath(os.path.join(winbuild_dir, "..")),
|
"pillow_dir": pillow_dir,
|
||||||
"winbuild_dir": winbuild_dir,
|
"winbuild_dir": winbuild_dir,
|
||||||
# Build paths
|
# Build paths
|
||||||
"build_dir": build_dir,
|
"build_dir": args.build_dir,
|
||||||
"inc_dir": inc_dir,
|
"inc_dir": inc_dir,
|
||||||
"lib_dir": lib_dir,
|
"lib_dir": lib_dir,
|
||||||
"bin_dir": bin_dir,
|
"bin_dir": bin_dir,
|
||||||
|
@ -669,7 +716,7 @@ if __name__ == "__main__":
|
||||||
# Compilers / Tools
|
# Compilers / Tools
|
||||||
**msvs,
|
**msvs,
|
||||||
"cmake": "cmake.exe", # TODO find CMAKE automatically
|
"cmake": "cmake.exe", # TODO find CMAKE automatically
|
||||||
"cmake_generator": cmake_generator,
|
"cmake_generator": args.cmake_generator,
|
||||||
# TODO find NASM automatically
|
# TODO find NASM automatically
|
||||||
# script header
|
# script header
|
||||||
"header": sum([header, msvs["header"], ["@echo on"]], []),
|
"header": sum([header, msvs["header"], ["@echo on"]], []),
|
||||||
|
@ -682,4 +729,6 @@ if __name__ == "__main__":
|
||||||
|
|
||||||
write_script(".gitignore", ["*"])
|
write_script(".gitignore", ["*"])
|
||||||
build_dep_all()
|
build_dep_all()
|
||||||
|
if args.verbose:
|
||||||
|
print()
|
||||||
build_pillow()
|
build_pillow()
|
||||||
|
|
Loading…
Reference in New Issue
Block a user