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   for line in open(readme):
     72     if ':' in line:
     73       name, value = line.split(':', 1)
     74       if name == "Version":
     75         version = value.strip()
     76       if name == "Chrome Revision":
     77         revision = value.strip()
     78 
     79   if revision == None or version == None:
     80     raise Error("error parsing SDK README: %s" % readme)
     81 
     82   try:
     83     revision = int(revision)
     84     version = int(version)
     85   except ValueError:
     86     raise Error("error parsing SDK README: %s" % readme)
     87 
     88   return (version, revision)
     89 
     90 
     91 def GetSystemArch(platform):
     92   if platform == 'win':
     93     if UseWin64():
     94       return 'x86_64'
     95     return 'x86_32'
     96 
     97   if platform in ['mac', 'linux']:
     98     try:
     99       pobj = subprocess.Popen(['uname', '-m'], stdout= subprocess.PIPE)
    100       arch = pobj.communicate()[0]
    101       arch = arch.split()[0]
    102       if arch.startswith('arm'):
    103         arch = 'arm'
    104     except Exception:
    105       arch = None
    106   return arch
    107 
    108 
    109 def GetChromePath(platform):
    110   # If CHROME_PATH is defined and exists, use that.
    111   chrome_path = os.environ.get('CHROME_PATH')
    112   if chrome_path:
    113     if not os.path.exists(chrome_path):
    114       raise Error('Invalid CHROME_PATH: %s' % chrome_path)
    115     return os.path.realpath(chrome_path)
    116 
    117   # Otherwise look in the PATH environment variable.
    118   basename = os.path.basename(CHROME_DEFAULT_PATH[platform])
    119   chrome_path = oshelpers.FindExeInPath(basename)
    120   if chrome_path:
    121     return os.path.realpath(chrome_path)
    122 
    123   # Finally, try the default paths to Chrome.
    124   chrome_path = CHROME_DEFAULT_PATH[platform]
    125   if os.path.exists(chrome_path):
    126     return os.path.realpath(chrome_path)
    127 
    128   raise Error('CHROME_PATH is undefined, and %s not found in PATH, nor %s.' % (
    129               basename, chrome_path))
    130 
    131 
    132 def GetNaClArch(platform):
    133   if platform == 'win':
    134     # On windows the nacl arch always matches to system arch
    135     return GetSystemArch(platform)
    136   elif platform == 'mac':
    137     # On Mac the nacl arch is currently always 32-bit.
    138     return 'x86_32'
    139 
    140   # On linux the nacl arch matches to chrome arch, so we inspect the chrome
    141   # binary using objdump
    142   chrome_path = GetChromePath(platform)
    143 
    144   # If CHROME_PATH is set to point to google-chrome or google-chrome
    145   # was found in the PATH and we are running on UNIX then google-chrome
    146   # is a bash script that points to 'chrome' in the same folder.
    147   if os.path.basename(chrome_path) == 'google-chrome':
    148     chrome_path = os.path.join(os.path.dirname(chrome_path), 'chrome')
    149 
    150   try:
    151     pobj = subprocess.Popen(['objdump', '-f', chrome_path],
    152                             stdout=subprocess.PIPE,
    153                             stderr=subprocess.PIPE)
    154     output, stderr = pobj.communicate()
    155     # error out here if objdump failed
    156     if pobj.returncode:
    157       raise Error(output + stderr.strip())
    158   except OSError as e:
    159     # This will happen if objdump is not installed
    160     raise Error("Error running objdump: %s" % e)
    161 
    162   pattern = r'(file format) ([a-zA-Z0-9_\-]+)'
    163   match = re.search(pattern, output)
    164   if not match:
    165     raise Error("Error running objdump on: %s" % chrome_path)
    166 
    167   arch = match.group(2)
    168   if 'arm' in arch:
    169     return 'arm'
    170   if '64' in arch:
    171     return 'x86_64'
    172   return 'x86_32'
    173 
    174 
    175 def ParseVersion(version):
    176   if '.' in version:
    177     version = version.split('.')
    178   else:
    179     version = (version, '0')
    180 
    181   try:
    182     return tuple(int(x) for x in version)
    183   except ValueError:
    184     raise Error('error parsing SDK version: %s' % version)
    185 
    186 
    187 def main(args):
    188   parser = optparse.OptionParser()
    189   parser.add_option('--arch', action='store_true',
    190       help='Print architecture of current machine (x86_32, x86_64 or arm).')
    191   parser.add_option('--chrome', action='store_true',
    192       help='Print the path chrome (by first looking in $CHROME_PATH and '
    193            'then $PATH).')
    194   parser.add_option('--nacl-arch', action='store_true',
    195       help='Print architecture used by NaCl on the current machine.')
    196   parser.add_option('--sdk-version', action='store_true',
    197       help='Print major version of the NaCl SDK.')
    198   parser.add_option('--sdk-revision', action='store_true',
    199       help='Print revision number of the NaCl SDK.')
    200   parser.add_option('--check-version',
    201       help='Check that the SDK version is at least as great as the '
    202            'version passed in.')
    203 
    204   options, _ = parser.parse_args(args)
    205 
    206   platform = GetPlatform()
    207 
    208   if len(args) > 1:
    209     parser.error('Only one option can be specified at a time.')
    210 
    211   if not args:
    212     print platform
    213     return 0
    214 
    215   if options.arch:
    216     out = GetSystemArch(platform)
    217   elif options.nacl_arch:
    218     out = GetNaClArch(platform)
    219   elif options.chrome:
    220     out = GetChromePath(platform)
    221   elif options.sdk_version:
    222     out = GetSDKVersion()[0]
    223   elif options.sdk_revision:
    224     out = GetSDKVersion()[1]
    225   elif options.check_version:
    226     required_version = ParseVersion(options.check_version)
    227     version = GetSDKVersion()
    228     if version < required_version:
    229       raise Error("SDK version too old (current: %s.%s, required: %s.%s)"
    230              % (version[0], version[1],
    231                 required_version[0], required_version[1]))
    232     out = None
    233 
    234   if out:
    235     print out
    236   return 0
    237 
    238 
    239 if __name__ == '__main__':
    240   try:
    241     sys.exit(main(sys.argv[1:]))
    242   except Error as e:
    243     sys.stderr.write(str(e) + '\n')
    244     sys.exit(1)
    245