1"""Patches the compile() to allow enable parallel compilation of C/C++. 2 3build_ext has lots of C/C++ files and normally them one by one. 4Enabling parallel build helps a lot. 5""" 6 7import os 8 9try: 10 BUILD_EXT_COMPILER_JOBS = int( 11 os.environ["GRPC_PYTHON_BUILD_EXT_COMPILER_JOBS"] 12 ) 13except KeyError: 14 import multiprocessing 15 16 BUILD_EXT_COMPILER_JOBS = multiprocessing.cpu_count() 17except ValueError: 18 BUILD_EXT_COMPILER_JOBS = 1 19 20 21# monkey-patch for parallel compilation 22def _parallel_compile( 23 self, 24 sources, 25 output_dir=None, 26 macros=None, 27 include_dirs=None, 28 debug=0, 29 extra_preargs=None, 30 extra_postargs=None, 31 depends=None, 32): 33 # setup the same way as distutils.ccompiler.CCompiler 34 # https://github.com/python/cpython/blob/31368a4f0e531c19affe2a1becd25fc316bc7501/Lib/distutils/ccompiler.py#L564 35 macros, objects, extra_postargs, pp_opts, build = self._setup_compile( 36 str(output_dir), macros, include_dirs, sources, depends, extra_postargs 37 ) 38 cc_args = self._get_cc_args(pp_opts, debug, extra_preargs) 39 40 def _compile_single_file(obj): 41 try: 42 src, ext = build[obj] 43 except KeyError: 44 return 45 self._compile(obj, src, ext, cc_args, extra_postargs, pp_opts) 46 47 # run compilation of individual files in parallel 48 import multiprocessing.pool 49 50 multiprocessing.pool.ThreadPool(BUILD_EXT_COMPILER_JOBS).map( 51 _compile_single_file, objects 52 ) 53 return objects 54 55 56def monkeypatch_compile_maybe(): 57 """ 58 Monkeypatching is dumb, but the build speed gain is worth it. 59 After python 3.12, we won't find distutils if SETUPTOOLS_USE_DISTUTILS=stdlib. 60 """ 61 use_distutils = os.environ.get("SETUPTOOLS_USE_DISTUTILS", "") 62 if BUILD_EXT_COMPILER_JOBS > 1 and use_distutils != "stdlib": 63 import distutils.ccompiler # pylint: disable=wrong-import-position 64 65 distutils.ccompiler.CCompiler.compile = _parallel_compile 66