blob: 41e4e4c5350e8159748ea27be84111055fa5c6cc [file] [log] [blame]
Simon Glassfc3fe1c2013-04-03 11:07:16 +00001# Copyright (c) 2012 The Chromium OS Authors.
2#
Wolfgang Denk1a459662013-07-08 09:37:19 +02003# SPDX-License-Identifier: GPL-2.0+
Simon Glassfc3fe1c2013-04-03 11:07:16 +00004#
5
Simon Glass4281ad82013-09-23 17:35:17 -06006import re
Simon Glassfc3fe1c2013-04-03 11:07:16 +00007import glob
Simon Glass827e37b2014-12-01 17:34:06 -07008from HTMLParser import HTMLParser
Simon Glassfc3fe1c2013-04-03 11:07:16 +00009import os
Simon Glass827e37b2014-12-01 17:34:06 -070010import sys
11import tempfile
12import urllib2
Simon Glassfc3fe1c2013-04-03 11:07:16 +000013
14import bsettings
15import command
Simon Glass713bea32016-07-27 20:33:02 -060016import terminal
Simon Glassfc3fe1c2013-04-03 11:07:16 +000017
Simon Glass17bce662016-03-12 18:50:32 -070018(PRIORITY_FULL_PREFIX, PRIORITY_PREFIX_GCC, PRIORITY_PREFIX_GCC_PATH,
19 PRIORITY_CALC) = range(4)
Simon Glassff690df2016-03-06 19:45:37 -070020
Simon Glass827e37b2014-12-01 17:34:06 -070021# Simple class to collect links from a page
22class MyHTMLParser(HTMLParser):
23 def __init__(self, arch):
24 """Create a new parser
25
26 After the parser runs, self.links will be set to a list of the links
27 to .xz archives found in the page, and self.arch_link will be set to
28 the one for the given architecture (or None if not found).
29
30 Args:
31 arch: Architecture to search for
32 """
33 HTMLParser.__init__(self)
34 self.arch_link = None
35 self.links = []
36 self._match = '_%s-' % arch
37
38 def handle_starttag(self, tag, attrs):
39 if tag == 'a':
40 for tag, value in attrs:
41 if tag == 'href':
42 if value and value.endswith('.xz'):
43 self.links.append(value)
44 if self._match in value:
45 self.arch_link = value
46
47
Simon Glassfc3fe1c2013-04-03 11:07:16 +000048class Toolchain:
49 """A single toolchain
50
51 Public members:
52 gcc: Full path to C compiler
53 path: Directory path containing C compiler
54 cross: Cross compile string, e.g. 'arm-linux-'
55 arch: Architecture of toolchain as determined from the first
56 component of the filename. E.g. arm-linux-gcc becomes arm
Simon Glassff690df2016-03-06 19:45:37 -070057 priority: Toolchain priority (0=highest, 20=lowest)
Simon Glassfc3fe1c2013-04-03 11:07:16 +000058 """
Simon Glass608e3992016-03-06 19:45:38 -070059 def __init__(self, fname, test, verbose=False, priority=PRIORITY_CALC,
60 arch=None):
Simon Glassfc3fe1c2013-04-03 11:07:16 +000061 """Create a new toolchain object.
62
63 Args:
64 fname: Filename of the gcc component
65 test: True to run the toolchain to test it
Simon Glassad24eba2016-03-06 19:45:35 -070066 verbose: True to print out the information
Simon Glassff690df2016-03-06 19:45:37 -070067 priority: Priority to use for this toolchain, or PRIORITY_CALC to
68 calculate it
Simon Glassfc3fe1c2013-04-03 11:07:16 +000069 """
70 self.gcc = fname
71 self.path = os.path.dirname(fname)
Simon Glassb5324122014-12-01 17:33:58 -070072
73 # Find the CROSS_COMPILE prefix to use for U-Boot. For example,
74 # 'arm-linux-gnueabihf-gcc' turns into 'arm-linux-gnueabihf-'.
75 basename = os.path.basename(fname)
76 pos = basename.rfind('-')
77 self.cross = basename[:pos + 1] if pos != -1 else ''
78
79 # The architecture is the first part of the name
Simon Glassfc3fe1c2013-04-03 11:07:16 +000080 pos = self.cross.find('-')
Simon Glass608e3992016-03-06 19:45:38 -070081 if arch:
82 self.arch = arch
83 else:
84 self.arch = self.cross[:pos] if pos != -1 else 'sandbox'
Simon Glassfc3fe1c2013-04-03 11:07:16 +000085
Simon Glassbb1501f2014-12-01 17:34:00 -070086 env = self.MakeEnvironment(False)
Simon Glassfc3fe1c2013-04-03 11:07:16 +000087
88 # As a basic sanity check, run the C compiler with --version
89 cmd = [fname, '--version']
Simon Glassff690df2016-03-06 19:45:37 -070090 if priority == PRIORITY_CALC:
91 self.priority = self.GetPriority(fname)
92 else:
93 self.priority = priority
Simon Glassfc3fe1c2013-04-03 11:07:16 +000094 if test:
Stephen Warren8bb2bdd2013-10-09 14:28:09 -060095 result = command.RunPipe([cmd], capture=True, env=env,
96 raise_on_error=False)
Simon Glassfc3fe1c2013-04-03 11:07:16 +000097 self.ok = result.return_code == 0
98 if verbose:
99 print 'Tool chain test: ',
100 if self.ok:
Simon Glass608e3992016-03-06 19:45:38 -0700101 print "OK, arch='%s', priority %d" % (self.arch,
102 self.priority)
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000103 else:
104 print 'BAD'
105 print 'Command: ', cmd
106 print result.stdout
107 print result.stderr
108 else:
109 self.ok = True
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000110
111 def GetPriority(self, fname):
112 """Return the priority of the toolchain.
113
114 Toolchains are ranked according to their suitability by their
115 filename prefix.
116
117 Args:
118 fname: Filename of toolchain
119 Returns:
Simon Glassff690df2016-03-06 19:45:37 -0700120 Priority of toolchain, PRIORITY_CALC=highest, 20=lowest.
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000121 """
Masahiro Yamada87082672014-07-07 09:47:45 +0900122 priority_list = ['-elf', '-unknown-linux-gnu', '-linux',
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000123 '-none-linux-gnueabi', '-uclinux', '-none-eabi',
124 '-gentoo-linux-gnu', '-linux-gnueabi', '-le-linux', '-uclinux']
125 for prio in range(len(priority_list)):
126 if priority_list[prio] in fname:
Simon Glassff690df2016-03-06 19:45:37 -0700127 return PRIORITY_CALC + prio
128 return PRIORITY_CALC + prio
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000129
Simon Glassbb1501f2014-12-01 17:34:00 -0700130 def MakeEnvironment(self, full_path):
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000131 """Returns an environment for using the toolchain.
132
Simon Glassbb1501f2014-12-01 17:34:00 -0700133 Thie takes the current environment and adds CROSS_COMPILE so that
134 the tool chain will operate correctly.
135
136 Args:
137 full_path: Return the full path in CROSS_COMPILE and don't set
138 PATH
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000139 """
140 env = dict(os.environ)
Simon Glassbb1501f2014-12-01 17:34:00 -0700141 if full_path:
142 env['CROSS_COMPILE'] = os.path.join(self.path, self.cross)
143 else:
144 env['CROSS_COMPILE'] = self.cross
145 env['PATH'] = self.path + ':' + env['PATH']
146
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000147 return env
148
149
150class Toolchains:
151 """Manage a list of toolchains for building U-Boot
152
153 We select one toolchain for each architecture type
154
155 Public members:
156 toolchains: Dict of Toolchain objects, keyed by architecture name
Simon Glass17bce662016-03-12 18:50:32 -0700157 prefixes: Dict of prefixes to check, keyed by architecture. This can
158 be a full path and toolchain prefix, for example
159 {'x86', 'opt/i386-linux/bin/i386-linux-'}, or the name of
160 something on the search path, for example
161 {'arm', 'arm-linux-gnueabihf-'}. Wildcards are not supported.
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000162 paths: List of paths to check for toolchains (may contain wildcards)
163 """
164
165 def __init__(self):
166 self.toolchains = {}
Simon Glass17bce662016-03-12 18:50:32 -0700167 self.prefixes = {}
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000168 self.paths = []
Simon Glassd4144e42014-09-05 19:00:13 -0600169 self._make_flags = dict(bsettings.GetItems('make-flags'))
170
Simon Glass80e6a482016-07-27 20:33:01 -0600171 def GetPathList(self, show_warning=True):
Simon Glass827e37b2014-12-01 17:34:06 -0700172 """Get a list of available toolchain paths
173
Simon Glass80e6a482016-07-27 20:33:01 -0600174 Args:
175 show_warning: True to show a warning if there are no tool chains.
176
Simon Glass827e37b2014-12-01 17:34:06 -0700177 Returns:
178 List of strings, each a path to a toolchain mentioned in the
179 [toolchain] section of the settings file.
180 """
Simon Glass4281ad82013-09-23 17:35:17 -0600181 toolchains = bsettings.GetItems('toolchain')
Simon Glass80e6a482016-07-27 20:33:01 -0600182 if show_warning and not toolchains:
Simon Glass713bea32016-07-27 20:33:02 -0600183 print ("Warning: No tool chains. Please run 'buildman "
184 "--fetch-arch all' to download all available toolchains, or "
185 "add a [toolchain] section to your buildman config file "
186 "%s. See README for details" %
187 bsettings.config_fname)
Simon Glass4281ad82013-09-23 17:35:17 -0600188
Simon Glass827e37b2014-12-01 17:34:06 -0700189 paths = []
Simon Glass4281ad82013-09-23 17:35:17 -0600190 for name, value in toolchains:
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000191 if '*' in value:
Simon Glass827e37b2014-12-01 17:34:06 -0700192 paths += glob.glob(value)
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000193 else:
Simon Glass827e37b2014-12-01 17:34:06 -0700194 paths.append(value)
195 return paths
196
Simon Glass80e6a482016-07-27 20:33:01 -0600197 def GetSettings(self, show_warning=True):
198 """Get toolchain settings from the settings file.
199
200 Args:
201 show_warning: True to show a warning if there are no tool chains.
202 """
203 self.prefixes = bsettings.GetItems('toolchain-prefix')
204 self.paths += self.GetPathList(show_warning)
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000205
Simon Glass608e3992016-03-06 19:45:38 -0700206 def Add(self, fname, test=True, verbose=False, priority=PRIORITY_CALC,
207 arch=None):
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000208 """Add a toolchain to our list
209
210 We select the given toolchain as our preferred one for its
211 architecture if it is a higher priority than the others.
212
213 Args:
214 fname: Filename of toolchain's gcc driver
215 test: True to run the toolchain to test it
Simon Glassff690df2016-03-06 19:45:37 -0700216 priority: Priority to use for this toolchain
Simon Glass608e3992016-03-06 19:45:38 -0700217 arch: Toolchain architecture, or None if not known
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000218 """
Simon Glass608e3992016-03-06 19:45:38 -0700219 toolchain = Toolchain(fname, test, verbose, priority, arch)
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000220 add_it = toolchain.ok
221 if toolchain.arch in self.toolchains:
222 add_it = (toolchain.priority <
223 self.toolchains[toolchain.arch].priority)
224 if add_it:
225 self.toolchains[toolchain.arch] = toolchain
Simon Glassff690df2016-03-06 19:45:37 -0700226 elif verbose:
227 print ("Toolchain '%s' at priority %d will be ignored because "
228 "another toolchain for arch '%s' has priority %d" %
229 (toolchain.gcc, toolchain.priority, toolchain.arch,
230 self.toolchains[toolchain.arch].priority))
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000231
Simon Glass827e37b2014-12-01 17:34:06 -0700232 def ScanPath(self, path, verbose):
233 """Scan a path for a valid toolchain
234
235 Args:
236 path: Path to scan
237 verbose: True to print out progress information
238 Returns:
239 Filename of C compiler if found, else None
240 """
Albert ARIBAUDd9088982015-02-01 00:12:44 +0100241 fnames = []
Simon Glass827e37b2014-12-01 17:34:06 -0700242 for subdir in ['.', 'bin', 'usr/bin']:
243 dirname = os.path.join(path, subdir)
244 if verbose: print " - looking in '%s'" % dirname
245 for fname in glob.glob(dirname + '/*gcc'):
246 if verbose: print " - found '%s'" % fname
Albert ARIBAUDd9088982015-02-01 00:12:44 +0100247 fnames.append(fname)
248 return fnames
Simon Glass827e37b2014-12-01 17:34:06 -0700249
Simon Glass17bce662016-03-12 18:50:32 -0700250 def ScanPathEnv(self, fname):
251 """Scan the PATH environment variable for a given filename.
252
253 Args:
254 fname: Filename to scan for
255 Returns:
256 List of matching pathanames, or [] if none
257 """
258 pathname_list = []
259 for path in os.environ["PATH"].split(os.pathsep):
260 path = path.strip('"')
261 pathname = os.path.join(path, fname)
262 if os.path.exists(pathname):
263 pathname_list.append(pathname)
264 return pathname_list
Simon Glass827e37b2014-12-01 17:34:06 -0700265
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000266 def Scan(self, verbose):
267 """Scan for available toolchains and select the best for each arch.
268
269 We look for all the toolchains we can file, figure out the
270 architecture for each, and whether it works. Then we select the
271 highest priority toolchain for each arch.
272
273 Args:
274 verbose: True to print out progress information
275 """
276 if verbose: print 'Scanning for tool chains'
Simon Glass17bce662016-03-12 18:50:32 -0700277 for name, value in self.prefixes:
278 if verbose: print " - scanning prefix '%s'" % value
279 if os.path.exists(value):
280 self.Add(value, True, verbose, PRIORITY_FULL_PREFIX, name)
281 continue
282 fname = value + 'gcc'
283 if os.path.exists(fname):
284 self.Add(fname, True, verbose, PRIORITY_PREFIX_GCC, name)
285 continue
286 fname_list = self.ScanPathEnv(fname)
287 for f in fname_list:
288 self.Add(f, True, verbose, PRIORITY_PREFIX_GCC_PATH, name)
289 if not fname_list:
290 raise ValueError, ("No tool chain found for prefix '%s'" %
291 value)
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000292 for path in self.paths:
293 if verbose: print " - scanning path '%s'" % path
Albert ARIBAUDd9088982015-02-01 00:12:44 +0100294 fnames = self.ScanPath(path, verbose)
295 for fname in fnames:
Simon Glass827e37b2014-12-01 17:34:06 -0700296 self.Add(fname, True, verbose)
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000297
298 def List(self):
299 """List out the selected toolchains for each architecture"""
Simon Glass713bea32016-07-27 20:33:02 -0600300 col = terminal.Color()
301 print col.Color(col.BLUE, 'List of available toolchains (%d):' %
302 len(self.toolchains))
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000303 if len(self.toolchains):
304 for key, value in sorted(self.toolchains.iteritems()):
305 print '%-10s: %s' % (key, value.gcc)
306 else:
307 print 'None'
308
309 def Select(self, arch):
310 """Returns the toolchain for a given architecture
311
312 Args:
313 args: Name of architecture (e.g. 'arm', 'ppc_8xx')
314
315 returns:
316 toolchain object, or None if none found
317 """
Simon Glass9b83bfd2014-12-01 17:34:05 -0700318 for tag, value in bsettings.GetItems('toolchain-alias'):
319 if arch == tag:
320 for alias in value.split():
321 if alias in self.toolchains:
322 return self.toolchains[alias]
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000323
324 if not arch in self.toolchains:
325 raise ValueError, ("No tool chain found for arch '%s'" % arch)
326 return self.toolchains[arch]
Simon Glass4281ad82013-09-23 17:35:17 -0600327
328 def ResolveReferences(self, var_dict, args):
329 """Resolve variable references in a string
330
331 This converts ${blah} within the string to the value of blah.
332 This function works recursively.
333
334 Args:
335 var_dict: Dictionary containing variables and their values
336 args: String containing make arguments
337 Returns:
338 Resolved string
339
340 >>> bsettings.Setup()
341 >>> tcs = Toolchains()
342 >>> tcs.Add('fred', False)
343 >>> var_dict = {'oblique' : 'OBLIQUE', 'first' : 'fi${second}rst', \
344 'second' : '2nd'}
345 >>> tcs.ResolveReferences(var_dict, 'this=${oblique}_set')
346 'this=OBLIQUE_set'
347 >>> tcs.ResolveReferences(var_dict, 'this=${oblique}_set${first}nd')
348 'this=OBLIQUE_setfi2ndrstnd'
349 """
Simon Glassf60c9d42014-08-28 09:43:40 -0600350 re_var = re.compile('(\$\{[-_a-z0-9A-Z]{1,}\})')
Simon Glass4281ad82013-09-23 17:35:17 -0600351
352 while True:
353 m = re_var.search(args)
354 if not m:
355 break
356 lookup = m.group(0)[2:-1]
357 value = var_dict.get(lookup, '')
358 args = args[:m.start(0)] + value + args[m.end(0):]
359 return args
360
361 def GetMakeArguments(self, board):
362 """Returns 'make' arguments for a given board
363
364 The flags are in a section called 'make-flags'. Flags are named
365 after the target they represent, for example snapper9260=TESTING=1
366 will pass TESTING=1 to make when building the snapper9260 board.
367
368 References to other boards can be added in the string also. For
369 example:
370
371 [make-flags]
372 at91-boards=ENABLE_AT91_TEST=1
373 snapper9260=${at91-boards} BUILD_TAG=442
374 snapper9g45=${at91-boards} BUILD_TAG=443
375
376 This will return 'ENABLE_AT91_TEST=1 BUILD_TAG=442' for snapper9260
377 and 'ENABLE_AT91_TEST=1 BUILD_TAG=443' for snapper9g45.
378
379 A special 'target' variable is set to the board target.
380
381 Args:
382 board: Board object for the board to check.
383 Returns:
384 'make' flags for that board, or '' if none
385 """
386 self._make_flags['target'] = board.target
387 arg_str = self.ResolveReferences(self._make_flags,
388 self._make_flags.get(board.target, ''))
389 args = arg_str.split(' ')
390 i = 0
391 while i < len(args):
392 if not args[i]:
393 del args[i]
394 else:
395 i += 1
396 return args
Simon Glass827e37b2014-12-01 17:34:06 -0700397
398 def LocateArchUrl(self, fetch_arch):
399 """Find a toolchain available online
400
401 Look in standard places for available toolchains. At present the
402 only standard place is at kernel.org.
403
404 Args:
405 arch: Architecture to look for, or 'list' for all
406 Returns:
407 If fetch_arch is 'list', a tuple:
408 Machine architecture (e.g. x86_64)
409 List of toolchains
410 else
411 URL containing this toolchain, if avaialble, else None
412 """
413 arch = command.OutputOneLine('uname', '-m')
414 base = 'https://www.kernel.org/pub/tools/crosstool/files/bin'
Michal Simek12462312015-04-20 11:46:24 +0200415 versions = ['4.9.0', '4.6.3', '4.6.2', '4.5.1', '4.2.4']
Simon Glass827e37b2014-12-01 17:34:06 -0700416 links = []
417 for version in versions:
418 url = '%s/%s/%s/' % (base, arch, version)
419 print 'Checking: %s' % url
420 response = urllib2.urlopen(url)
421 html = response.read()
422 parser = MyHTMLParser(fetch_arch)
423 parser.feed(html)
424 if fetch_arch == 'list':
425 links += parser.links
426 elif parser.arch_link:
427 return url + parser.arch_link
428 if fetch_arch == 'list':
429 return arch, links
430 return None
431
432 def Download(self, url):
433 """Download a file to a temporary directory
434
435 Args:
436 url: URL to download
437 Returns:
438 Tuple:
439 Temporary directory name
440 Full path to the downloaded archive file in that directory,
441 or None if there was an error while downloading
442 """
Simon Glassad24eba2016-03-06 19:45:35 -0700443 print 'Downloading: %s' % url
Simon Glass827e37b2014-12-01 17:34:06 -0700444 leaf = url.split('/')[-1]
445 tmpdir = tempfile.mkdtemp('.buildman')
446 response = urllib2.urlopen(url)
447 fname = os.path.join(tmpdir, leaf)
448 fd = open(fname, 'wb')
449 meta = response.info()
Simon Glassad24eba2016-03-06 19:45:35 -0700450 size = int(meta.getheaders('Content-Length')[0])
Simon Glass827e37b2014-12-01 17:34:06 -0700451 done = 0
452 block_size = 1 << 16
453 status = ''
454
455 # Read the file in chunks and show progress as we go
456 while True:
457 buffer = response.read(block_size)
458 if not buffer:
459 print chr(8) * (len(status) + 1), '\r',
460 break
461
462 done += len(buffer)
463 fd.write(buffer)
Simon Glassad24eba2016-03-06 19:45:35 -0700464 status = r'%10d MiB [%3d%%]' % (done / 1024 / 1024,
Simon Glass827e37b2014-12-01 17:34:06 -0700465 done * 100 / size)
466 status = status + chr(8) * (len(status) + 1)
467 print status,
468 sys.stdout.flush()
469 fd.close()
470 if done != size:
471 print 'Error, failed to download'
472 os.remove(fname)
473 fname = None
474 return tmpdir, fname
475
476 def Unpack(self, fname, dest):
477 """Unpack a tar file
478
479 Args:
480 fname: Filename to unpack
481 dest: Destination directory
482 Returns:
483 Directory name of the first entry in the archive, without the
484 trailing /
485 """
486 stdout = command.Output('tar', 'xvfJ', fname, '-C', dest)
487 return stdout.splitlines()[0][:-1]
488
489 def TestSettingsHasPath(self, path):
Simon Glass2289b272016-07-27 20:33:03 -0600490 """Check if buildman will find this toolchain
Simon Glass827e37b2014-12-01 17:34:06 -0700491
492 Returns:
493 True if the path is in settings, False if not
494 """
Simon Glass80e6a482016-07-27 20:33:01 -0600495 paths = self.GetPathList(False)
Simon Glass827e37b2014-12-01 17:34:06 -0700496 return path in paths
497
498 def ListArchs(self):
499 """List architectures with available toolchains to download"""
500 host_arch, archives = self.LocateArchUrl('list')
501 re_arch = re.compile('[-a-z0-9.]*_([^-]*)-.*')
502 arch_set = set()
503 for archive in archives:
504 # Remove the host architecture from the start
505 arch = re_arch.match(archive[len(host_arch):])
506 if arch:
507 arch_set.add(arch.group(1))
508 return sorted(arch_set)
509
510 def FetchAndInstall(self, arch):
511 """Fetch and install a new toolchain
512
513 arch:
514 Architecture to fetch, or 'list' to list
515 """
516 # Fist get the URL for this architecture
Simon Glass713bea32016-07-27 20:33:02 -0600517 col = terminal.Color()
518 print col.Color(col.BLUE, "Downloading toolchain for arch '%s'" % arch)
Simon Glass827e37b2014-12-01 17:34:06 -0700519 url = self.LocateArchUrl(arch)
520 if not url:
521 print ("Cannot find toolchain for arch '%s' - use 'list' to list" %
522 arch)
523 return 2
524 home = os.environ['HOME']
525 dest = os.path.join(home, '.buildman-toolchains')
526 if not os.path.exists(dest):
527 os.mkdir(dest)
528
529 # Download the tar file for this toolchain and unpack it
530 tmpdir, tarfile = self.Download(url)
531 if not tarfile:
532 return 1
Simon Glass713bea32016-07-27 20:33:02 -0600533 print col.Color(col.GREEN, 'Unpacking to: %s' % dest),
Simon Glass827e37b2014-12-01 17:34:06 -0700534 sys.stdout.flush()
535 path = self.Unpack(tarfile, dest)
536 os.remove(tarfile)
537 os.rmdir(tmpdir)
538 print
539
540 # Check that the toolchain works
Simon Glass713bea32016-07-27 20:33:02 -0600541 print col.Color(col.GREEN, 'Testing')
Simon Glass827e37b2014-12-01 17:34:06 -0700542 dirpath = os.path.join(dest, path)
Simon Glass2a76a642015-03-02 17:05:15 -0700543 compiler_fname_list = self.ScanPath(dirpath, True)
544 if not compiler_fname_list:
Simon Glass827e37b2014-12-01 17:34:06 -0700545 print 'Could not locate C compiler - fetch failed.'
546 return 1
Simon Glass2a76a642015-03-02 17:05:15 -0700547 if len(compiler_fname_list) != 1:
Simon Glass713bea32016-07-27 20:33:02 -0600548 print col.Color(col.RED, 'Warning, ambiguous toolchains: %s' %
549 ', '.join(compiler_fname_list))
Simon Glass2a76a642015-03-02 17:05:15 -0700550 toolchain = Toolchain(compiler_fname_list[0], True, True)
Simon Glass827e37b2014-12-01 17:34:06 -0700551
552 # Make sure that it will be found by buildman
553 if not self.TestSettingsHasPath(dirpath):
554 print ("Adding 'download' to config file '%s'" %
555 bsettings.config_fname)
Simon Glassc8785c52016-07-27 20:33:05 -0600556 bsettings.SetItem('toolchain', 'download', '%s/*/*' % dest)
Simon Glass827e37b2014-12-01 17:34:06 -0700557 return 0