mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-26 09:56:17 +03:00
64bce1a583
Python 3.5's distutils added support for parallel builds, which means that we don't need to monkeypatch it anymore. But more importantly, this monkeypatch made build fail (hang in fact) whenever `--parallel` was passed to `python setup.py build`. This commit fixes the problem by not applying the monkeypatch on python 3.5+ and preserve the old behavior (parallel build by default) by injecting a `parallel` option when it's not specified.
85 lines
2.7 KiB
Python
85 lines
2.7 KiB
Python
# A monkey patch of the base distutils.ccompiler to use parallel builds
|
|
# Tested on 2.7, looks to be identical to 3.3.
|
|
# Only applied on Python < 3.5 because otherwise, it conflicts with Python's
|
|
# own newly-added support for parallel builds.
|
|
|
|
from __future__ import print_function
|
|
from multiprocessing import Pool, cpu_count
|
|
from distutils.ccompiler import CCompiler
|
|
import os
|
|
import sys
|
|
|
|
try:
|
|
MAX_PROCS = int(os.environ.get('MAX_CONCURRENCY', min(4, cpu_count())))
|
|
except NotImplementedError:
|
|
MAX_PROCS = None
|
|
|
|
|
|
# hideous monkeypatching. but. but. but.
|
|
def _mp_compile_one(tp):
|
|
(self, obj, build, cc_args, extra_postargs, pp_opts) = tp
|
|
try:
|
|
src, ext = build[obj]
|
|
except KeyError:
|
|
return
|
|
self._compile(obj, src, ext, cc_args, extra_postargs, pp_opts)
|
|
return
|
|
|
|
|
|
def _mp_compile(self, sources, output_dir=None, macros=None,
|
|
include_dirs=None, debug=0, extra_preargs=None,
|
|
extra_postargs=None, depends=None):
|
|
"""Compile one or more source files.
|
|
|
|
see distutils.ccompiler.CCompiler.compile for comments.
|
|
"""
|
|
# A concrete compiler class can either override this method
|
|
# entirely or implement _compile().
|
|
|
|
macros, objects, extra_postargs, pp_opts, build = self._setup_compile(
|
|
output_dir, macros, include_dirs, sources, depends, extra_postargs)
|
|
cc_args = self._get_cc_args(pp_opts, debug, extra_preargs)
|
|
|
|
pool = Pool(MAX_PROCS)
|
|
try:
|
|
print("Building using %d processes" % pool._processes)
|
|
except:
|
|
pass
|
|
arr = [(self, obj, build, cc_args, extra_postargs, pp_opts)
|
|
for obj in objects]
|
|
pool.map_async(_mp_compile_one, arr)
|
|
pool.close()
|
|
pool.join()
|
|
# Return *all* object filenames, not just the ones we just built.
|
|
return objects
|
|
|
|
|
|
def install():
|
|
|
|
fl_win = sys.platform.startswith('win')
|
|
fl_cygwin = sys.platform.startswith('cygwin')
|
|
|
|
if fl_win or fl_cygwin:
|
|
# Windows barfs on multiprocessing installs
|
|
print("Single threaded build for Windows")
|
|
return
|
|
|
|
if MAX_PROCS != 1:
|
|
# explicitly don't enable if environment says 1 processor
|
|
try:
|
|
# bug, only enable if we can make a Pool. see issue #790 and
|
|
# https://stackoverflow.com/questions/6033599/oserror-38-errno-38-with-multiprocessing
|
|
Pool(2)
|
|
CCompiler.compile = _mp_compile
|
|
except Exception as msg:
|
|
print("Exception installing mp_compile, proceeding without:"
|
|
"%s" % msg)
|
|
else:
|
|
print("Single threaded build, not installing mp_compile:"
|
|
"%s processes" % MAX_PROCS)
|
|
|
|
|
|
# We monkeypatch only versions earlier than 3.5
|
|
if sys.version_info < (3, 5):
|
|
install()
|