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) 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))
|