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.
7 from optparse import OptionParser
12 sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
13 import pynacl.platform
15 NATIVE_CLIENT_DIR = os.path.dirname(os.path.dirname(__file__))
16 TOOLCHAIN_DIR = os.path.join(NATIVE_CLIENT_DIR, 'toolchain')
18 """Building verification script
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.
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)
31 filepath = os.path.abspath(filepath)
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):
40 if cwdparts[index] != fileparts[index]:
43 # Add 'cd ..' the rest of cwd that doesn't match
44 out = '../' * (len(cwdparts) - index)
45 out += '/'.join(fileparts[index:])
50 """Check if we are on 64 bit windows."""
51 if sys.platform != 'win32':
53 arch32 = os.environ.get('PROCESSOR_ARCHITECTURE', 'unk')
54 arch64 = os.environ.get('PROCESSOR_ARCHITEW6432', 'unk')
56 if arch32 == 'AMD64' or arch64 == 'AMD64':
62 """ErrOut prints an error message and the command-line that caused it.
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.
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')
75 """Run the provided command-line returning the error code.
77 Uses supbrocess to execute the command line, printing debugging information
78 as well as error messages as appropriate.
80 sys.stdout.write('Run: %s\n' % ' '.join(cmd_line))
83 ecode = subprocess.call(cmd_line)
84 except Exception, err:
85 ErrOut('\nFAILED: %s\n' % str(err))
88 ErrOut('FAILED with return value: %d\n' % ecode)
90 sys.stdout.write('Success\n')
95 def GetToolchainPath(tool):
96 """Given the requested tool, compute the path to that toolchain."""
97 os_name = pynacl.platform.GetOS()
106 '%s_x86_nacl_x86' % (os_name),
107 'nacl_x86_%s' % lib_name
111 def GetLibPath(tool, arch):
112 """For a given tool and architecture, determine the library path."""
119 # For 64bit win, the arch is incorrectly reported as 32bit, so override it.
122 return os.path.join(GetToolchainPath(tool), 'x86_64-nacl', lib)
125 def GetNexe(path, name, arch, tool):
126 """For a given nexe name, architecture, and tool generate a path to it."""
131 # For 64bit win, the arch is incorrectly reported as 32bit, so override it.
134 return os.path.join(path, '%s_%s_%s.nexe' % (name, tool, arch_map[arch]))
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')
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)
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]
155 # For GLIBC we need to add 'runnable-ld.so' and allow sel_ldr access to
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',
165 def RunLoader(path, nexe, arch, tools, out):
168 print '\n\nRunning: %s %s %s' % (nexe, arch, tool)
169 cmd_line = BuildCmdLine(path, nexe, arch, tool)
174 out.write('%s on %s built with %s, failed returning %s.\n' %
175 (nexe, arch, tool, err))
178 out.write('SUCCESS: %s on %s built with %s.\n' % (nexe, arch, tool))
182 def LogLoader(path, nexe, arch, tools):
184 cmd_line = BuildCmdLine(path, nexe, arch, tool)
185 print ' '.join(cmd_line)
189 def LogDeps(path, nexe, arch, tools):
191 out_set.add(RelativePath(__file__))
194 out_set |= set(GetLdrIrtNexe(path, nexe, arch, tool))
196 # Emit forward slashes here as that's what gyp expects.
197 print out.replace('\\', '/')
201 parser = OptionParser()
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='')
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.')
225 options, nexe_args = parser.parse_args(argv[1:])
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.')
231 parser.error('Missing run architecture.')
232 if not options.tools:
233 parser.error('Missing toolchains.')
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)
244 out = open(options.output, 'w')
245 except EnvironmentError:
246 print 'Failed to open %s.\n' % options.output
251 tools = ','.join(options.tools)
252 tools = tools.split(',')
255 if tool not in ['newlib', 'glibc', 'pnacl_newlib']:
256 parser.error('Unknown tool: %s\n' % tool)
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)
274 if __name__ == '__main__':
275 sys.exit(Main(sys.argv))