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__": |