Home | History | Annotate | Download | only in tools
      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 
      8 Determine the name of the platform used and other system properties such as
      9 the location of Chrome.  This is used, for example, to determine the correct
     10 Toolchain to invoke.
     11 """
     12 
     13 import optparse
     14 import os
     15 import re
     16 import subprocess
     17 import sys
     18 
     19 import oshelpers
     20 
     21 
     22 SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
     23 CHROME_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 
     30 if 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 
     35 class Error(Exception):
     36   pass
     37 
     38 
     39 def GetSDKPath():
     40   return os.getenv('NACL_SDK_ROOT', os.path.dirname(SCRIPT_DIR))
     41 
     42 
     43 def 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 
     54 def 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 
     63 def 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 
     94 def 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 
    112 def 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 
    135 def 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 
    186 def 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 
    202 def 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 
    218 def 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 
    272 if __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