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