1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
|
#!/usr/bin/env python
# Copyright (c) 2014 The Native Client 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))
|