Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / native_client / pnacl / driver / driver_tools.py
index bf82e69..4eea71c 100755 (executable)
@@ -2,26 +2,18 @@
 # Copyright (c) 2012 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.
-#
-# IMPORTANT NOTE: If you make local mods to this file, you must run:
-#   %  pnacl/build.sh driver
-# in order for them to take effect in the scons build.  This command
-# updates the copy in the toolchain/ tree.
-#
 
 import platform
 import os
+import random
 import re
 import shlex
 import signal
 import subprocess
-import struct
 import sys
 import tempfile
 
-import artools
 import elftools
-import ldtools
 # filetype needs to be imported here because pnacl-driver injects calls to
 # filetype.ForceFileType into argument parse actions.
 # TODO(dschuff): That's ugly. Find a better way.
@@ -31,7 +23,8 @@ import pathtools
 from driver_env import env
 # TODO: import driver_log and change these references from 'foo' to
 # 'driver_log.foo', or split driver_log further
-from driver_log import Log, DriverOpen, DriverClose, StringifyCommand, TempFiles, DriverExit, FixArch
+from driver_log import Log, DriverOpen, DriverClose, StringifyCommand, DriverExit, FixArch
+from driver_temps import TempFiles
 from shelltools import shell
 
 def ParseError(s, leftpos, rightpos, msg):
@@ -85,7 +78,32 @@ def ParseTriple(triple):
   Log.Fatal('machine/os ' + '-'.join(tokens[1:]) + ' not supported.')
 
 
