blob: 5cf97ac8148e290804ab240937abf52e2d45bd4d [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',
Tom Rini546a6f32017-04-14 19:47:50 -0400123 '-none-linux-gnueabi', '-none-linux-gnueabihf', '-uclinux',
124 '-none-eabi', '-gentoo-linux-gnu', '-linux-gnueabi',
125 '-linux-gnueabihf', '-le-linux', '-uclinux']
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000126 for prio in range(len(priority_list)):
127 if priority_list[prio] in fname:
Simon Glassff690df2016-03-06 19:45:37 -0700128 return PRIORITY_CALC + prio
129 return PRIORITY_CALC + prio
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000130
York Sund5fe0132016-10-04 14:33:51 -0700131 def GetWrapper(self, show_warning=True):
132 """Get toolchain wrapper from the setting file.
133 """
134 value = ''
135 for name, value in bsettings.GetItems('toolchain-wrapper'):
136 if not value:
137 print "Warning: Wrapper not found"
138 if value:
139 value = value + ' '
140
141 return value
142
Simon Glassbb1501f2014-12-01 17:34:00 -0700143 def MakeEnvironment(self, full_path):
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000144 """Returns an environment for using the toolchain.
145
Simon Glassbb1501f2014-12-01 17:34:00 -0700146 Thie takes the current environment and adds CROSS_COMPILE so that
147 the tool chain will operate correctly.
148
149 Args:
150 full_path: Return the full path in CROSS_COMPILE and don't set
151 PATH
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000152 """
153 env = dict(os.environ)
York Sund5fe0132016-10-04 14:33:51 -0700154 wrapper = self.GetWrapper()
155
Simon Glassbb1501f2014-12-01 17:34:00 -0700156 if full_path:
York Sund5fe0132016-10-04 14:33:51 -0700157 env['CROSS_COMPILE'] = wrapper + os.path.join(self.path, self.cross)
Simon Glassbb1501f2014-12-01 17:34:00 -0700158 else:
York Sund5fe0132016-10-04 14:33:51 -0700159 env['CROSS_COMPILE'] = wrapper + self.cross
Simon Glassbb1501f2014-12-01 17:34:00 -0700160 env['PATH'] = self.path + ':' + env['PATH']
161
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000162 return env
163
164
165class Toolchains:
166 """Manage a list of toolchains for building U-Boot
167
168 We select one toolchain for each architecture type
169
170 Public members:
171 toolchains: Dict of Toolchain objects, keyed by architecture name
Simon Glass17bce662016-03-12 18:50:32 -0700172 prefixes: Dict of prefixes to check, keyed by architecture. This can
173 be a full path and toolchain prefix, for example
174 {'x86', 'opt/i386-linux/bin/i386-linux-'}, or the name of
175 something on the search path, for example
176 {'arm', 'arm-linux-gnueabihf-'}. Wildcards are not supported.
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000177 paths: List of paths to check for toolchains (may contain wildcards)
178 """
179
180 def __init__(self):
181 self.toolchains = {}
Simon Glass17bce662016-03-12 18:50:32 -0700182 self.prefixes = {}
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000183 self.paths = []
Simon Glassd4144e42014-09-05 19:00:13 -0600184 self._make_flags = dict(bsettings.GetItems('make-flags'))
185
Simon Glass80e6a482016-07-27 20:33:01 -0600186 def GetPathList(self, show_warning=True):
Simon Glass827e37b2014-12-01 17:34:06 -0700187 """Get a list of available toolchain paths
188
Simon Glass80e6a482016-07-27 20:33:01 -0600189 Args:
190 show_warning: True to show a warning if there are no tool chains.
191
Simon Glass827e37b2014-12-01 17:34:06 -0700192 Returns:
193 List of strings, each a path to a toolchain mentioned in the
194 [toolchain] section of the settings file.
195 """
Simon Glass4281ad82013-09-23 17:35:17 -0600196 toolchains = bsettings.GetItems('toolchain')
Simon Glass80e6a482016-07-27 20:33:01 -0600197 if show_warning and not toolchains:
Simon Glass713bea32016-07-27 20:33:02 -0600198 print ("Warning: No tool chains. Please run 'buildman "
199 "--fetch-arch all' to download all available toolchains, or "
200 "add a [toolchain] section to your buildman config file "
201 "%s. See README for details" %
202 bsettings.config_fname)
Simon Glass4281ad82013-09-23 17:35:17 -0600203
Simon Glass827e37b2014-12-01 17:34:06 -0700204 paths = []
Simon Glass4281ad82013-09-23 17:35:17 -0600205 for name, value in toolchains:
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000206 if '*' in value:
Simon Glass827e37b2014-12-01 17:34:06 -0700207 paths += glob.glob(value)
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000208 else:
Simon Glass827e37b2014-12-01 17:34:06 -0700209 paths.append(value)
210 return paths
211
Simon Glass80e6a482016-07-27 20:33:01 -0600212 def GetSettings(self, show_warning=True):
213 """Get toolchain settings from the settings file.
214
215 Args:
216 show_warning: True to show a warning if there are no tool chains.
217 """
218 self.prefixes = bsettings.GetItems('toolchain-prefix')
219 self.paths += self.GetPathList(show_warning)
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000220
Simon Glass608e3992016-03-06 19:45:38 -0700221 def Add(self, fname, test=True, verbose=False, priority=PRIORITY_CALC,
222 arch=None):
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000223 """Add a toolchain to our list
224
225 We select the given toolchain as our preferred one for its
226 architecture if it is a higher priority than the others.
227
228 Args:
229 fname: Filename of toolchain's gcc driver
230 test: True to run the toolchain to test it
Simon Glassff690df2016-03-06 19:45:37 -0700231 priority: Priority to use for this toolchain
Simon Glass608e3992016-03-06 19:45:38 -0700232 arch: Toolchain architecture, or None if not known
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000233 """
Simon Glass608e3992016-03-06 19:45:38 -0700234 toolchain = Toolchain(fname, test, verbose, priority, arch)
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000235 add_it = toolchain.ok
236 if toolchain.arch in self.toolchains:
237 add_it = (toolchain.priority <
238 self.toolchains[toolchain.arch].priority)
239 if add_it:
240 self.toolchains[toolchain.arch] = toolchain
Simon Glassff690df2016-03-06 19:45:37 -0700241 elif verbose:
242 print ("Toolchain '%s' at priority %d will be ignored because "
243 "another toolchain for arch '%s' has priority %d" %
244 (toolchain.gcc, toolchain.priority, toolchain.arch,
245 self.toolchains[toolchain.arch].priority))
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000246
Simon Glass827e37b2014-12-01 17:34:06 -0700247 def ScanPath(self, path, verbose):
248 """Scan a path for a valid toolchain
249
250 Args:
251 path: Path to scan
252 verbose: True to print out progress information
253 Returns:
254 Filename of C compiler if found, else None
255 """
Albert ARIBAUDd9088982015-02-01 00:12:44 +0100256 fnames = []
Simon Glass827e37b2014-12-01 17:34:06 -0700257 for subdir in ['.', 'bin', 'usr/bin']:
258 dirname = os.path.join(path, subdir)
259 if verbose: print " - looking in '%s'" % dirname
260 for fname in glob.glob(dirname + '/*gcc'):
261 if verbose: print " - found '%s'" % fname
Albert ARIBAUDd9088982015-02-01 00:12:44 +0100262 fnames.append(fname)
263 return fnames
Simon Glass827e37b2014-12-01 17:34:06 -0700264
Simon Glass17bce662016-03-12 18:50:32 -0700265 def ScanPathEnv(self, fname):
266 """Scan the PATH environment variable for a given filename.
267
268 Args:
269 fname: Filename to scan for
270 Returns:
271 List of matching pathanames, or [] if none
272 """
273 pathname_list = []
274 for path in os.environ["PATH"].split(os.pathsep):
275 path = path.strip('"')
276 pathname = os.path.join(path, fname)
277 if os.path.exists(pathname):
278 pathname_list.append(pathname)
279 return pathname_list
Simon Glass827e37b2014-12-01 17:34:06 -0700280
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000281 def Scan(self, verbose):
282 """Scan for available toolchains and select the best for each arch.
283
284 We look for all the toolchains we can file, figure out the
285 architecture for each, and whether it works. Then we select the
286 highest priority toolchain for each arch.
287
288 Args:
289 verbose: True to print out progress information
290 """
291 if verbose: print 'Scanning for tool chains'
Simon Glass17bce662016-03-12 18:50:32 -0700292 for name, value in self.prefixes:
293 if verbose: print " - scanning prefix '%s'" % value
294 if os.path.exists(value):
295 self.Add(value, True, verbose, PRIORITY_FULL_PREFIX, name)
296 continue
297 fname = value + 'gcc'
298 if os.path.exists(fname):
299 self.Add(fname, True, verbose, PRIORITY_PREFIX_GCC, name)
300 continue
301 fname_list = self.ScanPathEnv(fname)
302 for f in fname_list:
303 self.Add(f, True, verbose, PRIORITY_PREFIX_GCC_PATH, name)
304 if not fname_list:
305 raise ValueError, ("No tool chain found for prefix '%s'" %
306 value)
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000307 for path in self.paths:
308 if verbose: print " - scanning path '%s'" % path
Albert ARIBAUDd9088982015-02-01 00:12:44 +0100309 fnames = self.ScanPath(path, verbose)
310 for fname in fnames:
Simon Glass827e37b2014-12-01 17:34:06 -0700311 self.Add(fname, True, verbose)
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000312
313 def List(self):
314 """List out the selected toolchains for each architecture"""
Simon Glass713bea32016-07-27 20:33:02 -0600315 col = terminal.Color()
316 print col.Color(col.BLUE, 'List of available toolchains (%d):' %
317 len(self.toolchains))
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000318 if len(self.toolchains):
319 for key, value in sorted(self.toolchains.iteritems()):
320 print '%-10s: %s' % (key, value.gcc)
321 else:
322 print 'None'
323
324 def Select(self, arch):
325 """Returns the toolchain for a given architecture
326
327 Args:
328 args: Name of architecture (e.g. 'arm', 'ppc_8xx')
329
330 returns:
331 toolchain object, or None if none found
332 """
Simon Glass9b83bfd2014-12-01 17:34:05 -0700333 for tag, value in bsettings.GetItems('toolchain-alias'):
334 if arch == tag:
335 for alias in value.split():
336 if alias in self.toolchains:
337 return self.toolchains[alias]
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000338
339 if not arch in self.toolchains:
340 raise ValueError, ("No tool chain found for arch '%s'" % arch)
341 return self.toolchains[arch]
Simon Glass4281ad82013-09-23 17:35:17 -0600342
343 def ResolveReferences(self, var_dict, args):
344 """Resolve variable references in a string
345
346 This converts ${blah} within the string to the value of blah.
347 This function works recursively.
348
349 Args:
350 var_dict: Dictionary containing variables and their values
351 args: String containing make arguments
352 Returns:
353 Resolved string
354
355 >>> bsettings.Setup()
356 >>> tcs = Toolchains()
357 >>> tcs.Add('fred', False)
358 >>> var_dict = {'oblique' : 'OBLIQUE', 'first' : 'fi${second}rst', \
359 'second' : '2nd'}
360 >>> tcs.ResolveReferences(var_dict, 'this=${oblique}_set')
361 'this=OBLIQUE_set'
362 >>> tcs.ResolveReferences(var_dict, 'this=${oblique}_set${first}nd')
363 'this=OBLIQUE_setfi2ndrstnd'
364 """
Simon Glassf60c9d42014-08-28 09:43:40 -0600365 re_var = re.compile('(\$\{[-_a-z0-9A-Z]{1,}\})')
Simon Glass4281ad82013-09-23 17:35:17 -0600366
367 while True:
368 m = re_var.search(args)
369 if not m:
370 break
371 lookup = m.group(0)[2:-1]
372 value = var_dict.get(lookup, '')
373 args = args[:m.start(0)] + value + args[m.end(0):]
374 return args
375
376 def GetMakeArguments(self, board):
377 """Returns 'make' arguments for a given board
378
379 The flags are in a section called 'make-flags'. Flags are named
380 after the target they represent, for example snapper9260=TESTING=1
381 will pass TESTING=1 to make when building the snapper9260 board.
382
383 References to other boards can be added in the string also. For
384 example:
385
386 [make-flags]
387 at91-boards=ENABLE_AT91_TEST=1
388 snapper9260=${at91-boards} BUILD_TAG=442
389 snapper9g45=${at91-boards} BUILD_TAG=443
390
391 This will return 'ENABLE_AT91_TEST=1 BUILD_TAG=442' for snapper9260
392 and 'ENABLE_AT91_TEST=1 BUILD_TAG=443' for snapper9g45.
393
394 A special 'target' variable is set to the board target.
395
396 Args:
397 board: Board object for the board to check.
398 Returns:
399 'make' flags for that board, or '' if none
400 """
401 self._make_flags['target'] = board.target
402 arg_str = self.ResolveReferences(self._make_flags,
403 self._make_flags.get(board.target, ''))
404 args = arg_str.split(' ')
405 i = 0
406 while i < len(args):
407 if not args[i]:
408 del args[i]
409 else:
410 i += 1
411 return args
Simon Glass827e37b2014-12-01 17:34:06 -0700412
413 def LocateArchUrl(self, fetch_arch):
414 """Find a toolchain available online
415
416 Look in standard places for available toolchains. At present the
417 only standard place is at kernel.org.
418
419 Args:
420 arch: Architecture to look for, or 'list' for all
421 Returns:
422 If fetch_arch is 'list', a tuple:
423 Machine architecture (e.g. x86_64)
424 List of toolchains
425 else
426 URL containing this toolchain, if avaialble, else None
427 """
428 arch = command.OutputOneLine('uname', '-m')
429 base = 'https://www.kernel.org/pub/tools/crosstool/files/bin'
Michal Simek12462312015-04-20 11:46:24 +0200430 versions = ['4.9.0', '4.6.3', '4.6.2', '4.5.1', '4.2.4']
Simon Glass827e37b2014-12-01 17:34:06 -0700431 links = []
432 for version in versions:
433 url = '%s/%s/%s/' % (base, arch, version)
434 print 'Checking: %s' % url
435 response = urllib2.urlopen(url)
436 html = response.read()
437 parser = MyHTMLParser(fetch_arch)
438 parser.feed(html)
439 if fetch_arch == 'list':
440 links += parser.links
441 elif parser.arch_link:
442 return url + parser.arch_link
443 if fetch_arch == 'list':
444 return arch, links
445 return None
446
447 def Download(self, url):
448 """Download a file to a temporary directory
449
450 Args:
451 url: URL to download
452 Returns:
453 Tuple:
454 Temporary directory name
455 Full path to the downloaded archive file in that directory,
456 or None if there was an error while downloading
457 """
Simon Glassad24eba2016-03-06 19:45:35 -0700458 print 'Downloading: %s' % url
Simon Glass827e37b2014-12-01 17:34:06 -0700459 leaf = url.split('/')[-1]
460 tmpdir = tempfile.mkdtemp('.buildman')
461 response = urllib2.urlopen(url)
462 fname = os.path.join(tmpdir, leaf)
463 fd = open(fname, 'wb')
464 meta = response.info()
Simon Glassad24eba2016-03-06 19:45:35 -0700465 size = int(meta.getheaders('Content-Length')[0])
Simon Glass827e37b2014-12-01 17:34:06 -0700466 done = 0
467 block_size = 1 << 16
468 status = ''
469
470 # Read the file in chunks and show progress as we go
471 while True:
472 buffer = response.read(block_size)
473 if not buffer:
474 print chr(8) * (len(status) + 1), '\r',
475 break
476
477 done += len(buffer)
478 fd.write(buffer)
Simon Glassad24eba2016-03-06 19:45:35 -0700479 status = r'%10d MiB [%3d%%]' % (done / 1024 / 1024,
Simon Glass827e37b2014-12-01 17:34:06 -0700480 done * 100 / size)
481 status = status + chr(8) * (len(status) + 1)
482 print status,
483 sys.stdout.flush()
484 fd.close()
485 if done != size:
486 print 'Error, failed to download'
487 os.remove(fname)
488 fname = None
489 return tmpdir, fname
490
491 def Unpack(self, fname, dest):
492 """Unpack a tar file
493
494 Args:
495 fname: Filename to unpack
496 dest: Destination directory
497 Returns:
498 Directory name of the first entry in the archive, without the
499 trailing /
500 """
501 stdout = command.Output('tar', 'xvfJ', fname, '-C', dest)
502 return stdout.splitlines()[0][:-1]
503
504 def TestSettingsHasPath(self, path):
Simon Glass2289b272016-07-27 20:33:03 -0600505 """Check if buildman will find this toolchain
Simon Glass827e37b2014-12-01 17:34:06 -0700506
507 Returns:
508 True if the path is in settings, False if not
509 """
Simon Glass80e6a482016-07-27 20:33:01 -0600510 paths = self.GetPathList(False)
Simon Glass827e37b2014-12-01 17:34:06 -0700511 return path in paths
512
513 def ListArchs(self):
514 """List architectures with available toolchains to download"""
515 host_arch, archives = self.LocateArchUrl('list')
516 re_arch = re.compile('[-a-z0-9.]*_([^-]*)-.*')
517 arch_set = set()
518 for archive in archives:
519 # Remove the host architecture from the start
520 arch = re_arch.match(archive[len(host_arch):])
521 if arch:
522 arch_set.add(arch.group(1))
523 return sorted(arch_set)
524
525 def FetchAndInstall(self, arch):
526 """Fetch and install a new toolchain
527
528 arch:
529 Architecture to fetch, or 'list' to list
530 """
531 # Fist get the URL for this architecture
Simon Glass713bea32016-07-27 20:33:02 -0600532 col = terminal.Color()
533 print col.Color(col.BLUE, "Downloading toolchain for arch '%s'" % arch)
Simon Glass827e37b2014-12-01 17:34:06 -0700534 url = self.LocateArchUrl(arch)
535 if not url:
536 print ("Cannot find toolchain for arch '%s' - use 'list' to list" %
537 arch)
538 return 2
539 home = os.environ['HOME']
540 dest = os.path.join(home, '.buildman-toolchains')
541 if not os.path.exists(dest):
542 os.mkdir(dest)
543
544 # Download the tar file for this toolchain and unpack it
545 tmpdir, tarfile = self.Download(url)
546 if not tarfile:
547 return 1
Simon Glass713bea32016-07-27 20:33:02 -0600548 print col.Color(col.GREEN, 'Unpacking to: %s' % dest),
Simon Glass827e37b2014-12-01 17:34:06 -0700549 sys.stdout.flush()
550 path = self.Unpack(tarfile, dest)
551 os.remove(tarfile)
552 os.rmdir(tmpdir)
553 print
554
555 # Check that the toolchain works
Simon Glass713bea32016-07-27 20:33:02 -0600556 print col.Color(col.GREEN, 'Testing')
Simon Glass827e37b2014-12-01 17:34:06 -0700557 dirpath = os.path.join(dest, path)
Simon Glass2a76a642015-03-02 17:05:15 -0700558 compiler_fname_list = self.ScanPath(dirpath, True)
559 if not compiler_fname_list:
Simon Glass827e37b2014-12-01 17:34:06 -0700560 print 'Could not locate C compiler - fetch failed.'
561 return 1
Simon Glass2a76a642015-03-02 17:05:15 -0700562 if len(compiler_fname_list) != 1:
Simon Glass713bea32016-07-27 20:33:02 -0600563 print col.Color(col.RED, 'Warning, ambiguous toolchains: %s' %
564 ', '.join(compiler_fname_list))
Simon Glass2a76a642015-03-02 17:05:15 -0700565 toolchain = Toolchain(compiler_fname_list[0], True, True)
Simon Glass827e37b2014-12-01 17:34:06 -0700566
567 # Make sure that it will be found by buildman
568 if not self.TestSettingsHasPath(dirpath):
569 print ("Adding 'download' to config file '%s'" %
570 bsettings.config_fname)
Simon Glassc8785c52016-07-27 20:33:05 -0600571 bsettings.SetItem('toolchain', 'download', '%s/*/*' % dest)
Simon Glass827e37b2014-12-01 17:34:06 -0700572 return 0