OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 # vim: set ts=2 sw=2 et sts=2 ai: |
5 | 6 |
6 """Compiler version checking tool for gcc | |
7 | 7 |
8 Print gcc version as XY if you are running gcc X.Y.*. | 8 """Compiler version checking tool. |
9 This is used to tweak build flags for gcc 4.4. | 9 |
| 10 Currently supports gcc and clang on Linux. |
| 11 |
| 12 Allows getting the compiler, assembler and linker versions. |
10 """ | 13 """ |
11 | 14 |
12 import os | 15 import os |
13 import re | 16 import re |
14 import subprocess | 17 import subprocess |
| 18 import signal |
| 19 import threading |
15 import sys | 20 import sys |
16 | 21 |
17 | 22 |
18 def GetVersion(compiler, tool): | 23 def call(cmdline): |
19 tool_output = tool_error = None | |
20 try: | 24 try: |
21 # Note that compiler could be something tricky like "distcc g++". | 25 pipe = subprocess.Popen( |
22 if tool == "compiler": | 26 cmdline, shell=True, |
23 compiler = compiler + " -dumpversion" | 27 stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
24 # 4.6 | |
25 version_re = re.compile(r"(\d+)\.(\d+)") | |
26 elif tool == "assembler": | |
27 compiler = compiler + " -Xassembler --version -x assembler -c /dev/null" | |
28 # Unmodified: GNU assembler (GNU Binutils) 2.24 | |
29 # Ubuntu: GNU assembler (GNU Binutils for Ubuntu) 2.22 | |
30 # Fedora: GNU assembler version 2.23.2 | |
31 version_re = re.compile(r"^GNU [^ ]+ .* (\d+).(\d+).*?$", re.M) | |
32 elif tool == "linker": | |
33 compiler = compiler + " -Xlinker --version" | |
34 # Using BFD linker | |
35 # Unmodified: GNU ld (GNU Binutils) 2.24 | |
36 # Ubuntu: GNU ld (GNU Binutils for Ubuntu) 2.22 | |
37 # Fedora: GNU ld version 2.23.2 | |
38 # Using Gold linker | |
39 # Unmodified: GNU gold (GNU Binutils 2.24) 1.11 | |
40 # Ubuntu: GNU gold (GNU Binutils for Ubuntu 2.22) 1.11 | |
41 # Fedora: GNU gold (version 2.23.2) 1.11 | |
42 version_re = re.compile(r"^GNU [^ ]+ .* (\d+).(\d+).*?$", re.M) | |
43 else: | |
44 raise Exception("Unknown tool %s" % tool) | |
45 | 28 |
46 pipe = subprocess.Popen(compiler, shell=True, | 29 t = threading.Timer(0.25, pipe.terminate) |
47 stdout=subprocess.PIPE, stderr=subprocess.PIPE) | 30 t.start() |
48 tool_output, tool_error = pipe.communicate() | 31 tool_output, tool_error = pipe.communicate() |
49 if pipe.returncode: | 32 t.cancel() |
50 raise subprocess.CalledProcessError(pipe.returncode, compiler) | 33 return pipe.returncode, tool_output, tool_error |
| 34 except subprocess.CalledProcessError, e: |
| 35 return e.returncode, e.output[0], e.output[1] |
51 | 36 |
52 result = version_re.match(tool_output) | 37 |
53 return result.group(1) + result.group(2) | 38 class GetVersionError(Exception): |
54 except Exception, e: | 39 pass |
55 if tool_error: | 40 |
56 sys.stderr.write(tool_error) | 41 |
57 print >> sys.stderr, "compiler_version.py failed to execute:", compiler | 42 def GetVersion(compiler, tool, call=call): |
58 print >> sys.stderr, e | 43 # Note that "compiler" is the string to launch the compiler which could |
59 return "" | 44 # contains all types of weirdness like "distcc g++". |
| 45 |
| 46 if tool == "compiler": |
| 47 totry = [" --version"] |
| 48 version_re = re.compile(r"(?P<major>\d+)\.(?P<minor>\d+)") |
| 49 output_fmt = "%i%i" |
| 50 elif tool == "assembler": |
| 51 totry = [ |
| 52 "-Xassembler -version -x assembler -c /dev/null", |
| 53 # Mac's need just -v |
| 54 "-Xassembler -v -x assembler -c /dev/null", |
| 55 ] |
| 56 |
| 57 # With clang we have to pass -no-integrated-as or -fno-integrated-as for |
| 58 # the system assembler. |
| 59 for args in list(totry): |
| 60 totry.append("-no-integrated-as " + args) |
| 61 totry.append("-fno-integrated-as " + args) |
| 62 |
| 63 version_re = re.compile( |
| 64 r"^.* assembler[ )].* (?P<major>\d+).(?P<minor>\d+).*?$", |
| 65 re.M) |
| 66 output_fmt = "%i%02i" |
| 67 elif tool == "linker": |
| 68 totry = ["-Xlinker -version"] |
| 69 version_re = re.compile( |
| 70 r"^.*[ :(-](ld|gold)[ )].* (?P<major>\d+).(?P<minor>\d+)(\.\d+)?$", |
| 71 re.M) |
| 72 output_fmt = "%i%02i" |
| 73 else: |
| 74 raise ValueError("Unknown tool %s" % tool) |
| 75 |
| 76 errors = [] |
| 77 for arguments in totry: |
| 78 cmdline = "%s %s" % (compiler, arguments) |
| 79 |
| 80 retcode, tool_output, tool_error = call(cmdline) |
| 81 |
| 82 result = version_re.search(tool_output) |
| 83 if not result: |
| 84 errors.append((retcode, cmdline, tool_output, tool_error)) |
| 85 continue |
| 86 |
| 87 return output_fmt % ( |
| 88 int(result.group('major')), int(result.group('minor'))) |
| 89 |
| 90 error_output = """\ |
| 91 compiler_version.py was unable to execute requested tool. Error output follows |
| 92 |
| 93 """ |
| 94 for retcode, cmdline, stdout, stderr in errors: |
| 95 error_output += """\ |
| 96 compiler_version.py tried to execute: %s |
| 97 Command returned %s |
| 98 |
| 99 stdout output was |
| 100 -------------------------------------------------------------------------- |
| 101 %s |
| 102 -------------------------------------------------------------------------- |
| 103 stderr output was |
| 104 -------------------------------------------------------------------------- |
| 105 %s |
| 106 ========================================================================== |
| 107 """ % (cmdline, retcode, stdout, stderr) |
| 108 raise GetVersionError(error_output) |
| 109 |
| 110 |
| 111 def FindCompiler(env): |
| 112 cxx = env.get("CXX", None) |
| 113 flags = env.get("CXXFLAGS", None) |
| 114 |
| 115 if not cxx: |
| 116 cxx = "c++" |
| 117 |
| 118 if flags: |
| 119 flags = " "+flags |
| 120 else: |
| 121 flags = "" |
| 122 |
| 123 return cxx+flags |
60 | 124 |
61 | 125 |
62 def main(args): | 126 def main(args): |
63 tool = "compiler" | 127 tool = "compiler" |
64 if len(args) == 1: | 128 if len(args) == 1: |
65 tool = args[0] | 129 tool = args[0] |
66 elif len(args) > 1: | 130 elif len(args) > 1: |
67 print "Unknown arguments!" | 131 print "Unknown arguments!" |
68 | 132 |
69 # Check if CXX environment variable exists and | 133 cxxversion = GetVersion(FindCompiler(os.environ), tool) |
70 # if it does use that compiler. | 134 print cxxversion |
71 cxx = os.getenv("CXX", None) | 135 return 0 |
72 if cxx: | |
73 cxxversion = GetVersion(cxx, tool) | |
74 if cxxversion != "": | |
75 print cxxversion | |
76 return 0 | |
77 else: | |
78 # Otherwise we check the g++ version. | |
79 gccversion = GetVersion("g++", tool) | |
80 if gccversion != "": | |
81 print gccversion | |
82 return 0 | |
83 | |
84 return 1 | |
85 | 136 |
86 | 137 |
87 if __name__ == "__main__": | 138 if __name__ == "__main__": |
88 sys.exit(main(sys.argv[1:])) | 139 sys.exit(main(sys.argv[1:])) |
OLD | NEW |