| Index: build/compiler_version.py
|
| diff --git a/build/compiler_version.py b/build/compiler_version.py
|
| new file mode 100755
|
| index 0000000000000000000000000000000000000000..05faf54454df5db32de33fddf0bf5723b297ebd8
|
| --- /dev/null
|
| +++ b/build/compiler_version.py
|
| @@ -0,0 +1,143 @@
|
| +#!/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.
|
| +
|
| +"""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.
|
| +"""
|
| +
|
| +import os
|
| +import re
|
| +import subprocess
|
| +import sys
|
| +
|
| +
|
| +compiler_version_cache = {} # Map from (compiler, tool) -> version.
|
| +
|
| +
|
| +def Usage(program_name):
|
| + print '%s MODE TOOL' % os.path.basename(program_name)
|
| + print 'MODE: host or target.'
|
| + print 'TOOL: assembler or compiler or linker.'
|
| + return 1
|
| +
|
| +
|
| +def ParseArgs(args):
|
| + if len(args) != 2:
|
| + raise Exception('Invalid number of arguments')
|
| + mode = args[0]
|
| + tool = args[1]
|
| + if mode not in ('host', 'target'):
|
| + raise Exception('Invalid mode: %s' % mode)
|
| + if tool not in ('assembler', 'compiler', 'linker'):
|
| + raise Exception('Invalid tool: %s' % tool)
|
| + return mode, tool
|
| +
|
| +
|
| +def GetEnvironFallback(var_list, default):
|
| + """Look up an environment variable from a possible list of variable names."""
|
| + for var in var_list:
|
| + if var in os.environ:
|
| + return os.environ[var]
|
| + return default
|
| +
|
| +
|
| +def GetVersion(compiler, tool):
|
| + tool_output = tool_error = None
|
| + cache_key = (compiler, tool)
|
| + cached_version = compiler_version_cache.get(cache_key)
|
| + if cached_version:
|
| + return cached_version
|
| + 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)
|
| +
|
| + # Force the locale to C otherwise the version string could be localized
|
| + # making regex matching fail.
|
| + env = os.environ.copy()
|
| + env["LC_ALL"] = "C"
|
| + pipe = subprocess.Popen(compiler, shell=True, env=env,
|
| + stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
| + tool_output, tool_error = pipe.communicate()
|
| + if pipe.returncode:
|
| + raise subprocess.CalledProcessError(pipe.returncode, compiler)
|
| +
|
| + parsed_output = version_re.match(tool_output)
|
| + result = parsed_output.group(1) + parsed_output.group(2)
|
| + compiler_version_cache[cache_key] = result
|
| + return result
|
| + 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 ""
|
| +
|
| +
|
| +def main(args):
|
| + try:
|
| + (mode, tool) = ParseArgs(args[1:])
|
| + except Exception, e:
|
| + sys.stderr.write(e.message + '\n\n')
|
| + return Usage(args[0])
|
| +
|
| + ret_code, result = ExtractVersion(mode, tool)
|
| + if ret_code == 0:
|
| + print result
|
| + return ret_code
|
| +
|
| +
|
| +def DoMain(args):
|
| + """Hook to be called from gyp without starting a separate python
|
| + interpreter."""
|
| + (mode, tool) = ParseArgs(args)
|
| + ret_code, result = ExtractVersion(mode, tool)
|
| + if ret_code == 0:
|
| + return result
|
| + raise Exception("Failed to extract compiler version for args: %s" % args)
|
| +
|
| +
|
| +def ExtractVersion(mode, tool):
|
| + # Check if various CXX environment variables exist and use them if they
|
| + # exist. The preferences and fallback order is a close approximation of
|
| + # GenerateOutputForConfig() in GYP's ninja generator.
|
| + # The main difference being not supporting GYP's make_global_settings.
|
| + environments = ['CXX_target', 'CXX']
|
| + if mode == 'host':
|
| + environments = ['CXX_host'] + environments;
|
| + compiler = GetEnvironFallback(environments, 'c++')
|
| +
|
| + if compiler:
|
| + compiler_version = GetVersion(compiler, tool)
|
| + if compiler_version != "":
|
| + return (0, compiler_version)
|
| + return (1, None)
|
| +
|
| +
|
| +if __name__ == "__main__":
|
| + sys.exit(main(sys.argv))
|
|
|