blob: 1e1ce42e8fe5f91d6838688435e67a6fc0e3f3c8 [file] [log] [blame]
Simon Glassc05694f2013-04-03 11:07:16 +00001# Copyright (c) 2012 The Chromium OS Authors.
2#
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02003# SPDX-License-Identifier: GPL-2.0+
Simon Glassc05694f2013-04-03 11:07:16 +00004#
5
Simon Glasscc246fb2013-09-23 17:35:17 -06006import re
Simon Glassc05694f2013-04-03 11:07:16 +00007import glob
Simon Glass7e803e12014-12-01 17:34:06 -07008from HTMLParser import HTMLParser
Simon Glassc05694f2013-04-03 11:07:16 +00009import os
Simon Glass7e803e12014-12-01 17:34:06 -070010import sys
11import tempfile
12import urllib2
Simon Glassc05694f2013-04-03 11:07:16 +000013
14import bsettings
15import command
16
Simon Glassf5902732016-03-12 18:50:32 -070017(PRIORITY_FULL_PREFIX, PRIORITY_PREFIX_GCC, PRIORITY_PREFIX_GCC_PATH,
18 PRIORITY_CALC) = range(4)
Simon Glass7b971292016-03-06 19:45:37 -070019
Simon Glass7e803e12014-12-01 17:34:06 -070020# Simple class to collect links from a page
21class MyHTMLParser(HTMLParser):
22 def __init__(self, arch):
23 """Create a new parser
24
25 After the parser runs, self.links will be set to a list of the links
26 to .xz archives found in the page, and self.arch_link will be set to
27 the one for the given architecture (or None if not found).
28
29 Args:
30 arch: Architecture to search for
31 """
32 HTMLParser.__init__(self)
33 self.arch_link = None
34 self.links = []
35 self._match = '_%s-' % arch
36
37 def handle_starttag(self, tag, attrs):
38 if tag == 'a':
39 for tag, value in attrs:
40 if tag == 'href':
41 if value and value.endswith('.xz'):
42 self.links.append(value)
43 if self._match in value:
44 self.arch_link = value
45
46
Simon Glassc05694f2013-04-03 11:07:16 +000047class Toolchain:
48 """A single toolchain
49
50 Public members:
51 gcc: Full path to C compiler
52 path: Directory path containing C compiler
53 cross: Cross compile string, e.g. 'arm-linux-'
54 arch: Architecture of toolchain as determined from the first
55 component of the filename. E.g. arm-linux-gcc becomes arm
Simon Glass7b971292016-03-06 19:45:37 -070056 priority: Toolchain priority (0=highest, 20=lowest)
Simon Glassc05694f2013-04-03 11:07:16 +000057 """
Simon Glassc6cdd3e2016-03-06 19:45:38 -070058 def __init__(self, fname, test, verbose=False, priority=PRIORITY_CALC,
59 arch=None):
Simon Glassc05694f2013-04-03 11:07:16 +000060 """Create a new toolchain object.
61
62 Args:
63 fname: Filename of the gcc component
64 test: True to run the toolchain to test it
Simon Glassd6ece322016-03-06 19:45:35 -070065 verbose: True to print out the information
Simon Glass7b971292016-03-06 19:45:37 -070066 priority: Priority to use for this toolchain, or PRIORITY_CALC to
67 calculate it
Simon Glassc05694f2013-04-03 11:07:16 +000068 """
69 self.gcc = fname
70 self.path = os.path.dirname(fname)
Simon Glass28ed0062014-12-01 17:33:58 -070071
72 # Find the CROSS_COMPILE prefix to use for U-Boot. For example,
73 # 'arm-linux-gnueabihf-gcc' turns into 'arm-linux-gnueabihf-'.
74 basename = os.path.basename(fname)
75 pos = basename.rfind('-')
76 self.cross = basename[:pos + 1] if pos != -1 else ''
77
78 # The architecture is the first part of the name
Simon Glassc05694f2013-04-03 11:07:16 +000079 pos = self.cross.find('-')
Simon Glassc6cdd3e2016-03-06 19:45:38 -070080 if arch:
81 self.arch = arch
82 else:
83 self.arch = self.cross[:pos] if pos != -1 else 'sandbox'
Simon Glassc05694f2013-04-03 11:07:16 +000084
Simon Glassd48a46c2014-12-01 17:34:00 -070085 env = self.MakeEnvironment(False)
Simon Glassc05694f2013-04-03 11:07:16 +000086
87 # As a basic sanity check, run the C compiler with --version
88 cmd = [fname, '--version']
Simon Glass7b971292016-03-06 19:45:37 -070089 if priority == PRIORITY_CALC:
90 self.priority = self.GetPriority(fname)
91 else:
92 self.priority = priority
Simon Glassc05694f2013-04-03 11:07:16 +000093 if test:
Stephen Warren288d7672013-10-09 14:28:09 -060094 result = command.RunPipe([cmd], capture=True, env=env,
95 raise_on_error=False)
Simon Glassc05694f2013-04-03 11:07:16 +000096 self.ok = result.return_code == 0
97 if verbose:
98 print 'Tool chain test: ',
99 if self.ok:
Simon Glassc6cdd3e2016-03-06 19:45:38 -0700100 print "OK, arch='%s', priority %d" % (self.arch,
101 self.priority)
Simon Glassc05694f2013-04-03 11:07:16 +0000102 else:
103 print 'BAD'
104 print 'Command: ', cmd
105 print result.stdout
106 print result.stderr
107 else:
108 self.ok = True
Simon Glassc05694f2013-04-03 11:07:16 +0000109
110 def GetPriority(self, fname):
111 """Return the priority of the toolchain.
112
113 Toolchains are ranked according to their suitability by their
114 filename prefix.
115
116 Args:
117 fname: Filename of toolchain
118 Returns:
Simon Glass7b971292016-03-06 19:45:37 -0700119 Priority of toolchain, PRIORITY_CALC=highest, 20=lowest.
Simon Glassc05694f2013-04-03 11:07:16 +0000120 """
Masahiro Yamadafa25e1f2014-07-07 09:47:45 +0900121 priority_list = ['-elf', '-unknown-linux-gnu', '-linux',
Simon Glassc05694f2013-04-03 11:07:16 +0000122 '-none-linux-gnueabi', '-uclinux', '-none-eabi',
123 '-gentoo-linux-gnu', '-linux-gnueabi', '-le-linux', '-uclinux']
124 for prio in range(len(priority_list)):
125 if priority_list[prio] in fname:
Simon Glass7b971292016-03-06 19:45:37 -0700126 return PRIORITY_CALC + prio
127 return PRIORITY_CALC + prio
Simon Glassc05694f2013-04-03 11:07:16 +0000128
Simon Glassd48a46c2014-12-01 17:34:00 -0700129 def MakeEnvironment(self, full_path):
Simon Glassc05694f2013-04-03 11:07:16 +0000130 """Returns an environment for using the toolchain.
131
Simon Glassd48a46c2014-12-01 17:34:00 -0700132 Thie takes the current environment and adds CROSS_COMPILE so that
133 the tool chain will operate correctly.
134
135 Args:
136 full_path: Return the full path in CROSS_COMPILE and don't set
137 PATH
Simon Glassc05694f2013-04-03 11:07:16 +0000138 """
139 env = dict(os.environ)
Simon Glassd48a46c2014-12-01 17:34:00 -0700140 if full_path:
141 env['CROSS_COMPILE'] = os.path.join(self.path, self.cross)
142 else:
143 env['CROSS_COMPILE'] = self.cross
144 env['PATH'] = self.path + ':' + env['PATH']
145
Simon Glassc05694f2013-04-03 11:07:16 +0000146 return env
147
148
149class Toolchains:
150 """Manage a list of toolchains for building U-Boot
151
152 We select one toolchain for each architecture type
153
154 Public members:
155 toolchains: Dict of Toolchain objects, keyed by architecture name
Simon Glassf5902732016-03-12 18:50:32 -0700156 prefixes: Dict of prefixes to check, keyed by architecture. This can
157 be a full path and toolchain prefix, for example
158 {'x86', 'opt/i386-linux/bin/i386-linux-'}, or the name of
159 something on the search path, for example
160 {'arm', 'arm-linux-gnueabihf-'}. Wildcards are not supported.
Simon Glassc05694f2013-04-03 11:07:16 +0000161 paths: List of paths to check for toolchains (may contain wildcards)
162 """
163
164 def __init__(self):
165 self.toolchains = {}
Simon Glassf5902732016-03-12 18:50:32 -0700166 self.prefixes = {}
Simon Glassc05694f2013-04-03 11:07:16 +0000167 self.paths = []
Simon Glassed098bb2014-09-05 19:00:13 -0600168 self._make_flags = dict(bsettings.GetItems('make-flags'))
169
Simon Glassf38a6422016-07-27 20:33:01 -0600170 def GetPathList(self, show_warning=True):
Simon Glass7e803e12014-12-01 17:34:06 -0700171 """Get a list of available toolchain paths
172
Simon Glassf38a6422016-07-27 20:33:01 -0600173 Args:
174 show_warning: True to show a warning if there are no tool chains.
175
Simon Glass7e803e12014-12-01 17:34:06 -0700176 Returns:
177 List of strings, each a path to a toolchain mentioned in the
178 [toolchain] section of the settings file.
179 """
Simon Glasscc246fb2013-09-23 17:35:17 -0600180 toolchains = bsettings.GetItems('toolchain')
Simon Glassf38a6422016-07-27 20:33:01 -0600181 if show_warning and not toolchains:
Simon Glassd6ece322016-03-06 19:45:35 -0700182 print ('Warning: No tool chains - please add a [toolchain] section'
183 ' to your buildman config file %s. See README for details' %
Masahiro Yamada73c12672014-07-07 09:46:36 +0900184 bsettings.config_fname)
Simon Glasscc246fb2013-09-23 17:35:17 -0600185
Simon Glass7e803e12014-12-01 17:34:06 -0700186 paths = []
Simon Glasscc246fb2013-09-23 17:35:17 -0600187 for name, value in toolchains:
Simon Glassc05694f2013-04-03 11:07:16 +0000188 if '*' in value:
Simon Glass7e803e12014-12-01 17:34:06 -0700189 paths += glob.glob(value)
Simon Glassc05694f2013-04-03 11:07:16 +0000190 else:
Simon Glass7e803e12014-12-01 17:34:06 -0700191 paths.append(value)
192 return paths
193
Simon Glassf38a6422016-07-27 20:33:01 -0600194 def GetSettings(self, show_warning=True):
195 """Get toolchain settings from the settings file.
196
197 Args:
198 show_warning: True to show a warning if there are no tool chains.
199 """
200 self.prefixes = bsettings.GetItems('toolchain-prefix')
201 self.paths += self.GetPathList(show_warning)
Simon Glassc05694f2013-04-03 11:07:16 +0000202
Simon Glassc6cdd3e2016-03-06 19:45:38 -0700203 def Add(self, fname, test=True, verbose=False, priority=PRIORITY_CALC,
204 arch=None):
Simon Glassc05694f2013-04-03 11:07:16 +0000205 """Add a toolchain to our list
206
207 We select the given toolchain as our preferred one for its
208 architecture if it is a higher priority than the others.
209
210 Args:
211 fname: Filename of toolchain's gcc driver
212 test: True to run the toolchain to test it
Simon Glass7b971292016-03-06 19:45:37 -0700213 priority: Priority to use for this toolchain
Simon Glassc6cdd3e2016-03-06 19:45:38 -0700214 arch: Toolchain architecture, or None if not known
Simon Glassc05694f2013-04-03 11:07:16 +0000215 """
Simon Glassc6cdd3e2016-03-06 19:45:38 -0700216 toolchain = Toolchain(fname, test, verbose, priority, arch)
Simon Glassc05694f2013-04-03 11:07:16 +0000217 add_it = toolchain.ok
218 if toolchain.arch in self.toolchains:
219 add_it = (toolchain.priority <
220 self.toolchains[toolchain.arch].priority)
221 if add_it:
222 self.toolchains[toolchain.arch] = toolchain
Simon Glass7b971292016-03-06 19:45:37 -0700223 elif verbose:
224 print ("Toolchain '%s' at priority %d will be ignored because "
225 "another toolchain for arch '%s' has priority %d" %
226 (toolchain.gcc, toolchain.priority, toolchain.arch,
227 self.toolchains[toolchain.arch].priority))
Simon Glassc05694f2013-04-03 11:07:16 +0000228
Simon Glass7e803e12014-12-01 17:34:06 -0700229 def ScanPath(self, path, verbose):
230 """Scan a path for a valid toolchain
231
232 Args:
233 path: Path to scan
234 verbose: True to print out progress information
235 Returns:
236 Filename of C compiler if found, else None
237 """
Albert ARIBAUDd4f22cf2015-02-01 00:12:44 +0100238 fnames = []
Simon Glass7e803e12014-12-01 17:34:06 -0700239 for subdir in ['.', 'bin', 'usr/bin']:
240 dirname = os.path.join(path, subdir)
241 if verbose: print " - looking in '%s'" % dirname
242 for fname in glob.glob(dirname + '/*gcc'):
243 if verbose: print " - found '%s'" % fname
Albert ARIBAUDd4f22cf2015-02-01 00:12:44 +0100244 fnames.append(fname)
245 return fnames
Simon Glass7e803e12014-12-01 17:34:06 -0700246
Simon Glassf5902732016-03-12 18:50:32 -0700247 def ScanPathEnv(self, fname):
248 """Scan the PATH environment variable for a given filename.
249
250 Args:
251 fname: Filename to scan for
252 Returns:
253 List of matching pathanames, or [] if none
254 """
255 pathname_list = []
256 for path in os.environ["PATH"].split(os.pathsep):
257 path = path.strip('"')
258 pathname = os.path.join(path, fname)
259 if os.path.exists(pathname):
260 pathname_list.append(pathname)
261 return pathname_list
Simon Glass7e803e12014-12-01 17:34:06 -0700262
Simon Glassc05694f2013-04-03 11:07:16 +0000263 def Scan(self, verbose):
264 """Scan for available toolchains and select the best for each arch.
265
266 We look for all the toolchains we can file, figure out the
267 architecture for each, and whether it works. Then we select the
268 highest priority toolchain for each arch.
269
270 Args:
271 verbose: True to print out progress information
272 """
273 if verbose: print 'Scanning for tool chains'
Simon Glassf5902732016-03-12 18:50:32 -0700274 for name, value in self.prefixes:
275 if verbose: print " - scanning prefix '%s'" % value
276 if os.path.exists(value):
277 self.Add(value, True, verbose, PRIORITY_FULL_PREFIX, name)
278 continue
279 fname = value + 'gcc'
280 if os.path.exists(fname):
281 self.Add(fname, True, verbose, PRIORITY_PREFIX_GCC, name)
282 continue
283 fname_list = self.ScanPathEnv(fname)
284 for f in fname_list:
285 self.Add(f, True, verbose, PRIORITY_PREFIX_GCC_PATH, name)
286 if not fname_list:
287 raise ValueError, ("No tool chain found for prefix '%s'" %
288 value)
Simon Glassc05694f2013-04-03 11:07:16 +0000289 for path in self.paths:
290 if verbose: print " - scanning path '%s'" % path
Albert ARIBAUDd4f22cf2015-02-01 00:12:44 +0100291 fnames = self.ScanPath(path, verbose)
292 for fname in fnames:
Simon Glass7e803e12014-12-01 17:34:06 -0700293 self.Add(fname, True, verbose)
Simon Glassc05694f2013-04-03 11:07:16 +0000294
295 def List(self):
296 """List out the selected toolchains for each architecture"""
297 print 'List of available toolchains (%d):' % len(self.toolchains)
298 if len(self.toolchains):
299 for key, value in sorted(self.toolchains.iteritems()):
300 print '%-10s: %s' % (key, value.gcc)
301 else:
302 print 'None'
303
304 def Select(self, arch):
305 """Returns the toolchain for a given architecture
306
307 Args:
308 args: Name of architecture (e.g. 'arm', 'ppc_8xx')
309
310 returns:
311 toolchain object, or None if none found
312 """
Simon Glassc1528c12014-12-01 17:34:05 -0700313 for tag, value in bsettings.GetItems('toolchain-alias'):
314 if arch == tag:
315 for alias in value.split():
316 if alias in self.toolchains:
317 return self.toolchains[alias]
Simon Glassc05694f2013-04-03 11:07:16 +0000318
319 if not arch in self.toolchains:
320 raise ValueError, ("No tool chain found for arch '%s'" % arch)
321 return self.toolchains[arch]
Simon Glasscc246fb2013-09-23 17:35:17 -0600322
323 def ResolveReferences(self, var_dict, args):
324 """Resolve variable references in a string
325
326 This converts ${blah} within the string to the value of blah.
327 This function works recursively.
328
329 Args:
330 var_dict: Dictionary containing variables and their values
331 args: String containing make arguments
332 Returns:
333 Resolved string
334
335 >>> bsettings.Setup()
336 >>> tcs = Toolchains()
337 >>> tcs.Add('fred', False)
338 >>> var_dict = {'oblique' : 'OBLIQUE', 'first' : 'fi${second}rst', \
339 'second' : '2nd'}
340 >>> tcs.ResolveReferences(var_dict, 'this=${oblique}_set')
341 'this=OBLIQUE_set'
342 >>> tcs.ResolveReferences(var_dict, 'this=${oblique}_set${first}nd')
343 'this=OBLIQUE_setfi2ndrstnd'
344 """
Simon Glass53e189d2014-08-28 09:43:40 -0600345 re_var = re.compile('(\$\{[-_a-z0-9A-Z]{1,}\})')
Simon Glasscc246fb2013-09-23 17:35:17 -0600346
347 while True:
348 m = re_var.search(args)
349 if not m:
350 break
351 lookup = m.group(0)[2:-1]
352 value = var_dict.get(lookup, '')
353 args = args[:m.start(0)] + value + args[m.end(0):]
354 return args
355
356 def GetMakeArguments(self, board):
357 """Returns 'make' arguments for a given board
358
359 The flags are in a section called 'make-flags'. Flags are named
360 after the target they represent, for example snapper9260=TESTING=1
361 will pass TESTING=1 to make when building the snapper9260 board.
362
363 References to other boards can be added in the string also. For
364 example:
365
366 [make-flags]
367 at91-boards=ENABLE_AT91_TEST=1
368 snapper9260=${at91-boards} BUILD_TAG=442
369 snapper9g45=${at91-boards} BUILD_TAG=443
370
371 This will return 'ENABLE_AT91_TEST=1 BUILD_TAG=442' for snapper9260
372 and 'ENABLE_AT91_TEST=1 BUILD_TAG=443' for snapper9g45.
373
374 A special 'target' variable is set to the board target.
375
376 Args:
377 board: Board object for the board to check.
378 Returns:
379 'make' flags for that board, or '' if none
380 """
381 self._make_flags['target'] = board.target
382 arg_str = self.ResolveReferences(self._make_flags,
383 self._make_flags.get(board.target, ''))
384 args = arg_str.split(' ')
385 i = 0
386 while i < len(args):
387 if not args[i]:
388 del args[i]
389 else:
390 i += 1
391 return args
Simon Glass7e803e12014-12-01 17:34:06 -0700392
393 def LocateArchUrl(self, fetch_arch):
394 """Find a toolchain available online
395
396 Look in standard places for available toolchains. At present the
397 only standard place is at kernel.org.
398
399 Args:
400 arch: Architecture to look for, or 'list' for all
401 Returns:
402 If fetch_arch is 'list', a tuple:
403 Machine architecture (e.g. x86_64)
404 List of toolchains
405 else
406 URL containing this toolchain, if avaialble, else None
407 """
408 arch = command.OutputOneLine('uname', '-m')
409 base = 'https://www.kernel.org/pub/tools/crosstool/files/bin'
Michal Simeke0e31f32015-04-20 11:46:24 +0200410 versions = ['4.9.0', '4.6.3', '4.6.2', '4.5.1', '4.2.4']
Simon Glass7e803e12014-12-01 17:34:06 -0700411 links = []
412 for version in versions:
413 url = '%s/%s/%s/' % (base, arch, version)
414 print 'Checking: %s' % url
415 response = urllib2.urlopen(url)
416 html = response.read()
417 parser = MyHTMLParser(fetch_arch)
418 parser.feed(html)
419 if fetch_arch == 'list':
420 links += parser.links
421 elif parser.arch_link:
422 return url + parser.arch_link
423 if fetch_arch == 'list':
424 return arch, links
425 return None
426
427 def Download(self, url):
428 """Download a file to a temporary directory
429
430 Args:
431 url: URL to download
432 Returns:
433 Tuple:
434 Temporary directory name
435 Full path to the downloaded archive file in that directory,
436 or None if there was an error while downloading
437 """
Simon Glassd6ece322016-03-06 19:45:35 -0700438 print 'Downloading: %s' % url
Simon Glass7e803e12014-12-01 17:34:06 -0700439 leaf = url.split('/')[-1]
440 tmpdir = tempfile.mkdtemp('.buildman')
441 response = urllib2.urlopen(url)
442 fname = os.path.join(tmpdir, leaf)
443 fd = open(fname, 'wb')
444 meta = response.info()
Simon Glassd6ece322016-03-06 19:45:35 -0700445 size = int(meta.getheaders('Content-Length')[0])
Simon Glass7e803e12014-12-01 17:34:06 -0700446 done = 0
447 block_size = 1 << 16
448 status = ''
449
450 # Read the file in chunks and show progress as we go
451 while True:
452 buffer = response.read(block_size)
453 if not buffer:
454 print chr(8) * (len(status) + 1), '\r',
455 break
456
457 done += len(buffer)
458 fd.write(buffer)
Simon Glassd6ece322016-03-06 19:45:35 -0700459 status = r'%10d MiB [%3d%%]' % (done / 1024 / 1024,
Simon Glass7e803e12014-12-01 17:34:06 -0700460 done * 100 / size)
461 status = status + chr(8) * (len(status) + 1)
462 print status,
463 sys.stdout.flush()
464 fd.close()
465 if done != size:
466 print 'Error, failed to download'
467 os.remove(fname)
468 fname = None
469 return tmpdir, fname
470
471 def Unpack(self, fname, dest):
472 """Unpack a tar file
473
474 Args:
475 fname: Filename to unpack
476 dest: Destination directory
477 Returns:
478 Directory name of the first entry in the archive, without the
479 trailing /
480 """
481 stdout = command.Output('tar', 'xvfJ', fname, '-C', dest)
482 return stdout.splitlines()[0][:-1]
483
484 def TestSettingsHasPath(self, path):
485 """Check if builmand will find this toolchain
486
487 Returns:
488 True if the path is in settings, False if not
489 """
Simon Glassf38a6422016-07-27 20:33:01 -0600490 paths = self.GetPathList(False)
Simon Glass7e803e12014-12-01 17:34:06 -0700491 return path in paths
492
493 def ListArchs(self):
494 """List architectures with available toolchains to download"""
495 host_arch, archives = self.LocateArchUrl('list')
496 re_arch = re.compile('[-a-z0-9.]*_([^-]*)-.*')
497 arch_set = set()
498 for archive in archives:
499 # Remove the host architecture from the start
500 arch = re_arch.match(archive[len(host_arch):])
501 if arch:
502 arch_set.add(arch.group(1))
503 return sorted(arch_set)
504
505 def FetchAndInstall(self, arch):
506 """Fetch and install a new toolchain
507
508 arch:
509 Architecture to fetch, or 'list' to list
510 """
511 # Fist get the URL for this architecture
512 url = self.LocateArchUrl(arch)
513 if not url:
514 print ("Cannot find toolchain for arch '%s' - use 'list' to list" %
515 arch)
516 return 2
517 home = os.environ['HOME']
518 dest = os.path.join(home, '.buildman-toolchains')
519 if not os.path.exists(dest):
520 os.mkdir(dest)
521
522 # Download the tar file for this toolchain and unpack it
523 tmpdir, tarfile = self.Download(url)
524 if not tarfile:
525 return 1
526 print 'Unpacking to: %s' % dest,
527 sys.stdout.flush()
528 path = self.Unpack(tarfile, dest)
529 os.remove(tarfile)
530 os.rmdir(tmpdir)
531 print
532
533 # Check that the toolchain works
534 print 'Testing'
535 dirpath = os.path.join(dest, path)
Simon Glassf6757502015-03-02 17:05:15 -0700536 compiler_fname_list = self.ScanPath(dirpath, True)
537 if not compiler_fname_list:
Simon Glass7e803e12014-12-01 17:34:06 -0700538 print 'Could not locate C compiler - fetch failed.'
539 return 1
Simon Glassf6757502015-03-02 17:05:15 -0700540 if len(compiler_fname_list) != 1:
541 print ('Internal error, ambiguous toolchains: %s' %
542 (', '.join(compiler_fname)))
543 return 1
544 toolchain = Toolchain(compiler_fname_list[0], True, True)
Simon Glass7e803e12014-12-01 17:34:06 -0700545
546 # Make sure that it will be found by buildman
547 if not self.TestSettingsHasPath(dirpath):
548 print ("Adding 'download' to config file '%s'" %
549 bsettings.config_fname)
550 tools_dir = os.path.dirname(dirpath)
551 bsettings.SetItem('toolchain', 'download', '%s/*' % tools_dir)
552 return 0