| Index: build/compiler_version.py | 
| diff --git a/build/compiler_version.py b/build/compiler_version.py | 
| index b06712d25b2d3c25990a97f99a630a66c703ce0b..aa6df62f7542d3d7231e0f9923b3f71ef183d843 100755 | 
| --- a/build/compiler_version.py | 
| +++ b/build/compiler_version.py | 
| @@ -2,61 +2,125 @@ | 
| # 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. | 
| +# vim: set ts=2 sw=2 et sts=2 ai: | 
|  | 
| -"""Compiler version checking tool for gcc | 
|  | 
| -Print gcc version as XY if you are running gcc X.Y.*. | 
| -This is used to tweak build flags for gcc 4.4. | 
| +"""Compiler version checking tool. | 
| + | 
| +Currently supports gcc and clang on Linux. | 
| + | 
| +Allows getting the compiler, assembler and linker versions. | 
| """ | 
|  | 
| import os | 
| import re | 
| import subprocess | 
| +import signal | 
| +import threading | 
| import sys | 
|  | 
|  | 
| -def GetVersion(compiler, tool): | 
| -  tool_output = tool_error = None | 
| +def call(cmdline): | 
| try: | 
| -    # Note that compiler could be something tricky like "distcc g++". | 
| -    if tool == "compiler": | 
| -      compiler = compiler + " -dumpversion" | 
| -      # 4.6 | 
| -      version_re = re.compile(r"(\d+)\.(\d+)") | 
| -    elif tool == "assembler": | 
| -      compiler = compiler + " -Xassembler --version -x assembler -c /dev/null" | 
| -      # Unmodified: GNU assembler (GNU Binutils) 2.24 | 
| -      # Ubuntu: GNU assembler (GNU Binutils for Ubuntu) 2.22 | 
| -      # Fedora: GNU assembler version 2.23.2 | 
| -      version_re = re.compile(r"^GNU [^ ]+ .* (\d+).(\d+).*?$", re.M) | 
| -    elif tool == "linker": | 
| -      compiler = compiler + " -Xlinker --version" | 
| -      # Using BFD linker | 
| -      # Unmodified: GNU ld (GNU Binutils) 2.24 | 
| -      # Ubuntu: GNU ld (GNU Binutils for Ubuntu) 2.22 | 
| -      # Fedora: GNU ld version 2.23.2 | 
| -      # Using Gold linker | 
| -      # Unmodified: GNU gold (GNU Binutils 2.24) 1.11 | 
| -      # Ubuntu: GNU gold (GNU Binutils for Ubuntu 2.22) 1.11 | 
| -      # Fedora: GNU gold (version 2.23.2) 1.11 | 
| -      version_re = re.compile(r"^GNU [^ ]+ .* (\d+).(\d+).*?$", re.M) | 
| -    else: | 
| -      raise Exception("Unknown tool %s" % tool) | 
| - | 
| -    pipe = subprocess.Popen(compiler, shell=True, | 
| -                            stdout=subprocess.PIPE, stderr=subprocess.PIPE) | 
| +    pipe = subprocess.Popen( | 
| +        cmdline, shell=True, | 
| +        stdout=subprocess.PIPE, stderr=subprocess.PIPE) | 
| + | 
| +    t = threading.Timer(0.25, pipe.terminate) | 
| +    t.start() | 
| tool_output, tool_error = pipe.communicate() | 
| -    if pipe.returncode: | 
| -      raise subprocess.CalledProcessError(pipe.returncode, compiler) | 
| +    t.cancel() | 
| +    return pipe.returncode, tool_output, tool_error | 
| +  except subprocess.CalledProcessError, e: | 
| +    return e.returncode, e.output[0], e.output[1] | 
| + | 
| + | 
| +class GetVersionError(Exception): | 
| +  pass | 
| + | 
| + | 
| +def GetVersion(compiler, tool, call=call): | 
| +  # Note that "compiler" is the string to launch the compiler which could | 
| +  # contains all types of weirdness like "distcc g++". | 
| + | 
| +  if tool == "compiler": | 
| +    totry = [" --version"] | 
| +    version_re = re.compile(r"(?P<major>\d+)\.(?P<minor>\d+)") | 
| +    output_fmt = "%i%i" | 
| +  elif tool == "assembler": | 
| +    totry = [ | 
| +        "-Xassembler -version -x assembler -c /dev/null", | 
| +        # Mac's need just -v | 
| +        "-Xassembler -v -x assembler -c /dev/null", | 
| +        ] | 
| + | 
| +    # With clang we have to pass -no-integrated-as or -fno-integrated-as for | 
| +    # the system assembler. | 
| +    for args in list(totry): | 
| +      totry.append("-no-integrated-as " + args) | 
| +      totry.append("-fno-integrated-as " + args) | 
| + | 
| +    version_re = re.compile( | 
| +        r"^.* assembler[ )].* (?P<major>\d+).(?P<minor>\d+).*?$", | 
| +        re.M) | 
| +    output_fmt = "%i%02i" | 
| +  elif tool == "linker": | 
| +    totry = ["-Xlinker -version"] | 
| +    version_re = re.compile( | 
| +        r"^.*[ :(-](ld|gold)[ )].* (?P<major>\d+).(?P<minor>\d+)(\.\d+)?$", | 
| +        re.M) | 
| +    output_fmt = "%i%02i" | 
| +  else: | 
| +    raise ValueError("Unknown tool %s" % tool) | 
| + | 
| +  errors = [] | 
| +  for arguments in totry: | 
| +    cmdline = "%s %s" % (compiler, arguments) | 
| + | 
| +    retcode, tool_output, tool_error = call(cmdline) | 
|  | 
| -    result = version_re.match(tool_output) | 
| -    return result.group(1) + result.group(2) | 
| -  except Exception, e: | 
| -    if tool_error: | 
| -      sys.stderr.write(tool_error) | 
| -    print >> sys.stderr, "compiler_version.py failed to execute:", compiler | 
| -    print >> sys.stderr, e | 
| -    return "" | 
| +    result = version_re.search(tool_output) | 
| +    if not result: | 
| +      errors.append((retcode, cmdline, tool_output, tool_error)) | 
| +      continue | 
| + | 
| +    return output_fmt % ( | 
| +        int(result.group('major')), int(result.group('minor'))) | 
| + | 
| +  error_output = """\ | 
| +compiler_version.py was unable to execute requested tool. Error output follows | 
| + | 
| +""" | 
| +  for retcode, cmdline, stdout, stderr in errors: | 
| +    error_output += """\ | 
| +compiler_version.py tried to execute: %s | 
| +Command returned %s | 
| + | 
| +stdout output was | 
| +-------------------------------------------------------------------------- | 
| +%s | 
| +-------------------------------------------------------------------------- | 
| +stderr output was | 
| +-------------------------------------------------------------------------- | 
| +%s | 
| +========================================================================== | 
| +""" % (cmdline, retcode, stdout, stderr) | 
| +  raise GetVersionError(error_output) | 
| + | 
| + | 
| +def FindCompiler(env): | 
| +  cxx = env.get("CXX", None) | 
| +  flags = env.get("CXXFLAGS", None) | 
| + | 
| +  if not cxx: | 
| +    cxx = "c++" | 
| + | 
| +  if flags: | 
| +    flags = " "+flags | 
| +  else: | 
| +    flags = "" | 
| + | 
| +  return cxx+flags | 
|  | 
|  | 
| def main(args): | 
| @@ -66,22 +130,9 @@ def main(args): | 
| elif len(args) > 1: | 
| print "Unknown arguments!" | 
|  | 
| -  # Check if CXX environment variable exists and | 
| -  # if it does use that compiler. | 
| -  cxx = os.getenv("CXX", None) | 
| -  if cxx: | 
| -    cxxversion = GetVersion(cxx, tool) | 
| -    if cxxversion != "": | 
| -      print cxxversion | 
| -      return 0 | 
| -  else: | 
| -    # Otherwise we check the g++ version. | 
| -    gccversion = GetVersion("g++", tool) | 
| -    if gccversion != "": | 
| -      print gccversion | 
| -      return 0 | 
| - | 
| -  return 1 | 
| +  cxxversion = GetVersion(FindCompiler(os.environ), tool) | 
| +  print cxxversion | 
| +  return 0 | 
|  | 
|  | 
| if __name__ == "__main__": | 
|  |