| Index: visual_studio/NativeClientVSAddIn/InstallerResources/NaCl/compiler_wrapper.py
|
| diff --git a/visual_studio/NativeClientVSAddIn/InstallerResources/NaCl/compiler_wrapper.py b/visual_studio/NativeClientVSAddIn/InstallerResources/NaCl/compiler_wrapper.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..f0daa33cc108d9ea637512b3041dedd87c06e329
|
| --- /dev/null
|
| +++ b/visual_studio/NativeClientVSAddIn/InstallerResources/NaCl/compiler_wrapper.py
|
| @@ -0,0 +1,168 @@
|
| +#!/usr/bin/env python
|
| +# Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| +# Use of this source code is governed by a BSD-style license that can be
|
| +# found in the LICENSE file
|
| +
|
| +"""Python wrapper around gcc to make it behave a little
|
| +more like cl.exe WRT to parallel building.
|
| +"""
|
| +
|
| +import multiprocessing
|
| +import os
|
| +import Queue
|
| +import shlex
|
| +import subprocess
|
| +import sys
|
| +import threading
|
| +import time
|
| +
|
| +verbose = int(os.environ.get('NACL_GCC_VERBOSE', '0'))
|
| +show_commands = int(os.environ.get('NACL_GCC_SHOW_COMMANDS', '0'))
|
| +stop_on_error = False
|
| +
|
| +
|
| +def RunGCC(cmd, basename):
|
| + """Run gcc and return the result along will the stdout/stderr."""
|
| + cmdstring = subprocess.list2cmdline(cmd)
|
| + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
| + stdout, stderr = p.communicate()
|
| + p.wait()
|
| + if show_commands:
|
| + logmsg = cmdstring
|
| + else:
|
| + logmsg = basename
|
| + stderr = logmsg + '\n' + stderr
|
| + return (p.returncode, stdout, stderr)
|
| +
|
| +
|
| +def BuildSerial(base_cmd, outpath, files):
|
| + final_result = 0
|
| +
|
| + for filename in files:
|
| + cmd, basename = MakeCommand(base_cmd, outpath, filename)
|
| + rtn, stdout, stderr = RunGCC(cmd, basename)
|
| + sys.stdout.write(stdout)
|
| + sys.stdout.flush()
|
| + sys.stderr.write(stderr)
|
| + sys.stderr.flush()
|
| + if rtn:
|
| + final_result = rtn
|
| + if stop_on_error:
|
| + break
|
| +
|
| + return final_result
|
| +
|
| +
|
| +def Worker(queue, out_queue):
|
| + """Entry point got worker threads.
|
| +
|
| + Each thread will compiler jobs from the queue until
|
| + there are no jobs left or until the main thread signals
|
| + for the work to stop.
|
| + """
|
| + while not queue.empty() and Worker.running:
|
| + item = queue.get(False)
|
| + if not item:
|
| + break
|
| + results = RunGCC(item[0], item[1])
|
| + out_queue.put(results)
|
| +
|
| +
|
| +def MakeCommand(base_cmd, outpath, filename):
|
| + """Build the full commandline given that output root
|
| + and the intput filename.
|
| +
|
| + If VS passes an existing directory to -o, then we derive the
|
| + actual object name by combining he directory name with the
|
| + basename of the source file and andding ".obj"
|
| + """
|
| + basename = os.path.basename(filename)
|
| + out = os.path.join(outpath, os.path.splitext(basename)[0] + '.obj')
|
| + return (base_cmd + ['-c', filename, '-o', out], basename)
|
| +
|
| +
|
| +def BuildParallel(cores, base_cmd, outpath, files):
|
| + Worker.running = True
|
| + pool = []
|
| + job_queue = Queue.Queue()
|
| + out_queue = Queue.Queue()
|
| +
|
| + for filename in files:
|
| + cmd, basename = MakeCommand(base_cmd, outpath, filename)
|
| + job_queue.put((cmd, basename))
|
| +
|
| + # Create worker thread pool, passing job queue
|
| + # and output queue to each worker.
|
| + args = (job_queue, out_queue)
|
| + for i in xrange(cores):
|
| + t = threading.Thread(target=Worker, args=args)
|
| + t.start()
|
| +
|
| + results = 0
|
| + Trace("waiting for %d results" % len(files))
|
| + final_result = 0
|
| + while results < len(files):
|
| + results += 1
|
| + rtn, stdout, stderr = out_queue.get()
|
| + # stdout seem to be completely ignored by visual studio
|
| + # but GCC should output all useful information on stderr
|
| + # anyway.
|
| + sys.stdout.write(stdout)
|
| + sys.stdout.flush()
|
| + sys.stderr.write(stderr)
|
| + sys.stderr.flush()
|
| + if rtn:
|
| + final_result = rtn
|
| + if stop_on_error:
|
| + # stop all workers
|
| + Worker.running = False
|
| + break
|
| +
|
| + return final_result
|
| +
|
| +
|
| +def Log(msg):
|
| + """Log message to stderr."""
|
| + # Since Visual Studio basically seems to completely ignore the stdout
|
| + # of the compiler and only echo stderr we print everythign to stderr.
|
| + sys.stderr.write(str(msg) + '\n')
|
| + sys.stderr.flush()
|
| +
|
| +
|
| +def Trace(msg):
|
| + if verbose:
|
| + Log("nacl_compiler:" + str(msg))
|
| +
|
| +
|
| +def main(args):
|
| + if args[0][0] == '@':
|
| + rspfile = args[0][1:]
|
| + args = shlex.split(open(rspfile).read())
|
| +
|
| + # find the last occurrence of '--' in the argument
|
| + # list and use that to signify the start of the
|
| + # list of sources
|
| + index = list(reversed(args)).index('--')
|
| + index = len(args) - index
|
| + base_cmd = args[:index-1]
|
| + files = args[index:]
|
| +
|
| + # remove -o <path> from base_cmd
|
| + index = base_cmd.index('-o')
|
| + outpath = base_cmd[index+1]
|
| + del base_cmd[index+1]
|
| + del base_cmd[index]
|
| +
|
| + cores = int(os.environ.get('NACL_GCC_CORES', '0'))
|
| + if not cores:
|
| + cores = multiprocessing.cpu_count()
|
| + cores = min(cores, len(files))
|
| +
|
| + Trace("compiling %d sources using %d threads" % (len(files), cores))
|
| + rtn = BuildParallel(cores, base_cmd, outpath, files)
|
| + Trace("returning %d" % rtn)
|
| + return rtn
|
| +
|
| +
|
| +if __name__ == '__main__':
|
| + sys.exit(main(sys.argv[1:]))
|
|
|