|
Packit |
562c7a |
"""
|
|
Packit |
562c7a |
Highly experimental script that compiles the CPython standard library using Cython.
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
Execute the script either in the CPython 'Lib' directory or pass the
|
|
Packit |
562c7a |
option '--current-python' to compile the standard library of the running
|
|
Packit |
562c7a |
Python interpreter.
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
Pass '-j N' to get a parallel build with N processes.
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
Usage example::
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
$ python cystdlib.py --current-python build_ext -i
|
|
Packit |
562c7a |
"""
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
import os
|
|
Packit |
562c7a |
import sys
|
|
Packit |
562c7a |
from distutils.core import setup
|
|
Packit |
562c7a |
from Cython.Build import cythonize
|
|
Packit |
562c7a |
from Cython.Compiler import Options
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
# improve Python compatibility by allowing some broken code
|
|
Packit |
562c7a |
Options.error_on_unknown_names = False
|
|
Packit |
562c7a |
Options.error_on_uninitialized = False
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
exclude_patterns = ['**/test/**/*.py', '**/tests/**/*.py', '**/__init__.py']
|
|
Packit |
562c7a |
broken = [
|
|
Packit |
562c7a |
'idlelib/MultiCall.py',
|
|
Packit |
562c7a |
'email/utils.py',
|
|
Packit |
562c7a |
'multiprocessing/reduction.py',
|
|
Packit |
562c7a |
'multiprocessing/util.py',
|
|
Packit |
562c7a |
'threading.py', # interrupt handling
|
|
Packit |
562c7a |
'lib2to3/fixes/fix_sys_exc.py',
|
|
Packit |
562c7a |
'traceback.py',
|
|
Packit |
562c7a |
'types.py',
|
|
Packit |
562c7a |
'enum.py',
|
|
Packit |
562c7a |
'keyword.py',
|
|
Packit |
562c7a |
'_collections_abc.py',
|
|
Packit |
562c7a |
'importlib/_bootstrap',
|
|
Packit |
562c7a |
]
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
default_directives = dict(
|
|
Packit |
562c7a |
auto_cpdef=False, # enable when it's safe, see long list of failures below
|
|
Packit |
562c7a |
binding=True,
|
|
Packit |
562c7a |
set_initial_path='SOURCEFILE')
|
|
Packit |
562c7a |
default_directives['optimize.inline_defnode_calls'] = True
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
special_directives = [
|
|
Packit |
562c7a |
(['pkgutil.py',
|
|
Packit |
562c7a |
'decimal.py',
|
|
Packit |
562c7a |
'datetime.py',
|
|
Packit |
562c7a |
'optparse.py',
|
|
Packit |
562c7a |
'sndhdr.py',
|
|
Packit |
562c7a |
'opcode.py',
|
|
Packit |
562c7a |
'ntpath.py',
|
|
Packit |
562c7a |
'urllib/request.py',
|
|
Packit |
562c7a |
'plat-*/TYPES.py',
|
|
Packit |
562c7a |
'plat-*/IN.py',
|
|
Packit |
562c7a |
'tkinter/_fix.py',
|
|
Packit |
562c7a |
'lib2to3/refactor.py',
|
|
Packit |
562c7a |
'webbrowser.py',
|
|
Packit |
562c7a |
'shutil.py',
|
|
Packit |
562c7a |
'multiprocessing/forking.py',
|
|
Packit |
562c7a |
'xml/sax/expatreader.py',
|
|
Packit |
562c7a |
'xmlrpc/client.py',
|
|
Packit |
562c7a |
'pydoc.py',
|
|
Packit |
562c7a |
'xml/etree/ElementTree.py',
|
|
Packit |
562c7a |
'posixpath.py',
|
|
Packit |
562c7a |
'inspect.py',
|
|
Packit |
562c7a |
'ctypes/util.py',
|
|
Packit |
562c7a |
'urllib/parse.py',
|
|
Packit |
562c7a |
'warnings.py',
|
|
Packit |
562c7a |
'tempfile.py',
|
|
Packit |
562c7a |
'trace.py',
|
|
Packit |
562c7a |
'heapq.py',
|
|
Packit |
562c7a |
'pickletools.py',
|
|
Packit |
562c7a |
'multiprocessing/connection.py',
|
|
Packit |
562c7a |
'hashlib.py',
|
|
Packit |
562c7a |
'getopt.py',
|
|
Packit |
562c7a |
'os.py',
|
|
Packit |
562c7a |
'types.py',
|
|
Packit |
562c7a |
], dict(auto_cpdef=False)),
|
|
Packit |
562c7a |
]
|
|
Packit |
562c7a |
del special_directives[:] # currently unused
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
def build_extensions(includes='**/*.py',
|
|
Packit |
562c7a |
excludes=None,
|
|
Packit |
562c7a |
special_directives=special_directives,
|
|
Packit |
562c7a |
language_level=sys.version_info[0],
|
|
Packit |
562c7a |
parallel=None):
|
|
Packit |
562c7a |
if isinstance(includes, str):
|
|
Packit |
562c7a |
includes = [includes]
|
|
Packit |
562c7a |
excludes = list(excludes or exclude_patterns) + broken
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
all_groups = (special_directives or []) + [(includes, {})]
|
|
Packit |
562c7a |
extensions = []
|
|
Packit |
562c7a |
for modules, directives in all_groups:
|
|
Packit |
562c7a |
exclude_now = excludes[:]
|
|
Packit |
562c7a |
for other_modules, _ in special_directives:
|
|
Packit |
562c7a |
if other_modules != modules:
|
|
Packit |
562c7a |
exclude_now.extend(other_modules)
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
d = dict(default_directives)
|
|
Packit |
562c7a |
d.update(directives)
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
extensions.extend(
|
|
Packit |
562c7a |
cythonize(
|
|
Packit |
562c7a |
modules,
|
|
Packit |
562c7a |
exclude=exclude_now,
|
|
Packit |
562c7a |
exclude_failures=True,
|
|
Packit |
562c7a |
language_level=language_level,
|
|
Packit |
562c7a |
compiler_directives=d,
|
|
Packit |
562c7a |
nthreads=parallel,
|
|
Packit |
562c7a |
))
|
|
Packit |
562c7a |
return extensions
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
def build(extensions):
|
|
Packit |
562c7a |
try:
|
|
Packit |
562c7a |
setup(ext_modules=extensions)
|
|
Packit |
562c7a |
result = True
|
|
Packit |
562c7a |
except:
|
|
Packit |
562c7a |
import traceback
|
|
Packit |
562c7a |
print('error building extensions %s' % (
|
|
Packit |
562c7a |
[ext.name for ext in extensions],))
|
|
Packit |
562c7a |
traceback.print_exc()
|
|
Packit |
562c7a |
result = False
|
|
Packit |
562c7a |
return extensions, result
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
def _build(args):
|
|
Packit |
562c7a |
sys_args, ext = args
|
|
Packit |
562c7a |
sys.argv[1:] = sys_args
|
|
Packit |
562c7a |
return build([ext])
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
def parse_args():
|
|
Packit |
562c7a |
from optparse import OptionParser
|
|
Packit |
562c7a |
parser = OptionParser('%prog [options] [LIB_DIR (default: ./Lib)]')
|
|
Packit |
562c7a |
parser.add_option(
|
|
Packit |
562c7a |
'--current-python', dest='current_python', action='store_true',
|
|
Packit |
562c7a |
help='compile the stdlib of the running Python')
|
|
Packit |
562c7a |
parser.add_option(
|
|
Packit |
562c7a |
'-j', '--jobs', dest='parallel_jobs', metavar='N',
|
|
Packit |
562c7a |
type=int, default=1,
|
|
Packit |
562c7a |
help='run builds in N parallel jobs (default: 1)')
|
|
Packit |
562c7a |
parser.add_option(
|
|
Packit |
562c7a |
'-x', '--exclude', dest='excludes', metavar='PATTERN',
|
|
Packit |
562c7a |
action="append", help='exclude modules/packages matching PATTERN')
|
|
Packit |
562c7a |
options, args = parser.parse_args()
|
|
Packit |
562c7a |
if not args:
|
|
Packit |
562c7a |
args = ['./Lib']
|
|
Packit |
562c7a |
elif len(args) > 1:
|
|
Packit |
562c7a |
parser.error('only one argument expected, got %d' % len(args))
|
|
Packit |
562c7a |
return options, args
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
if __name__ == '__main__':
|
|
Packit |
562c7a |
options, args = parse_args()
|
|
Packit |
562c7a |
if options.current_python:
|
|
Packit |
562c7a |
# assume that the stdlib is where the "os" module lives
|
|
Packit |
562c7a |
os.chdir(os.path.dirname(os.__file__))
|
|
Packit |
562c7a |
else:
|
|
Packit |
562c7a |
os.chdir(args[0])
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
pool = None
|
|
Packit |
562c7a |
parallel_jobs = options.parallel_jobs
|
|
Packit |
562c7a |
if options.parallel_jobs:
|
|
Packit |
562c7a |
try:
|
|
Packit |
562c7a |
import multiprocessing
|
|
Packit |
562c7a |
pool = multiprocessing.Pool(parallel_jobs)
|
|
Packit |
562c7a |
print("Building in %d parallel processes" % parallel_jobs)
|
|
Packit |
562c7a |
except (ImportError, OSError):
|
|
Packit |
562c7a |
print("Not building in parallel")
|
|
Packit |
562c7a |
parallel_jobs = 0
|
|
Packit |
562c7a |
|
|
Packit |
562c7a |
extensions = build_extensions(
|
|
Packit |
562c7a |
parallel=parallel_jobs,
|
|
Packit |
562c7a |
excludes=options.excludes)
|
|
Packit |
562c7a |
sys_args = ['build_ext', '-i']
|
|
Packit |
562c7a |
if pool is not None:
|
|
Packit |
562c7a |
results = pool.map(_build, [(sys_args, ext) for ext in extensions])
|
|
Packit |
562c7a |
pool.close()
|
|
Packit |
562c7a |
pool.join()
|
|
Packit |
562c7a |
for ext, result in results:
|
|
Packit |
562c7a |
if not result:
|
|
Packit |
562c7a |
print("building extension %s failed" % (ext[0].name,))
|
|
Packit |
562c7a |
else:
|
|
Packit |
562c7a |
sys.argv[1:] = sys_args
|
|
Packit |
562c7a |
build(extensions)
|