-def RunDriver(invocation, args, suppress_inherited_arch_args=False):
+def GetOSName():
+  if sys.platform == 'darwin':
+    os_name = 'mac'
+  elif sys.platform.startswith('linux'):
+    os_name = 'linux'
+  elif sys.platform in ('cygwin', 'win32'):
+    os_name = 'win'
+  else:
+    Log.Fatal('Machine: %s not supported.' % sys.platform)
+
+  return os_name
+
+def GetArchNameShort():
+  machine = platform.machine().lower()
+  if machine.startswith('arm'):
+    return 'arm'
+  elif machine.startswith('mips'):
+    return 'mips'
+  elif (machine.startswith('x86')
+        or machine in ('amd32', 'i386', 'i686', 'ia32', '32', 'amd64', '64')):
+    return 'x86'
+
+  Log.Fatal('Architecture: %s not supported.' % machine)
+  return 'unknown'
+
+def RunDriver(module_name, args, suppress_inherited_arch_args=False):
   """
   RunDriver() is used to invoke "driver" tools, e.g.
   those prefixed  with "pnacl-"
@@ -98,7 +116,6 @@ def RunDriver(invocation, args, suppress_inherited_arch_args=False):
   if isinstance(args, str):
     args = shell.split(env.eval(args))
 
-  module_name = 'pnacl-%s' % invocation
   script = env.eval('${DRIVER_BIN}/%s' % module_name)
   script = shell.unescape(script)
 
@@ -176,11 +193,15 @@ def FindBaseNaCl():
 @env.register
 @memoize
 def FindBaseToolchain():
-  """ Find toolchain/ directory """
-  dir = FindBaseDir(lambda cur: pathtools.basename(cur) == 'toolchain')
-  if dir is None:
+  """ Find toolchain/OS_ARCH directory """
+  base_dir = FindBaseDir(lambda cur: pathtools.basename(cur) == 'toolchain')
+  if base_dir is None:
     Log.Fatal("Unable to find 'toolchain' directory")
-  return shell.escape(dir)
+  toolchain_dir = os.path.join(
+      base_dir,
+      '%s_%s' % (GetOSName(), GetArchNameShort())
+  )
+  return shell.escape(toolchain_dir)
 
 @env.register
 @memoize
@@ -260,7 +281,6 @@ DriverArgPatterns = [
   ( '--pnacl-i686-bias',               "env.set('BIAS', 'X8632')"),
   ( '--pnacl-x86_64-bias',             "env.set('BIAS', 'X8664')"),
   ( '--pnacl-bias=(.+)',               "env.set('BIAS', FixArch($0))"),
-  ( '--pnacl-default-command-line',    "env.set('USE_DEFAULT_CMD_LINE', '1')"),
   ( '-save-temps',                     "env.set('SAVE_TEMPS', '1')"),
   ( '-no-save-temps',                  "env.set('SAVE_TEMPS', '0')"),
   ( ('-B', '(.*)'),  AddHostBinarySearchPath),
@@ -426,6 +446,44 @@ def PathSplit(f):
   paths.reverse()
   return paths
 
+
+def CheckPathLength(filename, exit_on_failure=True):
+  '''Check that the length of the path is short enough for Windows.
+
+  On Windows, MAX_PATH is ~260 and applies to absolute paths, and to relative
+  paths and the absolute paths they expand to (except for specific uses of
+  some APIs; see link below). Most applications don't bother to support long
+  paths properly (including LLVM, GNU binutils, and ninja). If a path is too
+  long, ERROR_PATH_NOT_FOUND is returned, which isn't very useful or clear for
+  users. In addition the Chrome build has deep directory hierarchies with long
+  names.
+  This function checks that the path is valid, so we can throw meaningful
+  errors.
+
+  http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
+  '''
+  if not IsWindowsPython() and not env.has('PNACL_RUNNING_UNITTESTS'):
+    return True
+
+  # First check the name as-is (it's usually a relative path)
+  if len(filename) > 255:
+    if exit_on_failure:
+      Log.Fatal('Path name %s is too long (%d characters)' %
+                (filename, len(filename)))
+    return False
+  if os.path.isabs(filename):
+    return True
+
+  # Don't assume that the underlying tools or windows APIs will normalize
+  # the path before using it. Conservatively count the length of CWD + filename
+  appended_name = os.path.join(os.getcwd(), filename)
+  if len(appended_name) > 255:
+    if exit_on_failure:
+      Log.Fatal('Path name %s (expanded from %s) is too long (%d characters)' %
+                (appended_name, filename, len(appended_name)))
+    return False
+  return True
+
 # Generate a unique identifier for each input file.
 # Start with the basename, and if that is not unique enough,
 # add parent directories. Rinse, repeat.
@@ -435,6 +493,7 @@ class TempNameGen(object):
     output = pathtools.abspath(output)
 
     self.TempBase = output + '---linked'
+    self.OutputDir = pathtools.dirname(output)
 
     # TODO(pdox): Figure out if there's a less confusing way
     #             to simplify the intermediate filename in this case.
@@ -481,10 +540,23 @@ class TempNameGen(object):
     self.TempMap = NewMap
     return
 
+  def ValidatePathLength(self, temp, imtype):
+    # If the temp name is too long, just pick a random one instead.
+    if not CheckPathLength(temp, exit_on_failure=False):
+      # imtype is sometimes just an extension, and sometimes a compound
+      # extension (e.g. pre_opt.pexe). To keep name length shorter,
+      # only take the last extension
+      if '.' in imtype:
+        imtype = imtype[imtype.rfind('.') + 1:]
+      temp = pathtools.join(
+          self.OutputDir,
+          str(random.randrange(100000, 1000000)) + '.' + imtype)
+      CheckPathLength(temp)
+    return temp
+
   def TempNameForOutput(self, imtype):
-    temp = self.TempBase + '.' + imtype
-    if not env.getbool('SAVE_TEMPS'):
-      TempFiles.add(temp)
+    temp = self.ValidatePathLength(self.TempBase + '.' + imtype, imtype)
+    TempFiles.add(temp)
     return temp
 
   def TempNameForInput(self, input, imtype):
@@ -496,8 +568,8 @@ class TempNameGen(object):
       # Source file
       temp = self.TempMap[fullpath] + '.' + imtype
 
-    if not env.getbool('SAVE_TEMPS'):
-      TempFiles.add(temp)
+    temp = self.ValidatePathLength(temp, imtype)
+    TempFiles.add(temp)
     return temp
 
 # (Invoked from loader.py)
@@ -686,7 +758,16 @@ def DriverMain(module, argv):
 
 
 def SetArch(arch):
-  env.set('ARCH', FixArch(arch))
+  arch = FixArch(arch)
+  env.set('ARCH', arch)
+
+  nonsfi_nacl = False
+  if arch.endswith('_NONSFI'):
+    arch = arch[:-len('_NONSFI')]
+    nonsfi_nacl = True
+  env.set('BASE_ARCH', arch)
+  env.setbool('NONSFI_NACL', nonsfi_nacl)
+
 
 def GetArch(required = False):
   arch = env.getone('ARCH')
@@ -767,7 +848,14 @@ class DriverChain(object):
     # If we're compiling for a single file, then we use
     # TempNameForInput. If there are multiple files
     # (e.g. linking), then we use TempNameForOutput.
-    self.use_names_for_input = isinstance(input, str)
+    if isinstance(input, str):
+      self.use_names_for_input = True
+      CheckPathLength(input)
+    else:
+      self.use_names_for_input = False
+      for path in input:
+        CheckPathLength(path)
+    CheckPathLength(output)
 
   def add(self, callback, output_type, **extra):
     step = (callback, output_type, extra)