getos.py revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
1#!/usr/bin/env python
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
4# found in the LICENSE file.
5
6"""Determine OS and various other system properties.
7
8Determine the name of the platform used and other system properties such as
9the location of Chrome.  This is used, for example, to determine the correct
10Toolchain to invoke.
11"""
12
13import optparse
14import os
15import re
16import subprocess
17import sys
18
19import oshelpers
20
21
22SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
23CHROME_DEFAULT_PATH = {
24  'win': r'c:\Program Files (x86)\Google\Chrome\Application\chrome.exe',
25  'mac': '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
26  'linux': '/usr/bin/google-chrome',
27}
28
29
30if sys.version_info < (2, 6, 0):
31  sys.stderr.write("python 2.6 or later is required run this script\n")
32  sys.exit(1)
33
34
35class Error(Exception):
36  pass
37
38
39def GetSDKPath():
40  return os.getenv('NACL_SDK_ROOT', os.path.dirname(SCRIPT_DIR))
41
42
43def GetPlatform():
44  if sys.platform.startswith('cygwin') or sys.platform.startswith('win'):
45    return 'win'
46  elif sys.platform.startswith('darwin'):
47    return 'mac'
48  elif sys.platform.startswith('linux'):
49    return 'linux'
50  else:
51    raise Error("Unknown platform: %s" % sys.platform)
52
53
54def UseWin64():
55  arch32 = os.environ.get('PROCESSOR_ARCHITECTURE')
56  arch64 = os.environ.get('PROCESSOR_ARCHITEW6432')
57
58  if arch32 == 'AMD64' or arch64 == 'AMD64':
59    return True
60  return False
61
62
63def GetSDKVersion():
64  root = GetSDKPath()
65  readme = os.path.join(root, "README")
66  if not os.path.exists(readme):
67    raise Error("README not found in SDK root: %s" % root)
68
69  version = None
70  revision = None
71  commit_position = None
72  for line in open(readme):
73    if ':' in line:
74      name, value = line.split(':', 1)
75      if name == "Version":
76        version = value.strip()
77      if name == "Chrome Revision":
78        revision = value.strip()
79      if name == "Chrome Commit Position":
80        commit_position = value.strip()
81
82  if revision is None or version is None or commit_position is None:
83    raise Error("error parsing SDK README: %s" % readme)
84
85  try:
86    version = int(version)
87    revision = int(revision)
88  except ValueError:
89    raise Error("error parsing SDK README: %s" % readme)
90
91  return (version, revision, commit_position)
92
93
94def GetSystemArch(platform):
95  if platform == 'win':
96    if UseWin64():
97      return 'x86_64'
98    return 'x86_32'
99
100  if platform in ['mac', 'linux']:
101    try:
102      pobj = subprocess.Popen(['uname', '-m'], stdout= subprocess.PIPE)
103      arch = pobj.communicate()[0]
104      arch = arch.split()[0]
105      if arch.startswith('arm'):
106        arch = 'arm'
107    except Exception:
108      arch = None
109  return arch
110
111
112def GetChromePath(platform):
113  # If CHROME_PATH is defined and exists, use that.
114  chrome_path = os.environ.get('CHROME_PATH')
115  if chrome_path:
116    if not os.path.exists(chrome_path):
117      raise Error('Invalid CHROME_PATH: %s' % chrome_path)
118    return os.path.realpath(chrome_path)
119
120  # Otherwise look in the PATH environment variable.
121  basename = os.path.basename(CHROME_DEFAULT_PATH[platform])
122  chrome_path = oshelpers.FindExeInPath(basename)
123  if chrome_path:
124    return os.path.realpath(chrome_path)
125
126  # Finally, try the default paths to Chrome.
127  chrome_path = CHROME_DEFAULT_PATH[platform]
128  if os.path.exists(chrome_path):
129    return os.path.realpath(chrome_path)
130
131  raise Error('CHROME_PATH is undefined, and %s not found in PATH, nor %s.' % (
132              basename, chrome_path))
133
134
135def GetNaClArch(platform):
136  if platform == 'win':
137    # On windows the nacl arch always matches to system arch
138    return GetSystemArch(platform)
139  elif platform == 'mac':
140    # On Mac the nacl arch is currently always 32-bit.
141    return 'x86_32'
142
143  # On linux the nacl arch matches to chrome arch, so we inspect the chrome
144  # binary using objdump
145  chrome_path = GetChromePath(platform)
146
147  # If CHROME_PATH is set to point to google-chrome or google-chrome
148  # was found in the PATH and we are running on UNIX then google-chrome
149  # is a bash script that points to 'chrome' in the same folder.
150  #
151  # When running beta or dev branch, the name is google-chrome-{beta,dev}.
152  if os.path.basename(chrome_path).startswith('google-chrome'):
153    chrome_path = os.path.join(os.path.dirname(chrome_path), 'chrome')
154
155  if not os.path.exists(chrome_path):
156    raise Error("File %s does not exist." % chrome_path)
157
158  if not os.access(chrome_path, os.X_OK):
159    raise Error("File %s is not executable" % chrome_path)
160
161  try:
162    pobj = subprocess.Popen(['objdump', '-f', chrome_path],
163                            stdout=subprocess.PIPE,
164                            stderr=subprocess.PIPE)
165    output, stderr = pobj.communicate()
166    # error out here if objdump failed
167    if pobj.returncode:
168      raise Error(output + stderr.strip())
169  except OSError as e:
170    # This will happen if objdump is not installed
171    raise Error("Error running objdump: %s" % e)
172
173  pattern = r'(file format) ([a-zA-Z0-9_\-]+)'
174  match = re.search(pattern, output)
175  if not match:
176    raise Error("Error running objdump on: %s" % chrome_path)
177
178  arch = match.group(2)
179  if 'arm' in arch:
180    return 'arm'
181  if '64' in arch:
182    return 'x86_64'
183  return 'x86_32'
184
185
186def ParseVersion(version):
187  """Parses a version number of the form '<major>.<position>'.
188
189  <position> is the Cr-Commit-Position number.
190  """
191  if '.' in version:
192    version = version.split('.')
193  else:
194    version = (version, '0')
195
196  try:
197    return tuple(int(x) for x in version)
198  except ValueError:
199    raise Error('error parsing SDK version: %s' % version)
200
201
202def CheckVersion(required_version):
203  """Determines whether the current SDK version meets the required version.
204
205  Args:
206    required_version: (major, position) pair, where position is the
207    Cr-Commit-Position number.
208
209  Raises:
210    Error: The SDK version is older than required_version.
211  """
212  version = GetSDKVersion()[:2]
213  if version < required_version:
214    raise Error("SDK version too old (current: %d.%d, required: %d.%d)"
215           % (version[0], version[1], required_version[0], required_version[1]))
216
217
218def main(args):
219  parser = optparse.OptionParser()
220  parser.add_option('--arch', action='store_true',
221      help='Print architecture of current machine (x86_32, x86_64 or arm).')
222  parser.add_option('--chrome', action='store_true',
223      help='Print the path chrome (by first looking in $CHROME_PATH and '
224           'then $PATH).')
225  parser.add_option('--nacl-arch', action='store_true',
226      help='Print architecture used by NaCl on the current machine.')
227  parser.add_option('--sdk-version', action='store_true',
228      help='Print major version of the NaCl SDK.')
229  parser.add_option('--sdk-revision', action='store_true',
230      help='Print revision number of the NaCl SDK.')
231  parser.add_option('--sdk-commit-position', action='store_true',
232      help='Print commit position of the NaCl SDK.')
233  parser.add_option('--check-version',
234      metavar='MAJOR.POSITION',
235      help='Check that the SDK version is at least as great as the '
236           'version passed in. MAJOR is the major version number and POSITION '
237           'is the Cr-Commit-Position number.')
238
239  options, _ = parser.parse_args(args)
240
241  platform = GetPlatform()
242
243  if len(args) > 1:
244    parser.error('Only one option can be specified at a time.')
245
246  if not args:
247    print platform
248    return 0
249
250  if options.arch:
251    out = GetSystemArch(platform)
252  elif options.nacl_arch:
253    out = GetNaClArch(platform)
254  elif options.chrome:
255    out = GetChromePath(platform)
256  elif options.sdk_version:
257    out = GetSDKVersion()[0]
258  elif options.sdk_revision:
259    out = GetSDKVersion()[1]
260  elif options.sdk_commit_position:
261    out = GetSDKVersion()[2]
262  elif options.check_version:
263    required_version = ParseVersion(options.check_version)
264    CheckVersion(required_version)
265    out = None
266
267  if out:
268    print out
269  return 0
270
271
272if __name__ == '__main__':
273  try:
274    sys.exit(main(sys.argv[1:]))
275  except Error as e:
276    sys.stderr.write(str(e) + '\n')
277    sys.exit(1)
278