OLD | NEW |
---|---|
(Empty) | |
1 #!/usr/bin/env python | |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
3 # Use of this source code is governed by a BSD-style license that can be | |
4 # found in the LICENSE file | |
5 | |
6 """Python wrapper around gcc to make it behave a little | |
7 more like cl.exe WRT to parallel building. | |
8 """ | |
9 | |
10 import multiprocessing | |
11 import os | |
12 import Queue | |
13 import shlex | |
14 import subprocess | |
15 import sys | |
16 import threading | |
17 import time | |
18 | |
19 verbose = int(os.environ.get('NACL_GCC_VERBOSE', '0')) | |
20 show_commands = int(os.environ.get('NACL_GCC_SHOW_COMMANDS', '0')) | |
21 cores = int(os.environ.get('NACL_GCC_CORES', '0')) | |
22 stop_on_error = False | |
23 | |
24 def RunGCC(cmd, basename): | |
25 cmdstring = subprocess.list2cmdline(cmd) | |
26 p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | |
27 stdout, stderr = p.communicate() | |
28 p.wait() | |
29 if show_commands: | |
30 logmsg = cmdstring | |
31 else: | |
32 logmsg = basename | |
33 stdout = logmsg + '\n' + stdout | |
34 return (p.returncode, stdout, stderr) | |
35 | |
36 | |
37 def BuildSerial(base_cmd, outpath, files): | |
38 final_result = 0 | |
39 | |
40 for filename in files: | |
41 cmd, basename = MakeCommand(base_cmd, outpath, filename) | |
42 rtn, stdout, stderr = RunGCC(cmd, basename) | |
43 sys.stderr.write(stdout) | |
44 sys.stderr.write(stderr) | |
45 if rtn: | |
46 final_result = rtn | |
47 if stop_on_error: | |
48 break | |
49 | |
50 return final_result | |
51 | |
52 | |
53 | |
54 | |
55 def Worker(queue, out_queue): | |
56 while not queue.empty() and Worker.running: | |
57 item = queue.get(False) | |
58 if not item: | |
59 break | |
60 results = RunGCC(item[0], item[1]) | |
61 out_queue.put(results) | |
62 | |
63 | |
64 def MakeCommand(base_cmd, outpath, filename): | |
65 basename = os.path.basename(filename) | |
66 out = os.path.join(outpath, os.path.splitext(basename)[0] + '.obj') | |
67 return (base_cmd + ['-c', filename, '-o', out], basename) | |
68 | |
69 | |
70 def BuildParallel(base_cmd, outpath, files): | |
71 Worker.running = True | |
72 pool = [] | |
73 job_queue = Queue.Queue() | |
74 out_queue = Queue.Queue() | |
75 | |
76 for filename in files: | |
77 cmd, basename = MakeCommand(base_cmd, outpath, filename) | |
78 job_queue.put((cmd, basename)) | |
79 | |
80 # Create worker thread pool, passing job queue | |
81 # and output queue to each worker. | |
82 args = (job_queue, out_queue) | |
83 for i in xrange(cores): | |
84 t = threading.Thread(target=Worker, args=args) | |
85 t.start() | |
86 | |
87 results = 0 | |
88 Trace("waiting for %d results" % len(files)) | |
89 final_result = 0 | |
90 while results < len(files): | |
91 results += 1 | |
92 rtn, stdout, stderr = out_queue.get() | |
93 sys.stderr.write(stdout) | |
94 sys.stderr.write(stderr) | |
95 if rtn: | |
96 final_result = rtn | |
97 if stop_on_error: | |
98 # stop all workers | |
99 Worker.running = False | |
100 break | |
101 | |
102 return final_result | |
103 | |
104 | |
105 def Log(msg): | |
106 sys.stderr.write(str(msg) + '\n') | |
107 sys.stderr.flush() | |
108 | |
109 | |
110 def Trace(msg): | |
111 if verbose: | |
112 Log(msg) | |
113 | |
114 | |
115 def main(args): | |
116 global cores | |
117 if args[0][0] == '@': | |
118 rspfile = args[0][1:] | |
119 args = shlex.split(open(rspfile).read()) | |
120 | |
121 # find the last occurrence of '--' in the argument | |
122 # list and use that to signify the start of the | |
123 # list of sources | |
124 index = list(reversed(args)).index('--') | |
125 index = len(args) - index | |
126 base_cmd = args[:index-1] | |
127 files = args[index:] | |
128 | |
129 # remove -o <path> from base_cmd | |
130 index = base_cmd.index('-o') | |
131 outpath = base_cmd[index+1] | |
132 del base_cmd[index+1] | |
133 del base_cmd[index] | |
134 | |
135 if not cores: | |
136 cores = multiprocessing.cpu_count() | |
137 | |
138 cores = min(cores, len(files)) | |
139 | |
140 Trace("compiling %d sources using %d threads" % (len(files), cores)) | |
141 | |
142 if cores == 1: | |
143 rtn = BuildSerial(base_cmd, outpath, files) | |
144 else: | |
145 rtn = BuildParallel(base_cmd, outpath, files) | |
146 | |
147 Trace("done build of %d sources" % (len(files))) | |
148 return rtn | |
149 | |
150 | |
151 if __name__ == '__main__': | |
152 main(sys.argv[1:]) | |
binji
2012/10/04 23:27:31
sys.exit(...) to send the errorcode (as long as yo
Sam Clegg
2012/10/05 21:11:19
Done.
| |
OLD | NEW |