Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / native_client / pnacl / driver / driver_env.py
1 #!/usr/bin/python
2 # Copyright (c) 2012 The Native Client 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 # Global environment and expression parsing for the PNaCl driver
7
8
9 # This dictionary initializes a shell-like environment.
10 # Shell escaping and ${} substitution are provided.
11 # See "class Environment" defined later for the implementation.
12
13 from driver_log import Log, DriverExit
14 from shelltools import shell
15 import types
16
17 INITIAL_ENV = {
18   # Set by DriverMain
19   'DRIVER_PATH'     : '', # Absolute path to this driver invocation
20   'DRIVER_BIN'      : '', # PNaCl driver bin/ directory
21   'DRIVER_REV_FILE' : '${DRIVER_BIN}/REV',
22
23   'BASE_NACL'       : '${@FindBaseNaCl}',      # Absolute path of native_client/
24   'BASE_TOOLCHAIN'  : '${@FindBaseToolchain}', # Absolute path to toolchain/OS_ARCH/
25   'BASE'            : '${@FindBasePNaCl}',     # Absolute path to PNaCl
26   'BUILD_OS'        : '${@GetBuildOS}',        # "linux", "darwin" or "windows"
27   'BUILD_ARCH'      : '${@GetBuildArch}',      # "x86_64" or "i686" or "i386"
28
29   # Directories
30   'BPREFIXES'       : '', # Prefixes specified using the -B flag.
31   'BASE_LLVM'       : '${@FindBaseHost:clang}',
32   'BASE_BINUTILS'   : '${@FindBaseHost:le32-nacl-ar}',
33
34   'BASE_LIB_NATIVE' : '${BASE}/lib-',
35
36   'BASE_USR'        : '${BASE}/usr',
37   'BASE_SDK'        : '${BASE}/sdk',
38   'BASE_LIB'        : '${BASE}/lib',
39   'BASE_USR_ARCH'   : '${BASE_USR_%BCLIB_ARCH%}',
40   'BASE_USR_X8632'  : '${BASE}/usr-bc-x86-32',
41   'BASE_USR_X8664'  : '${BASE}/usr-bc-x86-64',
42   'BASE_USR_ARM'    : '${BASE}/usr-bc-arm',
43   'BASE_LIB_ARCH'   : '${BASE_LIB_%BCLIB_ARCH%}',
44   'BASE_LIB_X8632'  : '${BASE}/lib-bc-x86-32',
45   'BASE_LIB_X8664'  : '${BASE}/lib-bc-x86-64',
46   'BASE_LIB_ARM'    : '${BASE}/lib-bc-arm',
47
48   'LIBS_NATIVE_ARCH' : '${LIBS_NATIVE_%ARCH%}',
49   'LIBS_NATIVE_ARM' : '${BASE_LIB_NATIVE}arm',
50   'LIBS_NATIVE_ARM_NONSFI' : '${BASE_LIB_NATIVE}arm-nonsfi',
51   'LIBS_NATIVE_X8632' : '${BASE_LIB_NATIVE}x86-32',
52   'LIBS_NATIVE_X8632_NONSFI' : '${BASE_LIB_NATIVE}x86-32-nonsfi',
53   'LIBS_NATIVE_X8664' : '${BASE_LIB_NATIVE}x86-64',
54   'LIBS_NATIVE_MIPS32' : '${BASE_LIB_NATIVE}mips32',
55
56   'BASE_LLVM_BIN'   : '${BASE_LLVM}/bin',
57   'TRANSLATOR_BIN'  :
58     '${BASE_TOOLCHAIN}/pnacl_translator/${STANDARD_ARCH}/bin',
59
60   # TODO(pdox): Unify this with ARCH.
61   'STANDARD_ARCH'       : '${STANDARD_ARCH_%ARCH%}',
62   'STANDARD_ARCH_X8632' : 'i686',
63   'STANDARD_ARCH_X8664' : 'x86_64',
64   'STANDARD_ARCH_ARM'   : 'armv7',
65   'STANDARD_ARCH_MIPS32': 'mips32',
66
67   'SCONS_OUT'       : '${BASE_NACL}/scons-out',
68
69   # Driver settings
70   'ARCH'        : '',     # Target architecture, including optional
71                           # suffixes such as '_NONSFI' or '_LINUX'.
72   'BASE_ARCH'   : '',     # Target architecture without any '_NONSFI' suffix.
73                           # Derived from ARCH field.
74   'NONSFI_NACL' : '0',    # Whether targeting Non-SFI Mode.  Derived from
75                           # ARCH field.
76   'BIAS'        : 'NONE', # This can be 'NONE', 'ARM', 'MIPS32', 'X8632' or
77                           # 'X8664'.
78                           # When not set to none, this causes the front-end to
79                           # act like a target-specific compiler. This bias is
80                           # currently needed while compiling newlib,
81                           # and some scons tests.
82   'DRY_RUN'     : '0',
83   'SAVE_TEMPS'  : '0',    # Do not clean up temporary files
84   'SANDBOXED'   : '0',    # Use sandboxed toolchain for this arch. (main switch)
85   'HAS_FRONTEND': '',     # Set by ReadConfig().  '1' if the driver install
86                           # has support for front-end bitcode tools, or '0'
87                           # if it only has the backend translator.
88
89   'USE_EMULATOR'        : '0',
90   # Args passed from one driver invocation to another
91   'INHERITED_DRIVER_ARGS' : '',
92
93   'BCLIB_ARCH'          : '',
94   # Logging settings
95   'LOG_VERBOSE'        : '0', # Log to stdout (--pnacl-driver-verbose)
96
97   # Conventions
98   'SO_EXT'          : '${SO_EXT_%BUILD_OS%}',
99   'SO_EXT_darwin'   : '.dylib',
100   'SO_EXT_linux'    : '.so',
101   'SO_EXT_windows'  : '.dll',
102
103   'SO_DIR'          : '${SO_DIR_%BUILD_OS%}',
104   'SO_DIR_darwin'   : 'lib',
105   'SO_DIR_linux'    : 'lib',
106   'SO_DIR_windows'  : 'bin',  # On Windows, DLLs are placed in bin/
107                               # because the dynamic loader searches %PATH%
108
109   'EXEC_EXT'        : '${EXEC_EXT_%BUILD_OS%}',
110   'EXEC_EXT_darwin' : '',
111   'EXEC_EXT_linux'  : '',
112   'EXEC_EXT_windows': '.exe',
113
114   'SCONS_OS'            : '${SCONS_OS_%BUILD_OS%}',
115   'SCONS_OS_linux'      : 'linux',
116   'SCONS_OS_darwin'     : 'mac',
117   'SCONS_OS_windows'    : 'win',
118
119   # llvm goldplugin
120   'GOLD_PLUGIN_SO'  : '${BASE_LLVM}/${SO_DIR}/LLVMgold${SO_EXT}',
121
122   'SCONS_STAGING'       : '${SCONS_STAGING_%ARCH%}',
123   'SCONS_STAGING_X8632' : '${SCONS_OUT}/opt-${SCONS_OS}-x86-32/staging',
124   'SCONS_STAGING_X8664' : '${SCONS_OUT}/opt-${SCONS_OS}-x86-64/staging',
125   'SCONS_STAGING_ARM'   : '${SCONS_OUT}/opt-${SCONS_OS}-arm/staging',
126   'SCONS_STAGING_MIPS32': '${SCONS_OUT}/opt-${SCONS_OS}-mips32/staging',
127
128   'SEL_UNIVERSAL_PREFIX': '${USE_EMULATOR ? ${EMULATOR}}',
129   'SEL_UNIVERSAL'       : '${SCONS_STAGING}/sel_universal${EXEC_EXT}',
130   # NOTE: -Q skips sel_ldr qualification tests, -c -c skips validation
131   # NOTE: We are not using -B to load the IRT, since the translators do not
132   # use the IRT.
133   'SEL_UNIVERSAL_FLAGS' : '--abort_on_error ' +
134                           '--uses_reverse_service ' +
135                           '${USE_EMULATOR ? -Q -c -c --command_prefix ${EMULATOR}}',
136
137   'EMULATOR'            : '${EMULATOR_%ARCH%}',
138   'EMULATOR_X8632'      : '',
139   'EMULATOR_X8664'      : '',
140   # NOTE: this is currently the only dependency on the arm trusted TC
141   'EMULATOR_ARM'        :
142       '${BASE_NACL}/toolchain/linux_x86/arm_trusted/run_under_qemu_arm',
143   'EMULATOR_MIPS32'     :
144       '${BASE_NACL}/toolchain/linux_x86/mips_trusted/run_under_qemu_mips32',
145
146   'SEL_LDR'       : '${SCONS_STAGING}/sel_ldr${EXEC_EXT}',
147   'BOOTSTRAP_LDR' : '${SCONS_STAGING}/nacl_helper_bootstrap${EXEC_EXT}',
148
149   # sandboxed llvm backend
150   'LLC_SB'      : '${TRANSLATOR_BIN}/pnacl-llc.nexe',
151   # sandboxed linker (gold based)
152   'LD_SB'       : '${TRANSLATOR_BIN}/ld.nexe',
153
154   # Bitcode LLVM tools
155   'CLANG'         : '${BASE_LLVM_BIN}/clang${EXEC_EXT}',
156   # 'clang++' doesn't work on Windows (outside of Cygwin),
157   # because it is a symlink.
158   'CLANGXX'       : '${BASE_LLVM_BIN}/clang${EXEC_EXT} --driver-mode=g++',
159   'LLVM_OPT'      : '${BASE_LLVM_BIN}/opt${EXEC_EXT}',
160   'LLVM_DIS'      : '${BASE_LLVM_BIN}/llvm-dis${EXEC_EXT}',
161   'LLVM_NM'       : '${BASE_LLVM_BIN}/llvm-nm${EXEC_EXT}',
162   # llvm-as compiles llvm assembly (.ll) to bitcode (.bc/.po)
163   'LLVM_AS'       : '${BASE_LLVM_BIN}/llvm-as${EXEC_EXT}',
164   'PNACL_ABICHECK': '${BASE_LLVM_BIN}/pnacl-abicheck${EXEC_EXT}',
165   'PNACL_COMPRESS': '${BASE_LLVM_BIN}/pnacl-bccompress${EXEC_EXT}',
166
167   # Native LLVM tools
168   'LLVM_PNACL_LLC': '${BASE_LLVM_BIN}/pnacl-llc${EXEC_EXT}',
169   # llvm-mc is llvm's native assembler
170   'LLVM_MC'       : '${BASE_LLVM_BIN}/llvm-mc${EXEC_EXT}',
171
172   # Binutils
173   'BINUTILS_BASE'  : '${BASE_BINUTILS}/bin/le32-nacl-',
174   'OBJDUMP'        : '${BINUTILS_BASE}objdump${EXEC_EXT}',
175   'NM'             : '${BINUTILS_BASE}nm${EXEC_EXT}',
176   'AR'             : '${BINUTILS_BASE}ar${EXEC_EXT}',
177   'RANLIB'         : '${BINUTILS_BASE}ranlib${EXEC_EXT}',
178   'READELF'        : '${BINUTILS_BASE}readelf${EXEC_EXT}',
179   'STRIP'          : '${BINUTILS_BASE}strip${EXEC_EXT}',
180   # linker (used for both bitcode and ELF linking)
181   'LD'        : '${BINUTILS_BASE}ld.gold${EXEC_EXT}',
182 }
183
184 ######################################################################
185 #
186 # Environment
187 #
188 ######################################################################
189
190 def ParseError(s, leftpos, rightpos, msg):
191   Log.Error("Parse Error: %s", msg)
192   Log.Error('  ' + s)
193   Log.Error('  ' + (' '*leftpos) + ('^'*(rightpos - leftpos + 1)))
194   DriverExit(1)
195
196 # Find the leftmost position in "s" which begins a substring
197 # in "strset", starting at "pos".
198 # For example:
199 #   FindFirst('hello world', 0, ['h','o']) = ('h', 0)
200 #   FindFirst('hello world', 1, ['h','o']) = ('o', 4)
201 #   FindFirst('hello world', 0, ['x']) = (None,11)
202 def FindFirst(s, pos, strset):
203   m = {}
204   for ss in strset:
205     m[s.find(ss, pos)] = ss
206   if -1 in m:
207     del m[-1]
208   if len(m) == 0:
209     return (None, len(s))
210   pos = min(m)
211   return (m[pos], pos)
212
213 class Environment(object):
214   functions = {}
215
216   @classmethod
217   def register(cls, func):
218     """ Register a function for use in the evaluator """
219     cls.functions[func.__name__] = func
220     return func
221
222   def __init__(self):
223     self.stack = []
224     self.reset()
225
226   def reset(self):
227     self.data = dict(INITIAL_ENV)
228
229   def update(self, extra):
230     self.data.update(extra)
231
232   def dump(self):
233     for (k,v) in self.data.iteritems():
234       print '%s == %s' % (k,v)
235
236   def push(self):
237     self.stack.append(self.data)
238     self.data = dict(self.data) # Make a copy
239
240   def pop(self):
241     self.data = self.stack.pop()
242
243   def has(self, varname):
244     return varname in self.data
245
246   def getraw(self, varname):
247     return self.eval(self.data[varname])
248
249   # Evaluate a variable from the environment.
250   # Returns a list of terms.
251   def get(self, varname):
252     return shell.split(self.getraw(varname))
253
254   # Retrieve a variable from the environment which
255   # is a single term. Returns a string.
256   def getone(self, varname):
257     return shell.unescape(self.getraw(varname))
258
259   def getbool(self, varname):
260     return bool(int(self.getone(varname)))
261
262   def setbool(self, varname, val):
263     if val:
264       self.set(varname, '1')
265     else:
266       self.set(varname, '0')
267
268   # Set a variable in the environment without shell-escape
269   def setraw(self, varname, val):
270     self.data[varname] = val
271
272   # Set one or more variables using named arguments
273   def setmany(self, **kwargs):
274     for k,v in kwargs.iteritems():
275       if isinstance(v, types.StringTypes):
276         self.set(k, v)
277       elif isinstance(v, types.ListType):
278         self.set(k, *v)
279       else:
280         Log.Fatal('env.setmany given a non-string and non-list value')
281
282   def clear(self, varname):
283     self.data[varname] = ''
284
285   # Set a variable to one or more terms, applying shell-escape.
286   def set(self, varname, *vals):
287     self.clear(varname)
288     self.append(varname, *vals)
289
290   # Append one or more terms to a variable in the
291   # environment, applying shell-escape.
292   def append(self, varname, *vals):
293     escaped = [ shell.escape(v) for v in vals ]
294     if len(self.data[varname]) > 0:
295       self.data[varname] += ' '
296     self.data[varname] += ' '.join(escaped)
297
298   # Evaluate an expression s
299   def eval(self, s):
300     (result, i) = self.eval_expr(s, 0, [])
301     assert(i == len(s))
302     return result
303
304   ######################################################################
305   # EXPRESSION EVALUATION CODE
306   # Context Free Grammar:
307   #
308   # str = empty | string literal
309   # expr = str | expr '$' '{' bracket_expr '}' expr
310   # bracket_expr = varname | boolexpr ? expr | boolexpr ? expr : expr | @call
311   # boolexpr = boolval | boolval '&&' boolexpr | boolval '||' boolexpr
312   # boolval = varname | !varname | #varname | !#varname | varname '==' str
313   # varname = str | varname '%' bracket_expr '%' varname
314   # call = func | func ':' arglist
315   # func = str
316   # arglist = empty | arg ':' arglist
317   #
318   # Do not call these functions outside of this class.
319   # The env.eval method is the external interface to the evaluator.
320   ######################################################################
321
322   # Evaluate a string literal
323   def eval_str(self, s, pos, terminators):
324     (_,i) = FindFirst(s, pos, terminators)
325     return (s[pos:i], i)
326
327   # Evaluate %var% substitutions inside a variable name.
328   # Returns (the_actual_variable_name, endpos)
329   # Terminated by } character
330   def eval_varname(self, s, pos, terminators):
331     (_,i) = FindFirst(s, pos, ['%'] + terminators)
332     leftpart = s[pos:i].strip(' ')
333     if i == len(s) or s[i] in terminators:
334       return (leftpart, i)
335
336     (middlepart, j) = self.eval_bracket_expr(s, i+1, ['%'])
337     if j == len(s) or s[j] != '%':
338       ParseError(s, i, j, "Unterminated %")
339
340     (rightpart, k) = self.eval_varname(s, j+1, terminators)
341
342     fullname = leftpart + middlepart + rightpart
343     fullname = fullname.strip()
344     return (fullname, k)
345
346   # Absorb whitespace
347   def eval_whitespace(self, s, pos):
348     i = pos
349     while i < len(s) and s[i] == ' ':
350       i += 1
351     return (None, i)
352
353   def eval_bool_val(self, s, pos, terminators):
354     (_,i) = self.eval_whitespace(s, pos)
355
356     if s[i] == '!':
357       negated = True
358       i += 1
359     else:
360       negated = False
361
362     (_,i) = self.eval_whitespace(s, i)
363
364     if s[i] == '#':
365       uselen = True
366       i += 1
367     else:
368       uselen = False
369
370     (varname, j) = self.eval_varname(s, i, ['=']+terminators)
371     if j == len(s):
372       # This is an error condition one level up. Don't evaluate anything.
373       return (False, j)
374
375     if varname not in self.data:
376       ParseError(s, i, j, "Undefined variable '%s'" % varname)
377     vardata = self.data[varname]
378
379     contents = self.eval(vardata)
380
381     if s[j] == '=':
382       # String equality test
383       if j+1 == len(s) or s[j+1] != '=':
384         ParseError(s, j, j, "Unexpected token")
385       if uselen:
386         ParseError(s, j, j, "Cannot combine == and #")
387       (_,j) = self.eval_whitespace(s, j+2)
388       (literal_str,j) = self.eval_str(s, j, [' ']+terminators)
389       (_,j) = self.eval_whitespace(s, j)
390       if j == len(s):
391         return (False, j) # Error one level up
392     else:
393       literal_str = None
394
395     if uselen:
396       val = (len(contents) != 0)
397     elif literal_str is not None:
398       val = (contents == literal_str)
399     else:
400       if contents not in ('0','1'):
401         ParseError(s, j, j,
402           "%s evaluated to %s, which is not a boolean!" % (varname, contents))
403       val = bool(int(contents))
404     return (negated ^ val, j)
405
406   # Evaluate a boolexpr
407   def eval_bool_expr(self, s, pos, terminators):
408     (boolval1, i) = self.eval_bool_val(s, pos, ['&','|']+terminators)
409     if i == len(s):
410       # This is an error condition one level up. Don't evaluate anything.
411       return (False, i)
412
413     if s[i] in ('&','|'):
414       # and/or expression
415       if i+1 == len(s) or s[i+1] != s[i]:
416         ParseError(s, i, i, "Unexpected token")
417       is_and = (s[i] == '&')
418
419       (boolval2, j) = self.eval_bool_expr(s, i+2, terminators)
420       if j == len(s):
421         # This is an error condition one level up.
422         return (False, j)
423
424       if is_and:
425         return (boolval1 and boolval2, j)
426       else:
427         return (boolval1 or boolval2, j)
428
429     return (boolval1, i)
430
431   # Evaluate the inside of a ${} or %%.
432   # Returns the (the_evaluated_string, endpos)
433   def eval_bracket_expr(self, s, pos, terminators):
434     (_,pos) = self.eval_whitespace(s, pos)
435
436     if s[pos] == '@':
437       # Function call: ${@func}
438       # or possibly  : ${@func:arg1:arg2...}
439       (_,i) = FindFirst(s, pos, [':']+terminators)
440       if i == len(s):
441         return ('', i) # Error one level up
442       funcname = s[pos+1:i]
443
444       if s[i] != ':':
445         j = i
446         args = []
447       else:
448         (_,j) = FindFirst(s, i+1, terminators)
449         if j == len(s):
450           return ('', j) # Error one level up
451         args = s[i+1:j].split(':')
452
453       val = self.functions[funcname](*args)
454       contents = self.eval(val)
455       return (contents, j)
456
457     (m,_) = FindFirst(s, pos, ['?']+terminators)
458     if m != '?':
459       # Regular variable substitution
460       (varname,i) = self.eval_varname(s, pos, terminators)
461       if len(s) == i:
462         return ('', i)  # Error one level up
463       if varname not in self.data:
464         ParseError(s, pos, i, "Undefined variable '%s'" % varname)
465       vardata = self.data[varname]
466       contents = self.eval(vardata)
467       return (contents, i)
468     else:
469       # Ternary Mode
470       (is_cond_true,i) = self.eval_bool_expr(s, pos, ['?']+terminators)
471       assert(i < len(s) and s[i] == '?')
472
473       (if_true_expr, j) = self.eval_expr(s, i+1, [' : ']+terminators)
474       if j == len(s):
475         return ('', j) # Error one level up
476
477       if s[j:j+3] == ' : ':
478         (if_false_expr,j) = self.eval_expr(s, j+3, terminators)
479         if j == len(s):
480           # This is an error condition one level up.
481           return ('', j)
482       else:
483         if_false_expr = ''
484
485       if is_cond_true:
486         contents = if_true_expr.strip()
487       else:
488         contents = if_false_expr.strip()
489
490       return (contents, j)
491
492   # Evaluate an expression with ${} in string s, starting at pos.
493   # Returns (the_evaluated_expression, endpos)
494   def eval_expr(self, s, pos, terminators):
495     (m,i) = FindFirst(s, pos, ['${'] + terminators)
496     leftpart = s[pos:i]
497     if i == len(s) or m in terminators:
498       return (leftpart, i)
499
500     (middlepart, j) = self.eval_bracket_expr(s, i+2, ['}'])
501     if j == len(s) or s[j] != '}':
502       ParseError(s, i, j, 'Unterminated ${')
503
504     (rightpart, k) = self.eval_expr(s, j+1, terminators)
505     return (leftpart + middlepart + rightpart, k)
506
507
508 env = Environment()
509
510 def override_env(meth_name, func):
511   """Override a method in the global |env|, given the method name
512   and the new function.
513   """
514   global env
515   setattr(env, meth_name, types.MethodType(func, env, Environment))