Enable parallel builds

This commit is contained in:
Kovid Goyal 2017-11-19 11:38:35 +05:30
parent ee232fb08c
commit b5b2f11b18
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C

View File

@ -11,6 +11,7 @@ import shutil
import subprocess import subprocess
import sys import sys
import sysconfig import sysconfig
from multiprocessing import cpu_count
base = os.path.dirname(os.path.abspath(__file__)) base = os.path.dirname(os.path.abspath(__file__))
build_dir = os.path.join(base, 'build') build_dir = os.path.join(base, 'build')
@ -212,10 +213,10 @@ def define(x):
return '-D' + x return '-D' + x
def run_tool(cmd): def run_tool(cmd, desc=None):
if isinstance(cmd, str): if isinstance(cmd, str):
cmd = shlex.split(cmd[0]) cmd = shlex.split(cmd[0])
print(' '.join(cmd)) print(desc or ' '.join(cmd))
p = subprocess.Popen(cmd) p = subprocess.Popen(cmd)
ret = p.wait() ret = p.wait()
if ret != 0: if ret != 0:
@ -262,6 +263,40 @@ def dependecies_for(src, obj, all_headers):
yield path yield path
def emphasis(text):
if sys.stdout.isatty():
text = '\033[32m' + text + '\033[39m'
return text
def parallel_run(todo, desc='Compiling {} ...'):
num_workers = max(1, cpu_count())
items = list(todo.items())
workers = {}
failed = None
def wait():
nonlocal failed
if not workers:
return
pid, s = os.wait()
name, cmd, w = workers.pop(pid, (None, None, None))
if name is not None and ((s & 0xff) != 0 or ((s >> 8) & 0xff) != 0) and failed is None:
failed = name, cmd
while items and failed is None:
while len(workers) < num_workers and items:
name, cmd = items.pop()
print(desc.format(emphasis(name)))
w = subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
workers[w.pid] = name, cmd, w
wait()
while len(workers):
wait()
if failed:
run_tool(failed[1])
def compile_c_extension(module, incremental, compilation_database, sources, headers): def compile_c_extension(module, incremental, compilation_database, sources, headers):
prefix = os.path.basename(module) prefix = os.path.basename(module)
objects = [ objects = [
@ -269,6 +304,8 @@ def compile_c_extension(module, incremental, compilation_database, sources, head
for src in sources for src in sources
] ]
todo = {}
for original_src, dest in zip(sources, objects): for original_src, dest in zip(sources, objects):
src = original_src src = original_src
cflgs = cflags[:] cflgs = cflags[:]
@ -286,10 +323,12 @@ def compile_c_extension(module, incremental, compilation_database, sources, head
): ):
cmd += ['-c', src] + ['-o', dest] cmd += ['-c', src] + ['-o', dest]
compilation_database[original_src] = cmd compilation_database[original_src] = cmd
run_tool(cmd) todo[original_src] = cmd
if todo:
parallel_run(todo)
dest = os.path.join(base, module + '.so') dest = os.path.join(base, module + '.so')
if not incremental or newer(dest, *objects): if not incremental or newer(dest, *objects):
run_tool([cc] + ldflags + objects + ldpaths + ['-o', dest]) run_tool([cc] + ldflags + objects + ldpaths + ['-o', dest], desc='Linking {} ...'.format(emphasis(module)))
def option_parser(): def option_parser():