Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 #!/usr/bin/env python | |
|
binji
2012/10/03 22:52:13
add license header
Sam Clegg
2012/10/04 22:57:57
Done.
| |
| 2 import os | |
| 3 import Queue | |
| 4 import shlex | |
| 5 import subprocess | |
| 6 import sys | |
| 7 import threading | |
| 8 import multiprocessing | |
| 9 import time | |
|
binji
2012/10/03 22:52:13
sort imports alphabetically
Sam Clegg
2012/10/04 22:57:57
Done.
| |
| 10 | |
| 11 """Python wrapper around gcc to make it behave a little | |
| 12 more like cl.exe WRT to parallel building. | |
| 13 """ | |
| 14 | |
| 15 verbose = int(os.environ.get('NACL_GCC_VERBOSE', '0')) | |
| 16 show_commands = int(os.environ.get('NACL_GCC_SHOW_COMMANDS', '0')) | |
| 17 cores = int(os.environ.get('NACL_GCC_CORES', '0')) | |
| 18 stop_on_error = False | |
| 19 | |
| 20 def RunGCC(cmd, basename): | |
| 21 cmdstring = subprocess.list2cmdline(cmd) | |
| 22 if show_commands: | |
|
binji
2012/10/03 22:52:13
nit: move down to use of logmsg
Sam Clegg
2012/10/04 22:57:57
Done.
| |
| 23 logmsg = cmdstring | |
| 24 else: | |
| 25 logmsg = basename | |
| 26 p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | |
| 27 stdout, stderr = p.communicate() | |
| 28 p.wait() | |
| 29 stdout = logmsg + '\n' + stdout | |
| 30 return (p.returncode, stdout, stderr) | |
| 31 | |
| 32 | |
| 33 def BuildSerial(base_cmd, outpath, files): | |
|
binji
2012/10/03 22:52:13
Is this necessary? Why not always use BuildParalle
Sam Clegg
2012/10/04 22:57:57
Just here for debugging. This code path is not us
binji
2012/10/04 23:27:31
Looks like it will still run if cores==1... but it
| |
| 34 final_result = 0 | |
| 35 | |
| 36 for filename in files: | |
| 37 cmd, basename = MakeCommand(base_cmd, outpath, filename) | |
| 38 rtn, stdout, stderr = RunGCC(cmd, basename) | |
| 39 sys.stderr.write(stdout) | |
| 40 sys.stderr.write(stderr) | |
| 41 if rtn: | |
| 42 final_result = rtn | |
| 43 if stop_on_error: | |
| 44 break | |
| 45 | |
| 46 return final_result | |
| 47 | |
| 48 | |
| 49 q = Queue.Queue() | |
|
binji
2012/10/03 22:52:13
IMO, it is nicer to make these local to BuildParal
Sam Clegg
2012/10/04 22:57:57
Done.
| |
| 50 outq = Queue.Queue() | |
| 51 | |
| 52 | |
| 53 def Worker(): | |
| 54 while not q.empty(): | |
|
binji
2012/10/03 22:52:13
and Worker.running?
Sam Clegg
2012/10/04 22:57:57
Done.
| |
| 55 item = q.get(False) | |
| 56 if not item: | |
| 57 break | |
| 58 results = RunGCC(item[0], item[1]) | |
| 59 outq.put(results) | |
| 60 | |
| 61 | |
| 62 def MakeCommand(base_cmd, outpath, filename): | |
| 63 basename = os.path.basename(filename) | |
| 64 out = os.path.join(outpath, os.path.splitext(basename)[0] + '.obj') | |
|
binji
2012/10/03 22:52:13
use .o instead of .obj?
Sam Clegg
2012/10/04 22:57:57
Unfortunately we can't in this case as we need the
binji
2012/10/04 23:27:31
ok, comment would be nice. :)
| |
| 65 return (base_cmd + ['-c', filename, '-o', out], basename) | |
| 66 | |
| 67 | |
| 68 def BuildParallel(base_cmd, outpath, files): | |
| 69 pool = [] | |
| 70 | |
| 71 for filename in files: | |
| 72 cmd, basename = MakeCommand(base_cmd, outpath, filename) | |
| 73 q.put((cmd, basename)) | |
| 74 | |
| 75 Worker.running = True | |
| 76 for i in xrange(cores): | |
| 77 t = threading.Thread(target=Worker) | |
| 78 t.start() | |
| 79 | |
| 80 results = 0 | |
| 81 Trace("waiting for %d results" % len(files)) | |
| 82 final_result = 0 | |
| 83 while results < len(files): | |
| 84 results += 1 | |
| 85 rtn, stdout, stderr = outq.get() | |
| 86 sys.stderr.write(stdout) | |
|
binji
2012/10/03 22:52:13
why write stdout from compiler to stderr?
Sam Clegg
2012/10/04 22:57:57
Good question. Visual studio doesn't display stdo
binji
2012/10/04 23:27:31
OK, might add a comment then.
Sam Clegg
2012/10/05 21:11:19
Done.
| |
| 87 sys.stderr.write(stderr) | |
| 88 if rtn: | |
| 89 final_result = rtn | |
| 90 if stop_on_error: | |
| 91 # stop all workers | |
| 92 Worker.running = False | |
| 93 break | |
| 94 | |
| 95 return final_result | |
| 96 | |
| 97 | |
| 98 def Log(msg): | |
| 99 sys.stderr.write(str(msg) + '\n') | |
| 100 sys.stderr.flush() | |
| 101 | |
| 102 | |
| 103 def Trace(msg): | |
| 104 if verbose: | |
| 105 Log(msg) | |
| 106 | |
| 107 | |
| 108 def main(args): | |
| 109 global cores | |
| 110 if args[0][0] == '@': | |
| 111 rspfile = args[0][1:] | |
| 112 args = shlex.split(open(rspfile).read()) | |
| 113 | |
| 114 # find the last occurance of '--' in the argument | |
|
binji
2012/10/03 22:52:13
nit: s/occurance/occurrence/
Sam Clegg
2012/10/04 22:57:57
Done.
| |
| 115 # list an use that to signify the start of the | |
|
binji
2012/10/03 22:52:13
s/an/and/
Sam Clegg
2012/10/04 22:57:57
Done.
| |
| 116 # list of sources | |
| 117 index = list(reversed(args)).index('--') | |
| 118 index = len(args) - index | |
| 119 base_cmd = args[:index-1] | |
| 120 files = args[index:] | |
| 121 | |
| 122 # remove -o <path> from base_cmd | |
| 123 index = base_cmd.index('-o') | |
| 124 outpath = base_cmd[index+1] | |
| 125 del base_cmd[index+1] | |
| 126 del base_cmd[index] | |
| 127 | |
| 128 if not cores: | |
| 129 cores = multiprocessing.cpu_count() | |
| 130 | |
| 131 cores = min(cores, len(files)) | |
| 132 | |
| 133 Trace("compiling %d sources using %d threads" % (len(files), cores)) | |
| 134 | |
| 135 if cores == 1: | |
| 136 rtn = BuildSerial(base_cmd, outpath, files) | |
| 137 else: | |
| 138 rtn = BuildParallel(base_cmd, outpath, files) | |
| 139 | |
| 140 Trace("done build of %d sources" % (len(files))) | |
|
binji
2012/10/03 22:52:13
what about when the build fails?
Sam Clegg
2012/10/04 22:57:57
Well spotted. Amazingly (you are not going to bel
binji
2012/10/04 23:27:31
Haha, I actually meant the Trace is displaying tha
Sam Clegg
2012/10/05 21:11:19
Done.
| |
| 141 | |
| 142 | |
| 143 if __name__ == '__main__': | |
| 144 main(sys.argv[1:]) | |
| OLD | NEW |