Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / native_client / build / test_build.py
1 #!/usr/bin/python
2 # Copyright (c) 2011 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
7 from optparse import OptionParser
8 import os
9 import subprocess
10 import sys
11
12 sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
13 import pynacl.platform
14
15 NATIVE_CLIENT_DIR = os.path.dirname(os.path.dirname(__file__))
16 TOOLCHAIN_DIR = os.path.join(NATIVE_CLIENT_DIR, 'toolchain')
17
18 """Building verification script
19
20 This module will take the output directory path, base nexe name and
21 architecture and combine them to generate a sel_ldr execution command
22 line using irt_core of the appropriate architecture.
23 """
24
25
26 def RelativePath(filepath):
27   """Return a POSIX style relative path."""
28   cwdpath = os.path.abspath(os.getcwd())
29   cwdparts = cwdpath.split(os.path.sep)
30
31   filepath = os.path.abspath(filepath)
32
33   # For Windows, convert to POSIX style path
34   if sys.platform == 'win32':
35     filepath = filepath.replace('\\', '/')
36   fileparts = filepath.split('/')
37   for index in range(len(fileparts)):
38     if index >= len(cwdparts):
39       break
40     if cwdparts[index] != fileparts[index]:
41       break
42
43   # Add 'cd ..' the rest of cwd that doesn't match
44   out = '../' * (len(cwdparts) - index)
45   out += '/'.join(fileparts[index:])
46   return out
47
48
49 def UseWin64():
50   """Check if we are on 64 bit windows."""
51   if sys.platform != 'win32':
52     return False
53   arch32 = os.environ.get('PROCESSOR_ARCHITECTURE', 'unk')
54   arch64 = os.environ.get('PROCESSOR_ARCHITEW6432', 'unk')
55
56   if arch32 == 'AMD64' or arch64 == 'AMD64':
57     return True
58   return False
59
60
61 def ErrOut(text):
62   """ErrOut prints an error message and the command-line that caused it.
63
64   Prints to standard err, both the command-line normally, and separated by
65   >>...<< to make it easier to copy and paste the command, or to
66   find command formating issues.
67   """
68   sys.stderr.write('\n\n')
69   sys.stderr.write( '>>>' + '>> <<'.join(sys.argv) + '<<\n\n')
70   sys.stderr.write(' '.join(sys.argv) + '<<\n\n')
71   sys.stderr.write(text + '\n')
72   sys.exit(1)
73
74 def Run(cmd_line):
75   """Run the provided command-line returning the error code.
76
77   Uses supbrocess to execute the command line, printing debugging information
78   as well as error messages as appropriate.
79   """
80   sys.stdout.write('Run: %s\n' % ' '.join(cmd_line))
81   sys.stdout.flush()
82   try:
83     ecode = subprocess.call(cmd_line)
84   except Exception, err:
85     ErrOut('\nFAILED: %s\n' % str(err))
86
87   if ecode:
88     ErrOut('FAILED with return value: %d\n' % ecode)
89   else:
90     sys.stdout.write('Success\n')
91     sys.stdout.flush()
92   return ecode
93
94
95 def GetToolchainPath(tool):
96   """Given the requested tool, compute the path to that toolchain."""
97   os_name = pynacl.platform.GetOS()
98
99   if tool == 'newlib':
100     lib_name = 'newlib'
101   else:
102     lib_name = 'glibc'
103
104   return os.path.join(
105       TOOLCHAIN_DIR,
106       '%s_x86_nacl_x86' % (os_name),
107       'nacl_x86_%s' % lib_name
108   )
109
110
111 def GetLibPath(tool, arch):
112   """For a given tool and architecture, determine the library path."""
113   arch_map = {
114     'ia32': 'lib32',
115     'x64': 'lib',
116   }
117   lib = arch_map[arch]
118
119   # For 64bit win, the arch is incorrectly reported as 32bit, so override it.
120   if UseWin64():
121     lib = 'lib'
122   return os.path.join(GetToolchainPath(tool), 'x86_64-nacl', lib)
123
124
125 def GetNexe(path, name, arch, tool):
126   """For a given nexe name, architecture, and tool generate a path to it."""
127   arch_map = {
128     'ia32': 'x32',
129     'x64': 'x64',
130   }
131   # For 64bit win, the arch is incorrectly reported as 32bit, so override it.
132   if UseWin64():
133     arch = 'x64'
134   return os.path.join(path, '%s_%s_%s.nexe' % (name, tool, arch_map[arch]))
135
136
137 def GetLdrIrtNexe(path, nexe, arch, tool):
138   sel_ldr = os.path.join(path, 'sel_ldr')
139   # If incorrectly reported use sel_ldr64 otherwise assume sel_ldr is already
140   # the correct architecture.
141   if UseWin64() and arch == 'ia32':
142     sel_ldr = os.path.join(path, 'sel_ldr64')
143
144   # Get IRT_CORE which is built with newlib
145   irt_core = GetNexe(path, 'irt_core', arch, 'newlib')
146   nexe = GetNexe(path, nexe, arch, tool)
147   return (sel_ldr, irt_core, nexe)
148
149
150 def BuildCmdLine(path, nexe, arch, tool):
151   (sel_ldr, irt_core, nexe) = GetLdrIrtNexe(path, nexe, arch, tool)
152   if tool in ('newlib', 'pnacl_newlib'):
153     return [sel_ldr, '-B', irt_core, '--', nexe]
154
155   # For GLIBC we need to add 'runnable-ld.so' and allow sel_ldr access to
156   # the file system.
157   libpath = GetLibPath(tool, arch)
158   ldso = os.path.join(libpath, 'runnable-ld.so')
159   # Force POSIX style paths required by runnable-ld
160   nexe = nexe.replace('\\', '/')
161   return [sel_ldr, '-a', '-B', irt_core, '--', ldso, '--library-path',
162           libpath, nexe]
163
164
165 def RunLoader(path, nexe, arch, tools, out):
166   fail = 0
167   for tool in tools:
168     print '\n\nRunning: %s %s %s' % (nexe, arch, tool)
169     cmd_line = BuildCmdLine(path, nexe, arch, tool)
170     err = Run(cmd_line)
171     if err:
172       fail = fail + 1
173       if out:
174         out.write('%s on %s built with %s, failed returning %s.\n' %
175                   (nexe, arch, tool, err))
176     else:
177       if out:
178         out.write('SUCCESS: %s on %s built with %s.\n' % (nexe, arch, tool))
179   return fail
180
181
182 def LogLoader(path, nexe, arch, tools):
183   for tool in tools:
184     cmd_line = BuildCmdLine(path, nexe, arch, tool)
185     print ' '.join(cmd_line)
186   return 0
187
188
189 def LogDeps(path, nexe, arch, tools):
190   out_set = set()
191   out_set.add(RelativePath(__file__))
192
193   for tool in tools:
194     out_set |= set(GetLdrIrtNexe(path, nexe, arch, tool))
195   for out in out_set:
196     # Emit forward slashes here as that's what gyp expects.
197     print out.replace('\\', '/')
198
199
200 def Main(argv):
201   parser = OptionParser()
202
203   # Test build modes
204   parser.add_option('-i', '--input', help='Generate input list.',
205       action='store_const', const='i', dest='mode', default='')
206   parser.add_option('-r', '--run', help='Run the nexe.',
207       action='store_const', const='r', dest='mode', default='')
208   parser.add_option('-l', '--log', help='Log the command-lines to run.',
209       action='store_const', const='l', dest='mode', default='')
210
211   # Options
212   parser.add_option('-v', '--verbose', dest='verbose', default=False,
213                     help='Enable verbosity', action='store_true')
214   parser.add_option('-o', '--output', dest='output', default='',
215                     help='Set output file name.', action='store')
216   parser.add_option('-p', '--path', dest='path', default='.',
217                     help='Set path to sel_ldr and NEXEs.', action='store')
218   parser.add_option('-n', '--name', dest='name', action='store', default='',
219                     help='Base name of the NEXE.')
220   parser.add_option('-x', '--arch', dest='arch', action='store', default='',
221                     help='Run architecture.')
222   parser.add_option('-t', '--tools', dest='tools', action='append', default=[],
223                     help='Select which toolchains versions to run.')
224
225   options, nexe_args = parser.parse_args(argv[1:])
226   if not options.name:
227     parser.error('Missing NEXE name.')
228   if not options.mode or options.mode not in ['i', 'r', 'l']:
229     parser.error('Missing run mode.')
230   if not options.arch:
231     parser.error('Missing run architecture.')
232   if not options.tools:
233     parser.error('Missing toolchains.')
234
235   # TODO(bradnelson): Hack to prevent gyp generated path ending with \" from
236   #               being interpreted as escaped quote. Here we strip the extra
237   #               '/hack' we added in the gyp file.
238   # http://code.google.com/p/chromium/issues/detail?id=141463
239   if options.mode is 'r':
240     options.path = os.path.dirname(options.path)
241
242   if options.output:
243     try:
244       out = open(options.output, 'w')
245     except EnvironmentError:
246       print 'Failed to open %s.\n' % options.output
247       return 1
248   else:
249     out = None
250
251   tools = ','.join(options.tools)
252   tools = tools.split(',')
253   fail = 0
254   for tool in tools:
255     if tool not in ['newlib', 'glibc', 'pnacl_newlib']:
256       parser.error('Unknown tool: %s\n' % tool)
257
258   path = options.path
259   nexe = options.name
260   arch = options.arch
261
262   if options.mode == 'r':
263     fail = RunLoader(path, nexe, arch, tools, out)
264   if options.mode == 'l':
265     fail = LogLoader(path, nexe, arch, tools)
266   if options.mode == 'i':
267     fail = LogDeps('<(PRODUCT_DIR)', nexe, arch, tools)
268
269   if out:
270     out.close()
271   return fail
272
273
274 if __name__ == '__main__':
275   sys.exit(Main(sys.argv))