blob: b35a02fbd85d4a963b1b7af13d905af15eb59664 [file] [log] [blame]
Brian Silvermana29ebf92014-04-23 13:08:49 -05001#!/usr/bin/python3
2
3import argparse
4import sys
5import subprocess
6import re
7import os
8import os.path
9import string
10import shutil
11import errno
12
Brian Silvermanbe6cfe22014-04-27 08:06:27 -050013def aos_path():
14 return os.path.join(os.path.dirname(__file__), '..')
15
16def get_ip(device):
17 FILENAME = os.path.normpath(os.path.join(aos_path(), '..', 'output', 'ip_base.txt'))
18 if not os.access(FILENAME, os.R_OK):
19 os.makedirs(os.path.dirname(FILENAME), exist_ok=True)
20 with open(FILENAME, 'w') as f:
21 f.write('10.9.71')
22 with open(FILENAME, 'r') as f:
23 base = f.readline()
24 if device == 'prime':
25 return base + '.179'
26 elif device == 'robot':
27 return base + '.2'
28 else:
29 raise Exception('Unknown device %s to get an IP address for.' % device)
30
Brian Silvermana9b1e5c2014-04-30 18:08:04 -070031def user_output(message):
32 print('build.py: ' + message, file=sys.stderr)
33
Brian Silvermana29ebf92014-04-23 13:08:49 -050034class Processor(object):
35 class UnknownPlatform(Exception):
36 def __init__(self, message):
37 self.message = message
38
Brian Silvermanb3d50542014-04-23 14:28:55 -050039 class Platform(object):
40 def outdir(self):
41 return os.path.join(
Brian Silvermanbe6cfe22014-04-27 08:06:27 -050042 aos_path(), '..', 'output', self.outname())
Brian Silvermanb3d50542014-04-23 14:28:55 -050043 def build_ninja(self):
44 return os.path.join(self.outdir(), 'build.ninja')
45
Brian Silvermanbe6cfe22014-04-27 08:06:27 -050046 def do_deploy(self, dry_run, command):
47 real_command = (('echo',) + command) if dry_run else command
48 subprocess.check_call(real_command, stdin=open(os.devnull, 'r'))
Brian Silvermana29ebf92014-04-23 13:08:49 -050049
Brian Silvermanc2d8e5a2014-05-01 18:33:12 -070050 # TODO(brians): Verify that this (and its callers) catch everything from a
51 # fresh install.
52 def do_check_installed(self, other_packages):
53 all_packages = () + other_packages
54 try:
55 result = subprocess.check_output(
56 ('dpkg-query', '--show') + all_packages,
57 stdin=open(os.devnull, 'r'),
58 stderr=subprocess.STDOUT)
59 except subprocess.CalledProcessError as e:
60 user_output('Some packages not installed:\n'
61 + e.output.decode('utf-8').rstrip())
62 exit(1)
63
Brian Silvermana29ebf92014-04-23 13:08:49 -050064class CRIOProcessor(Processor):
Brian Silvermanb3d50542014-04-23 14:28:55 -050065 class Platform(Processor.Platform):
Brian Silvermana4aff562014-05-02 17:43:50 -070066 def __init__(self, debug, wind_base):
Brian Silvermanb3d50542014-04-23 14:28:55 -050067 super(CRIOProcessor.Platform, self).__init__()
68
69 self.debug = debug
Brian Silvermana4aff562014-05-02 17:43:50 -070070 self.wind_base = wind_base
Brian Silvermanb3d50542014-04-23 14:28:55 -050071
72 def __repr__(self):
73 return 'CRIOProcessor.Platform(debug=%s)' % self.debug
74 def __str__(self):
75 return 'crio%s' % ('-debug' if self.debug else '')
76
77 def outname(self):
78 return 'crio-debug' if self.debug else 'crio'
79 def os(self):
80 return 'vxworks'
81 def gyp_platform(self):
82 return 'crio'
83 def architecture(self):
84 return 'ppc'
85 def compiler(self):
86 return 'gcc'
87
Brian Silvermane48c09a2014-04-30 18:04:58 -070088 # TODO(brians): test this
Brian Silvermanbe6cfe22014-04-27 08:06:27 -050089 def deploy(self, dry_run):
90 self.do_deploy(dry_run,
91 ('ncftpput', get_ip('robot'), '/',
92 os.path.join(self.outdir(), 'lib', 'FRC_UserProgram.out')))
93
Brian Silvermana4aff562014-05-02 17:43:50 -070094 def build_env(self):
95 return {'WIND_BASE': self.wind_base}
96
Brian Silvermana29ebf92014-04-23 13:08:49 -050097 def __init__(self):
98 super(CRIOProcessor, self).__init__()
99
100 if 'WIND_BASE' in os.environ:
101 self.wind_base = os.environ['WIND_BASE']
102 else:
103 self.wind_base = '/usr/local/powerpc-wrs-vxworks/wind_base'
104
105 def parse_platforms(self, string):
Brian Silvermanb3d50542014-04-23 14:28:55 -0500106 if string is None or string == 'crio':
Brian Silvermana4aff562014-05-02 17:43:50 -0700107 return (CRIOProcessor.Platform(False, self.wind_base),)
108 elif string == 'crio-debug' or string == 'debug':
109 return (CRIOProcessor.Platform(True, self.wind_base),)
Brian Silvermanb3d50542014-04-23 14:28:55 -0500110 else:
111 raise Processor.UnknownPlatform('Unknown cRIO platform "%s".' % string)
Brian Silvermana29ebf92014-04-23 13:08:49 -0500112
Brian Silvermanb3d50542014-04-23 14:28:55 -0500113 def extra_gyp_flags(self):
114 return ('-DWIND_BASE=%s' % self.wind_base,)
115
Brian Silvermana29ebf92014-04-23 13:08:49 -0500116 def is_crio(self): return True
117
Brian Silvermanc2d8e5a2014-05-01 18:33:12 -0700118 def check_installed(self):
119 # TODO(brians): Add powerpc-wrs-vxworks (a new enough version too).
120 self.do_check_installed(
121 ('ncftp',))
122
Brian Silvermana29ebf92014-04-23 13:08:49 -0500123class PrimeProcessor(Processor):
Brian Silvermanb3d50542014-04-23 14:28:55 -0500124 class Platform(Processor.Platform):
Brian Silvermanf0d3c782014-05-02 23:56:32 -0700125 def __init__(self, architecture, compiler, debug, sanitizer):
Brian Silvermanb3d50542014-04-23 14:28:55 -0500126 super(PrimeProcessor.Platform, self).__init__()
127
Brian Silvermana29ebf92014-04-23 13:08:49 -0500128 self.architecture = architecture
129 self.compiler = compiler
130 self.debug = debug
Brian Silvermanf0d3c782014-05-02 23:56:32 -0700131 self.sanitizer = sanitizer
Brian Silvermana29ebf92014-04-23 13:08:49 -0500132
133 def __repr__(self):
Brian Silvermanf0d3c782014-05-02 23:56:32 -0700134 return 'PrimeProcessor.Platform(architecture=%s, compiler=%s, debug=%s' \
135 ', sanitizer=%s)' \
136 % (self.architecture, self.compiler, self.debug, self.sanitizer)
Brian Silvermana29ebf92014-04-23 13:08:49 -0500137 def __str__(self):
Brian Silvermanf0d3c782014-05-02 23:56:32 -0700138 return '%s-%s%s-%s' % (self.architecture, self.compiler,
139 '-debug' if self.debug else '', self.sanitizer)
Brian Silvermana29ebf92014-04-23 13:08:49 -0500140
141 def os(self):
142 return 'linux'
143 def gyp_platform(self):
144 return '%s-%s-%s' % (self.os(), self.architecture, self.compiler)
145
Brian Silvermana29ebf92014-04-23 13:08:49 -0500146 def outname(self):
147 return str(self)
Brian Silvermana29ebf92014-04-23 13:08:49 -0500148
Brian Silvermane48c09a2014-04-30 18:04:58 -0700149 # TODO(brians): test this
Brian Silvermanbe6cfe22014-04-27 08:06:27 -0500150 def deploy(self, dry_run):
151 """Downloads code to the prime in a way that avoids clashing too badly with starter
152 """
153 SUM = 'md5sum'
154 TARGET_DIR = '/home/driver/robot_code/bin'
155 TEMP_DIR = '/tmp/aos_downloader'
156 TARGET = 'driver@' + get_ip('prime')
157
158 from_dir = os.path.join(self.outdir(), 'outputs')
159 sums = subprocess.check_output((SUM,) + tuple(os.listdir(from_dir)),
160 stdin=open(os.devnull, 'r'),
161 cwd=from_dir)
162 to_download = subprocess.check_output(
163 ('ssh', TARGET,
164 """rm -rf {TMPDIR} && mkdir {TMPDIR} && cd {TO_DIR}
165 && echo '{SUMS}' | {SUM} --check --quiet
166 |& grep -F FAILED | sed 's/^\\(.*\\): FAILED.*"'$'"/\\1/g'""".format(
167 TMPDIR=TEMP_DIR, TO_DIR=TARGET_DIR, SUMS=sums, SUM=SUM)))
168 if not to_download:
Brian Silvermana9b1e5c2014-04-30 18:08:04 -0700169 user_output("Nothing to download")
Brian Silvermanbe6cfe22014-04-27 08:06:27 -0500170 return
171 self.do_deploy(
172 dry_run,
173 ('scp', '-o', 'Compression yes') + to_download
174 + (('%s:%s' % (TARGET, TEMP_DIR)),))
175 if not dry_run:
176 subprocess.check_call(
177 ('ssh', TARGET,
178 """mv {TMPDIR}/* {TO_DIR}
179 && echo 'Done moving new executables into place'
180 && ionice -c 3 bash -c 'sync && sync && sync'""".format(
181 TMPDIR=TEMP_DIR, TO_DIR=TARGET_DIR)))
182
Brian Silvermana4aff562014-05-02 17:43:50 -0700183 def build_env(self):
184 r = {}
Brian Silverman47cd6f62014-05-03 10:35:52 -0700185 if self.compiler == 'clang' or self.compiler == 'gcc_4.8':
Brian Silvermana4aff562014-05-02 17:43:50 -0700186 r['LD_LIBRARY_PATH'] = '/opt/clang-3.5/lib64'
Brian Silvermanf0d3c782014-05-02 23:56:32 -0700187 if self.sanitizer == 'address':
Brian Silvermana4aff562014-05-02 17:43:50 -0700188 r['ASAN_SYMBOLIZER_PATH'] = '/opt/clang-3.5/bin/llvm-symbolizer'
189 r['ASAN_OPTIONS'] = 'detect_leaks=1:check_initialization_order=1:strict_init_order=1'
Brian Silvermanf0d3c782014-05-02 23:56:32 -0700190 elif self.sanitizer == 'memory':
191 r['MSAN_SYMBOLIZER_PATH'] = '/opt/clang-3.5/bin/llvm-symbolizer'
Brian Silvermand3fac732014-05-03 16:03:46 -0700192
193 r['CCACHE_COMPRESS'] = 'yes'
194 r['CCACHE_DIR'] = \
195 os.path.abspath(os.path.join(aos_path(), '..', 'output', 'ccache_dir'))
196 r['CCACHE_HASHDIR'] = 'yes'
197 if self.compiler == 'clang':
198 # clang doesn't like being run directly on the preprocessed files.
199 r['CCACHE_CPP2'] = 'yes'
200 # Without this, ccache slows down because of the generated header files.
201 # The race condition that this opens up isn't a problem because the build
202 # system finishes modifying header files before compiling anything that
203 # uses them.
204 r['CCACHE_SLOPPINESS'] = 'include_file_mtime'
205 r['CCACHE_COMPILERCHECK'] = 'content'
206
207 if self.architecture == 'amd64':
208 r['PATH'] = os.path.join(aos_path(), 'build', 'bin-ld.gold') + \
209 ':' + os.environ['PATH']
210
Brian Silvermana4aff562014-05-02 17:43:50 -0700211 return r
212
Brian Silverman47cd6f62014-05-03 10:35:52 -0700213 ARCHITECTURES = ('arm', 'amd64')
214 COMPILERS = ('clang', 'gcc', 'gcc_4.8')
215 SANITIZERS = ('address', 'undefined', 'integer', 'memory', 'thread', 'none')
216 SANITIZER_TEST_WARNINGS = {
217 'memory': (True,
218"""We don't have all of the libraries instrumented which leads to lots of false
219errors with msan (especially stdlibc++).
220TODO(brians): Figure out a way to deal with it."""),
221 'undefined': (False,
222"""There are several warnings in other people's code that ubsan catches.
223The following have been verified non-interesting:
224 include/c++/4.8.2/array:*: runtime error: reference binding to null pointer of type 'int'
225 This happens with ::std::array<T, 0> and it doesn't seem to cause any issues.
226 output/downloaded/eigen-3.2.1/Eigen/src/Core/util/Memory.h:782:*: runtime error: load of misaligned address 0x* for type 'const int', which requires 4 byte alignment
227 That's in the CPUID detection code which only runs on x86."""),
228 }
Brian Silvermana5301e32014-05-03 10:51:49 -0700229 PIE_SANITIZERS = ('memory', 'thread')
Brian Silvermana29ebf92014-04-23 13:08:49 -0500230
Brian Silvermanbe6cfe22014-04-27 08:06:27 -0500231 def __init__(self, is_test, is_deploy):
Brian Silvermana29ebf92014-04-23 13:08:49 -0500232 super(Processor, self).__init__()
233
234 platforms = []
235 for architecture in PrimeProcessor.ARCHITECTURES:
236 for compiler in PrimeProcessor.COMPILERS:
237 for debug in [True, False]:
Brian Silverman47cd6f62014-05-03 10:35:52 -0700238 if architecture == 'arm' and compiler == 'gcc_4.8':
239 # We don't have a compiler to use here.
240 continue
Brian Silvermana29ebf92014-04-23 13:08:49 -0500241 platforms.append(
Brian Silvermanf0d3c782014-05-02 23:56:32 -0700242 PrimeProcessor.Platform(architecture, compiler, debug, 'none'))
243 for sanitizer in PrimeProcessor.SANITIZERS:
Brian Silverman47cd6f62014-05-03 10:35:52 -0700244 for compiler in ('gcc_4.8', 'clang'):
245 if compiler == 'gcc_4.8' and (sanitizer == 'undefined' or
246 sanitizer == 'integer' or
247 sanitizer == 'memory'):
248 # GCC 4.8 doesn't support these sanitizers.
249 continue
250 # We already added sanitizer == 'none' above.
251 if sanitizer != 'none':
252 platforms.append(
253 PrimeProcessor.Platform('amd64', compiler, True, sanitizer))
Brian Silvermana29ebf92014-04-23 13:08:49 -0500254 self.platforms = frozenset(platforms)
Brian Silvermanbe6cfe22014-04-27 08:06:27 -0500255 if is_test:
Brian Silvermanc2d8e5a2014-05-01 18:33:12 -0700256 self.default_platforms = self.select_platforms(architecture='amd64',
257 debug=True)
Brian Silverman47cd6f62014-05-03 10:35:52 -0700258 for sanitizer in PrimeProcessor.SANITIZER_TEST_WARNINGS:
259 self.default_platforms -= self.select_platforms(sanitizer=sanitizer)
Brian Silvermanbe6cfe22014-04-27 08:06:27 -0500260 elif is_deploy:
261 # TODO(brians): Switch to deploying the code built with clang.
Brian Silvermanc2d8e5a2014-05-01 18:33:12 -0700262 self.default_platforms = self.select_platforms(architecture='arm',
263 compiler='gcc',
264 debug=False)
Brian Silvermanbe6cfe22014-04-27 08:06:27 -0500265 else:
266 self.default_platforms = self.select_platforms(debug=False)
Brian Silvermana29ebf92014-04-23 13:08:49 -0500267
Brian Silvermanb3d50542014-04-23 14:28:55 -0500268 def extra_gyp_flags(self):
269 return ()
Brian Silvermana29ebf92014-04-23 13:08:49 -0500270 def is_crio(self): return False
271
272 def parse_platforms(self, string):
273 if string is None:
274 return self.default_platforms
275 r = self.default_platforms
276 for part in string.split(','):
277 if part[0] == '+':
278 r = r | self.select_platforms_string(part[1:])
279 elif part[0] == '-':
280 r = r - self.select_platforms_string(part[1:])
281 elif part[0] == '=':
282 r = self.select_platforms_string(part[1:])
283 else:
Brian Silverman7cd5ad42014-04-27 08:11:30 -0500284 selected = self.select_platforms_string(part)
285 r = r - (self.platforms - selected)
286 if not r:
287 r = selected
Brian Silvermana29ebf92014-04-23 13:08:49 -0500288 return r
289
Brian Silvermanf0d3c782014-05-02 23:56:32 -0700290 def select_platforms(self, architecture=None, compiler=None, debug=None, sanitizer=None):
Brian Silvermana29ebf92014-04-23 13:08:49 -0500291 r = []
292 for platform in self.platforms:
293 if architecture is None or platform.architecture == architecture:
294 if compiler is None or platform.compiler == compiler:
295 if debug is None or platform.debug == debug:
Brian Silvermanf0d3c782014-05-02 23:56:32 -0700296 if sanitizer is None or platform.sanitizer == sanitizer:
297 r.append(platform)
Brian Silvermana29ebf92014-04-23 13:08:49 -0500298 return set(r)
299
300 def select_platforms_string(self, string):
301 r = []
Brian Silvermanf0d3c782014-05-02 23:56:32 -0700302 architecture, compiler, debug, sanitizer = None, None, None, None
Brian Silvermana29ebf92014-04-23 13:08:49 -0500303 for part in string.split('-'):
304 if part in PrimeProcessor.ARCHITECTURES:
305 architecture = part
306 elif part in PrimeProcessor.COMPILERS:
307 compiler = part
308 elif part in ['debug', 'dbg']:
309 debug = True
310 elif part in ['release', 'nodebug', 'ndb']:
311 debug = False
Brian Silvermanf0d3c782014-05-02 23:56:32 -0700312 elif part in PrimeProcessor.SANITIZERS:
313 sanitizer = part
Brian Silvermana29ebf92014-04-23 13:08:49 -0500314 else:
315 raise Processor.UnknownPlatform('Unknown platform string component "%s".' % part)
316 return self.select_platforms(
317 architecture=architecture,
318 compiler=compiler,
Brian Silvermanf0d3c782014-05-02 23:56:32 -0700319 debug=debug,
320 sanitizer=sanitizer)
Brian Silvermana29ebf92014-04-23 13:08:49 -0500321
Brian Silvermanc2d8e5a2014-05-01 18:33:12 -0700322 def check_installed(self):
323 self.do_check_installed(
324 ('clang-3.5', 'gcc-4.7-arm-linux-gnueabihf',
325 'g++-4.7-arm-linux-gnueabihf', 'openssh-client'))
326
Brian Silvermana29ebf92014-04-23 13:08:49 -0500327def main():
328 class TryParsingAgain(Exception):
329 pass
330
331 class TryAgainArgumentParser(argparse.ArgumentParser):
332 def __init__(self, **kwargs):
333 super(TryAgainArgumentParser, self).__init__(**kwargs)
334
335 def error(self, message):
336 raise TryParsingAgain
337
338 def SetUpParser(parser, args):
339 def AddBuildArgs(parser):
340 parser.add_argument(
341 'target',
342 help='target to build',
343 nargs='*')
344 def AddCommonArgs(parser):
345 parser.add_argument(
346 'platforms',
347 help='platform(s) to act on',
348 nargs='?')
349
350 parser.add_argument('--processor', required=True, help='prime or crio')
351 parser.add_argument('--main_gyp', required=True, help='main .gyp file')
352 subparsers = parser.add_subparsers(dest='action_name')
353
354 build_parser = subparsers.add_parser(
355 'build',
356 help='build the code (default)')
357 AddCommonArgs(build_parser)
358 AddBuildArgs(build_parser)
359
360 clean_parser = subparsers.add_parser(
361 'clean',
362 help='remove all output directories')
363 AddCommonArgs(clean_parser)
364
365 deploy_parser = subparsers.add_parser(
366 'deploy',
367 help='build and download the code')
368 AddCommonArgs(deploy_parser)
369 AddBuildArgs(deploy_parser)
370 deploy_parser.add_argument(
371 '-n', '--dry-run',
372 help="don't actually download anything",
373 action='store_true')
374
Brian Silvermane48c09a2014-04-30 18:04:58 -0700375 tests_parser = subparsers.add_parser(
376 'tests',
377 help='run tests')
378 AddCommonArgs(tests_parser)
379 AddBuildArgs(tests_parser)
380
Brian Silvermana29ebf92014-04-23 13:08:49 -0500381 return parser.parse_args(args)
382
383 try:
384 parser = TryAgainArgumentParser()
385 args = SetUpParser(parser, sys.argv[1:])
386 except TryParsingAgain:
387 parser = argparse.ArgumentParser()
388 REQUIRED_ARGS_END = 5
389 args = SetUpParser(parser, sys.argv[1:REQUIRED_ARGS_END] + ['build'] +
390 sys.argv[(REQUIRED_ARGS_END):])
391
392 if args.processor == 'crio':
393 processor = CRIOProcessor()
394 elif args.processor == 'prime':
Brian Silvermanbe6cfe22014-04-27 08:06:27 -0500395 processor = PrimeProcessor(args.action_name == 'tests',
396 args.action_name == 'deploy')
Brian Silvermana29ebf92014-04-23 13:08:49 -0500397 else:
398 parser.exit(status=1, message='Unknown processor "%s".' % args.processor)
Brian Silvermanc2d8e5a2014-05-01 18:33:12 -0700399 processor.check_installed()
Brian Silvermana29ebf92014-04-23 13:08:49 -0500400
401 if 'target' in args:
402 targets = args.target[:]
403 else:
404 targets = []
405 unknown_platform_error = None
406 try:
407 platforms = processor.parse_platforms(args.platforms)
408 except Processor.UnknownPlatform as e:
409 unknown_platform_error = e.message
410 targets.append(args.platforms)
411 platforms = processor.parse_platforms(None)
412 if not platforms:
Brian Silvermana9b1e5c2014-04-30 18:08:04 -0700413 user_output("No platforms selected!")
Brian Silvermana29ebf92014-04-23 13:08:49 -0500414 exit(1)
415
416 def download_externals(argument):
417 subprocess.check_call(
Brian Silvermanbe6cfe22014-04-27 08:06:27 -0500418 (os.path.join(aos_path(), 'build', 'download_externals.sh'),
Brian Silvermana29ebf92014-04-23 13:08:49 -0500419 argument),
Brian Silvermanbe6cfe22014-04-27 08:06:27 -0500420 stdin=open(os.devnull, 'r'))
Brian Silvermana29ebf92014-04-23 13:08:49 -0500421
422 if processor.is_crio():
423 download_externals('crio')
424 else:
Brian Silvermanf0d3c782014-05-02 23:56:32 -0700425 to_download = set()
Brian Silvermana29ebf92014-04-23 13:08:49 -0500426 for architecture in PrimeProcessor.ARCHITECTURES:
Brian Silvermana5301e32014-05-03 10:51:49 -0700427 for sanitizer in PrimeProcessor.PIE_SANITIZERS:
Brian Silvermanf0d3c782014-05-02 23:56:32 -0700428 if platforms & processor.select_platforms(architecture=architecture,
429 sanitizer=sanitizer):
Brian Silvermana5301e32014-05-03 10:51:49 -0700430 to_download.add(architecture + '-fPIE')
Brian Silvermanf0d3c782014-05-02 23:56:32 -0700431 if platforms & processor.select_platforms(architecture=architecture,
432 sanitizer='none'):
433 to_download.add(architecture)
434 for download_target in to_download:
435 download_externals(download_target)
Brian Silvermana29ebf92014-04-23 13:08:49 -0500436
437 class ToolsConfig(object):
438 def __init__(self):
Brian Silvermanbe6cfe22014-04-27 08:06:27 -0500439 self.variables = {'AOS': aos_path()}
440 with open(os.path.join(aos_path(), 'build', 'tools_config'), 'r') as f:
Brian Silvermana29ebf92014-04-23 13:08:49 -0500441 for line in f:
442 if line[0] == '#':
443 pass
444 elif line.isspace():
445 pass
446 else:
447 new_name, new_value = line.rstrip().split('=')
448 for name, value in self.variables.items():
449 new_value = new_value.replace('${%s}' % name, value)
450 self.variables[new_name] = new_value
451 def __getitem__(self, key):
452 return self.variables[key]
453
454 tools_config = ToolsConfig()
455
456 def handle_clean_error(function, path, excinfo):
457 if issubclass(OSError, excinfo[0]):
458 if excinfo[1].errno == errno.ENOENT:
459 # Who cares if the file we're deleting isn't there?
460 return
461 raise excinfo[1]
462
Brian Silvermanc2d8e5a2014-05-01 18:33:12 -0700463 def need_to_run_gyp(platform):
Brian Silvermanf0d3c782014-05-02 23:56:32 -0700464 if not os.path.exists(platform.build_ninja()):
465 return True
Brian Silvermanc2d8e5a2014-05-01 18:33:12 -0700466 dirs = os.listdir(os.path.join(aos_path(), '..'))
Brian Silvermana4aff562014-05-02 17:43:50 -0700467 # Looking through these folders takes a long time and isn't useful.
Brian Silvermanc2d8e5a2014-05-01 18:33:12 -0700468 dirs.remove('output')
Brian Silvermana4aff562014-05-02 17:43:50 -0700469 dirs.remove('.git')
470 return not not subprocess.check_output(
Brian Silvermanc2d8e5a2014-05-01 18:33:12 -0700471 ('find',) + tuple(os.path.join(aos_path(), '..', d) for d in dirs)
472 + ('-newer', platform.build_ninja(),
473 '(', '-name', '*.gyp', '-or', '-name', '*.gypi', ')'),
Brian Silvermana4aff562014-05-02 17:43:50 -0700474 stdin=open(os.devnull, 'r'))
475
476 def env(platform):
477 build_env = dict(platform.build_env())
Brian Silvermand3fac732014-05-03 16:03:46 -0700478 if not 'TERM' in build_env:
479 build_env['TERM'] = os.environ['TERM']
480 if not 'PATH' in build_env:
481 build_env['PATH'] = os.environ['PATH']
Brian Silvermana4aff562014-05-02 17:43:50 -0700482 return build_env
Brian Silvermanc2d8e5a2014-05-01 18:33:12 -0700483
Brian Silverman47cd6f62014-05-03 10:35:52 -0700484 to_build = []
485 for platform in platforms:
486 to_build.append(str(platform))
487 if len(to_build) > 1:
488 to_build[-1] = 'and ' + to_build[-1]
489 user_output('Building %s...' % ', '.join(to_build))
490
491 if args.action_name == 'tests':
492 for sanitizer, warning in PrimeProcessor.SANITIZER_TEST_WARNINGS.items():
493 warned_about = platforms & processor.select_platforms(sanitizer=sanitizer)
494 if warned_about:
495 user_output(warning[1])
496 if warning[0]:
497 # TODO(brians): Add a --force flag or something?
498 user_output('Refusing to run tests for sanitizer %s.' % sanitizer)
499 exit(1)
500
Brian Silvermanc2d8e5a2014-05-01 18:33:12 -0700501 num = 1
Brian Silvermana29ebf92014-04-23 13:08:49 -0500502 for platform in platforms:
Brian Silvermanc2d8e5a2014-05-01 18:33:12 -0700503 user_output('Building %s (%d/%d)...' % (platform, num, len(platforms)))
Brian Silvermana29ebf92014-04-23 13:08:49 -0500504 if args.action_name == 'clean':
505 shutil.rmtree(platform.outdir(), onerror=handle_clean_error)
506 else:
507 if need_to_run_gyp(platform):
Brian Silvermana9b1e5c2014-04-30 18:08:04 -0700508 user_output('Running gyp...')
Brian Silvermana29ebf92014-04-23 13:08:49 -0500509 gyp = subprocess.Popen(
510 (tools_config['GYP'],
511 '--check',
Brian Silvermanbe6cfe22014-04-27 08:06:27 -0500512 '--depth=%s' % os.path.join(aos_path(), '..'),
Brian Silvermana29ebf92014-04-23 13:08:49 -0500513 '--no-circular-check',
514 '-f', 'ninja',
Brian Silvermanbe6cfe22014-04-27 08:06:27 -0500515 '-I%s' % os.path.join(aos_path(), 'build', 'aos.gypi'),
Brian Silvermana29ebf92014-04-23 13:08:49 -0500516 '-I/dev/stdin', '-Goutput_dir=output',
517 '-DOS=%s' % platform.os(),
518 '-DPLATFORM=%s' % platform.gyp_platform(),
519 '-DARCHITECTURE=%s' % platform.architecture,
Brian Silverman47cd6f62014-05-03 10:35:52 -0700520 '-DCOMPILER=%s' % platform.compiler.split('_')[0],
521 '-DFULL_COMPILER=%s' % platform.compiler,
Brian Silvermanf0d3c782014-05-02 23:56:32 -0700522 '-DDEBUG=%s' % ('yes' if platform.debug else 'no'),
523 '-DSANITIZER=%s' % platform.sanitizer,
Brian Silvermana5301e32014-05-03 10:51:49 -0700524 '-DSANITIZER_FPIE=%s' % ('-fPIE'
525 if platform.sanitizer in PrimeProcessor.PIE_SANITIZERS
Brian Silvermanf0d3c782014-05-02 23:56:32 -0700526 else '')) +
Brian Silvermanb3d50542014-04-23 14:28:55 -0500527 processor.extra_gyp_flags() + (args.main_gyp,),
Brian Silvermana29ebf92014-04-23 13:08:49 -0500528 stdin=subprocess.PIPE)
529 gyp.communicate(("""
530{
531 'target_defaults': {
532 'configurations': {
533 '%s': {}
534 }
535 }
536}""" % platform.outname()).encode())
537 if gyp.returncode:
Brian Silvermana9b1e5c2014-04-30 18:08:04 -0700538 user_output("Running gyp failed!")
Brian Silvermana29ebf92014-04-23 13:08:49 -0500539 exit(1)
Brian Silvermanb3d50542014-04-23 14:28:55 -0500540 if processor.is_crio():
541 subprocess.check_call(
542 ('sed', '-i',
543 's/nm -gD/nm/g', platform.build_ninja()),
Brian Silvermanbe6cfe22014-04-27 08:06:27 -0500544 stdin=open(os.devnull, 'r'))
Brian Silverman47cd6f62014-05-03 10:35:52 -0700545 user_output('Done running gyp')
Brian Silvermana29ebf92014-04-23 13:08:49 -0500546 else:
Brian Silverman47cd6f62014-05-03 10:35:52 -0700547 user_output("Not running gyp")
Brian Silvermana29ebf92014-04-23 13:08:49 -0500548
549 try:
550 subprocess.check_call(
551 (tools_config['NINJA'],
552 '-C', platform.outdir()) + tuple(targets),
Brian Silvermanbe6cfe22014-04-27 08:06:27 -0500553 stdin=open(os.devnull, 'r'),
Brian Silvermana4aff562014-05-02 17:43:50 -0700554 env=env(platform))
Brian Silvermana29ebf92014-04-23 13:08:49 -0500555 except subprocess.CalledProcessError as e:
556 if unknown_platform_error is not None:
Brian Silvermana9b1e5c2014-04-30 18:08:04 -0700557 user_output(unknown_platform_error)
Brian Silvermana29ebf92014-04-23 13:08:49 -0500558 raise e
559
Brian Silvermanbe6cfe22014-04-27 08:06:27 -0500560 if args.action_name == 'deploy':
561 platform.deploy(args.dry_run)
Brian Silvermane48c09a2014-04-30 18:04:58 -0700562 elif args.action_name == 'tests':
563 dirname = os.path.join(platform.outdir(), 'tests')
564 for f in targets or os.listdir(dirname):
Brian Silvermana9b1e5c2014-04-30 18:08:04 -0700565 user_output('Running test %s...' % f)
Brian Silvermana4aff562014-05-02 17:43:50 -0700566 subprocess.check_call(
567 os.path.join(dirname, f),
568 env=env(platform))
Brian Silvermana9b1e5c2014-04-30 18:08:04 -0700569 user_output('Test %s succeeded' % f)
Brian Silvermanbe6cfe22014-04-27 08:06:27 -0500570
Brian Silvermanc2d8e5a2014-05-01 18:33:12 -0700571 user_output('Done building %s (%d/%d)' % (platform, num, len(platforms)))
572 num += 1
Brian Silvermana29ebf92014-04-23 13:08:49 -0500573
574if __name__ == '__main__':
575 main()