11a459660SWolfgang Denk# SPDX-License-Identifier: GPL-2.0+ 283d290c5STom Rini# Copyright (c) 2012 The Chromium OS Authors. 3fc3fe1c2SSimon Glass# 4fc3fe1c2SSimon Glass 54281ad8eSSimon Glassimport re 6fc3fe1c2SSimon Glassimport glob 7827e37b5SSimon Glassfrom HTMLParser import HTMLParser 8fc3fe1c2SSimon Glassimport os 9827e37b5SSimon Glassimport sys 10827e37b5SSimon Glassimport tempfile 11827e37b5SSimon Glassimport urllib2 12fc3fe1c2SSimon Glass 13fc3fe1c2SSimon Glassimport bsettings 14fc3fe1c2SSimon Glassimport command 15713bea38SSimon Glassimport terminal 16fc3fe1c2SSimon Glass 1717bce66cSSimon Glass(PRIORITY_FULL_PREFIX, PRIORITY_PREFIX_GCC, PRIORITY_PREFIX_GCC_PATH, 1817bce66cSSimon Glass PRIORITY_CALC) = range(4) 19ff690df9SSimon Glass 20827e37b5SSimon Glass# Simple class to collect links from a page 21827e37b5SSimon Glassclass MyHTMLParser(HTMLParser): 22827e37b5SSimon Glass def __init__(self, arch): 23827e37b5SSimon Glass """Create a new parser 24827e37b5SSimon Glass 25827e37b5SSimon Glass After the parser runs, self.links will be set to a list of the links 26827e37b5SSimon Glass to .xz archives found in the page, and self.arch_link will be set to 27827e37b5SSimon Glass the one for the given architecture (or None if not found). 28827e37b5SSimon Glass 29827e37b5SSimon Glass Args: 30827e37b5SSimon Glass arch: Architecture to search for 31827e37b5SSimon Glass """ 32827e37b5SSimon Glass HTMLParser.__init__(self) 33827e37b5SSimon Glass self.arch_link = None 34827e37b5SSimon Glass self.links = [] 35*4c58d273SDaniel Schwierzeck self.re_arch = re.compile('[-_]%s-' % arch) 36827e37b5SSimon Glass 37827e37b5SSimon Glass def handle_starttag(self, tag, attrs): 38827e37b5SSimon Glass if tag == 'a': 39827e37b5SSimon Glass for tag, value in attrs: 40827e37b5SSimon Glass if tag == 'href': 41827e37b5SSimon Glass if value and value.endswith('.xz'): 42827e37b5SSimon Glass self.links.append(value) 43*4c58d273SDaniel Schwierzeck if self.re_arch.search(value): 44827e37b5SSimon Glass self.arch_link = value 45827e37b5SSimon Glass 46827e37b5SSimon Glass 47fc3fe1c2SSimon Glassclass Toolchain: 48fc3fe1c2SSimon Glass """A single toolchain 49fc3fe1c2SSimon Glass 50fc3fe1c2SSimon Glass Public members: 51fc3fe1c2SSimon Glass gcc: Full path to C compiler 52fc3fe1c2SSimon Glass path: Directory path containing C compiler 53fc3fe1c2SSimon Glass cross: Cross compile string, e.g. 'arm-linux-' 54fc3fe1c2SSimon Glass arch: Architecture of toolchain as determined from the first 55fc3fe1c2SSimon Glass component of the filename. E.g. arm-linux-gcc becomes arm 56ff690df9SSimon Glass priority: Toolchain priority (0=highest, 20=lowest) 57fc3fe1c2SSimon Glass """ 58608e399fSSimon Glass def __init__(self, fname, test, verbose=False, priority=PRIORITY_CALC, 59608e399fSSimon Glass arch=None): 60fc3fe1c2SSimon Glass """Create a new toolchain object. 61fc3fe1c2SSimon Glass 62fc3fe1c2SSimon Glass Args: 63fc3fe1c2SSimon Glass fname: Filename of the gcc component 64fc3fe1c2SSimon Glass test: True to run the toolchain to test it 65ad24ebacSSimon Glass verbose: True to print out the information 66ff690df9SSimon Glass priority: Priority to use for this toolchain, or PRIORITY_CALC to 67ff690df9SSimon Glass calculate it 68fc3fe1c2SSimon Glass """ 69fc3fe1c2SSimon Glass self.gcc = fname 70fc3fe1c2SSimon Glass self.path = os.path.dirname(fname) 71b5324123SSimon Glass 72b5324123SSimon Glass # Find the CROSS_COMPILE prefix to use for U-Boot. For example, 73b5324123SSimon Glass # 'arm-linux-gnueabihf-gcc' turns into 'arm-linux-gnueabihf-'. 74b5324123SSimon Glass basename = os.path.basename(fname) 75b5324123SSimon Glass pos = basename.rfind('-') 76b5324123SSimon Glass self.cross = basename[:pos + 1] if pos != -1 else '' 77b5324123SSimon Glass 78b5324123SSimon Glass # The architecture is the first part of the name 79fc3fe1c2SSimon Glass pos = self.cross.find('-') 80608e399fSSimon Glass if arch: 81608e399fSSimon Glass self.arch = arch 82608e399fSSimon Glass else: 83fc3fe1c2SSimon Glass self.arch = self.cross[:pos] if pos != -1 else 'sandbox' 84fc3fe1c2SSimon Glass 85bb1501f2SSimon Glass env = self.MakeEnvironment(False) 86fc3fe1c2SSimon Glass 87fc3fe1c2SSimon Glass # As a basic sanity check, run the C compiler with --version 88fc3fe1c2SSimon Glass cmd = [fname, '--version'] 89ff690df9SSimon Glass if priority == PRIORITY_CALC: 90ff690df9SSimon Glass self.priority = self.GetPriority(fname) 91ff690df9SSimon Glass else: 92ff690df9SSimon Glass self.priority = priority 93fc3fe1c2SSimon Glass if test: 948bb2bddcSStephen Warren result = command.RunPipe([cmd], capture=True, env=env, 958bb2bddcSStephen Warren raise_on_error=False) 96fc3fe1c2SSimon Glass self.ok = result.return_code == 0 97fc3fe1c2SSimon Glass if verbose: 98fc3fe1c2SSimon Glass print 'Tool chain test: ', 99fc3fe1c2SSimon Glass if self.ok: 100608e399fSSimon Glass print "OK, arch='%s', priority %d" % (self.arch, 101608e399fSSimon Glass self.priority) 102fc3fe1c2SSimon Glass else: 103fc3fe1c2SSimon Glass print 'BAD' 104fc3fe1c2SSimon Glass print 'Command: ', cmd 105fc3fe1c2SSimon Glass print result.stdout 106fc3fe1c2SSimon Glass print result.stderr 107fc3fe1c2SSimon Glass else: 108fc3fe1c2SSimon Glass self.ok = True 109fc3fe1c2SSimon Glass 110fc3fe1c2SSimon Glass def GetPriority(self, fname): 111fc3fe1c2SSimon Glass """Return the priority of the toolchain. 112fc3fe1c2SSimon Glass 113fc3fe1c2SSimon Glass Toolchains are ranked according to their suitability by their 114fc3fe1c2SSimon Glass filename prefix. 115fc3fe1c2SSimon Glass 116fc3fe1c2SSimon Glass Args: 117fc3fe1c2SSimon Glass fname: Filename of toolchain 118fc3fe1c2SSimon Glass Returns: 119ff690df9SSimon Glass Priority of toolchain, PRIORITY_CALC=highest, 20=lowest. 120fc3fe1c2SSimon Glass """ 1218708267fSMasahiro Yamada priority_list = ['-elf', '-unknown-linux-gnu', '-linux', 122546a6f3aSTom Rini '-none-linux-gnueabi', '-none-linux-gnueabihf', '-uclinux', 123546a6f3aSTom Rini '-none-eabi', '-gentoo-linux-gnu', '-linux-gnueabi', 124546a6f3aSTom Rini '-linux-gnueabihf', '-le-linux', '-uclinux'] 125fc3fe1c2SSimon Glass for prio in range(len(priority_list)): 126fc3fe1c2SSimon Glass if priority_list[prio] in fname: 127ff690df9SSimon Glass return PRIORITY_CALC + prio 128ff690df9SSimon Glass return PRIORITY_CALC + prio 129fc3fe1c2SSimon Glass 130d5fe013cSYork Sun def GetWrapper(self, show_warning=True): 131d5fe013cSYork Sun """Get toolchain wrapper from the setting file. 132d5fe013cSYork Sun """ 133d5fe013cSYork Sun value = '' 134d5fe013cSYork Sun for name, value in bsettings.GetItems('toolchain-wrapper'): 135d5fe013cSYork Sun if not value: 136d5fe013cSYork Sun print "Warning: Wrapper not found" 137d5fe013cSYork Sun if value: 138d5fe013cSYork Sun value = value + ' ' 139d5fe013cSYork Sun 140d5fe013cSYork Sun return value 141d5fe013cSYork Sun 142bb1501f2SSimon Glass def MakeEnvironment(self, full_path): 143fc3fe1c2SSimon Glass """Returns an environment for using the toolchain. 144fc3fe1c2SSimon Glass 145bb1501f2SSimon Glass Thie takes the current environment and adds CROSS_COMPILE so that 146b0e994c2SDaniel Schwierzeck the tool chain will operate correctly. This also disables localized 147b0e994c2SDaniel Schwierzeck output and possibly unicode encoded output of all build tools by 148b0e994c2SDaniel Schwierzeck adding LC_ALL=C. 149bb1501f2SSimon Glass 150bb1501f2SSimon Glass Args: 151bb1501f2SSimon Glass full_path: Return the full path in CROSS_COMPILE and don't set 152bb1501f2SSimon Glass PATH 153fc3fe1c2SSimon Glass """ 154fc3fe1c2SSimon Glass env = dict(os.environ) 155d5fe013cSYork Sun wrapper = self.GetWrapper() 156d5fe013cSYork Sun 157bb1501f2SSimon Glass if full_path: 158d5fe013cSYork Sun env['CROSS_COMPILE'] = wrapper + os.path.join(self.path, self.cross) 159bb1501f2SSimon Glass else: 160d5fe013cSYork Sun env['CROSS_COMPILE'] = wrapper + self.cross 161f210b587SSimon Glass env['PATH'] = self.path + ':' + env['PATH'] 162bb1501f2SSimon Glass 163b0e994c2SDaniel Schwierzeck env['LC_ALL'] = 'C' 164b0e994c2SDaniel Schwierzeck 165fc3fe1c2SSimon Glass return env 166fc3fe1c2SSimon Glass 167fc3fe1c2SSimon Glass 168fc3fe1c2SSimon Glassclass Toolchains: 169fc3fe1c2SSimon Glass """Manage a list of toolchains for building U-Boot 170fc3fe1c2SSimon Glass 171fc3fe1c2SSimon Glass We select one toolchain for each architecture type 172fc3fe1c2SSimon Glass 173fc3fe1c2SSimon Glass Public members: 174fc3fe1c2SSimon Glass toolchains: Dict of Toolchain objects, keyed by architecture name 17517bce66cSSimon Glass prefixes: Dict of prefixes to check, keyed by architecture. This can 17617bce66cSSimon Glass be a full path and toolchain prefix, for example 17717bce66cSSimon Glass {'x86', 'opt/i386-linux/bin/i386-linux-'}, or the name of 17817bce66cSSimon Glass something on the search path, for example 17917bce66cSSimon Glass {'arm', 'arm-linux-gnueabihf-'}. Wildcards are not supported. 180fc3fe1c2SSimon Glass paths: List of paths to check for toolchains (may contain wildcards) 181fc3fe1c2SSimon Glass """ 182fc3fe1c2SSimon Glass 183fc3fe1c2SSimon Glass def __init__(self): 184fc3fe1c2SSimon Glass self.toolchains = {} 18517bce66cSSimon Glass self.prefixes = {} 186fc3fe1c2SSimon Glass self.paths = [] 187d4144e45SSimon Glass self._make_flags = dict(bsettings.GetItems('make-flags')) 188d4144e45SSimon Glass 18980e6a487SSimon Glass def GetPathList(self, show_warning=True): 190827e37b5SSimon Glass """Get a list of available toolchain paths 191827e37b5SSimon Glass 19280e6a487SSimon Glass Args: 19380e6a487SSimon Glass show_warning: True to show a warning if there are no tool chains. 19480e6a487SSimon Glass 195827e37b5SSimon Glass Returns: 196827e37b5SSimon Glass List of strings, each a path to a toolchain mentioned in the 197827e37b5SSimon Glass [toolchain] section of the settings file. 198827e37b5SSimon Glass """ 1994281ad8eSSimon Glass toolchains = bsettings.GetItems('toolchain') 20080e6a487SSimon Glass if show_warning and not toolchains: 201713bea38SSimon Glass print ("Warning: No tool chains. Please run 'buildman " 202713bea38SSimon Glass "--fetch-arch all' to download all available toolchains, or " 203713bea38SSimon Glass "add a [toolchain] section to your buildman config file " 204713bea38SSimon Glass "%s. See README for details" % 2051826a18dSMasahiro Yamada bsettings.config_fname) 2064281ad8eSSimon Glass 207827e37b5SSimon Glass paths = [] 2084281ad8eSSimon Glass for name, value in toolchains: 209fc3fe1c2SSimon Glass if '*' in value: 210827e37b5SSimon Glass paths += glob.glob(value) 211fc3fe1c2SSimon Glass else: 212827e37b5SSimon Glass paths.append(value) 213827e37b5SSimon Glass return paths 214827e37b5SSimon Glass 21580e6a487SSimon Glass def GetSettings(self, show_warning=True): 21680e6a487SSimon Glass """Get toolchain settings from the settings file. 21780e6a487SSimon Glass 21880e6a487SSimon Glass Args: 21980e6a487SSimon Glass show_warning: True to show a warning if there are no tool chains. 22080e6a487SSimon Glass """ 22117bce66cSSimon Glass self.prefixes = bsettings.GetItems('toolchain-prefix') 22280e6a487SSimon Glass self.paths += self.GetPathList(show_warning) 223fc3fe1c2SSimon Glass 224608e399fSSimon Glass def Add(self, fname, test=True, verbose=False, priority=PRIORITY_CALC, 225608e399fSSimon Glass arch=None): 226fc3fe1c2SSimon Glass """Add a toolchain to our list 227fc3fe1c2SSimon Glass 228fc3fe1c2SSimon Glass We select the given toolchain as our preferred one for its 229fc3fe1c2SSimon Glass architecture if it is a higher priority than the others. 230fc3fe1c2SSimon Glass 231fc3fe1c2SSimon Glass Args: 232fc3fe1c2SSimon Glass fname: Filename of toolchain's gcc driver 233fc3fe1c2SSimon Glass test: True to run the toolchain to test it 234ff690df9SSimon Glass priority: Priority to use for this toolchain 235608e399fSSimon Glass arch: Toolchain architecture, or None if not known 236fc3fe1c2SSimon Glass """ 237608e399fSSimon Glass toolchain = Toolchain(fname, test, verbose, priority, arch) 238fc3fe1c2SSimon Glass add_it = toolchain.ok 239fc3fe1c2SSimon Glass if toolchain.arch in self.toolchains: 240fc3fe1c2SSimon Glass add_it = (toolchain.priority < 241fc3fe1c2SSimon Glass self.toolchains[toolchain.arch].priority) 242fc3fe1c2SSimon Glass if add_it: 243fc3fe1c2SSimon Glass self.toolchains[toolchain.arch] = toolchain 244ff690df9SSimon Glass elif verbose: 245ff690df9SSimon Glass print ("Toolchain '%s' at priority %d will be ignored because " 246ff690df9SSimon Glass "another toolchain for arch '%s' has priority %d" % 247ff690df9SSimon Glass (toolchain.gcc, toolchain.priority, toolchain.arch, 248ff690df9SSimon Glass self.toolchains[toolchain.arch].priority)) 249fc3fe1c2SSimon Glass 250827e37b5SSimon Glass def ScanPath(self, path, verbose): 251827e37b5SSimon Glass """Scan a path for a valid toolchain 252827e37b5SSimon Glass 253827e37b5SSimon Glass Args: 254827e37b5SSimon Glass path: Path to scan 255827e37b5SSimon Glass verbose: True to print out progress information 256827e37b5SSimon Glass Returns: 257827e37b5SSimon Glass Filename of C compiler if found, else None 258827e37b5SSimon Glass """ 259d9088983SAlbert ARIBAUD fnames = [] 260827e37b5SSimon Glass for subdir in ['.', 'bin', 'usr/bin']: 261827e37b5SSimon Glass dirname = os.path.join(path, subdir) 262827e37b5SSimon Glass if verbose: print " - looking in '%s'" % dirname 263827e37b5SSimon Glass for fname in glob.glob(dirname + '/*gcc'): 264827e37b5SSimon Glass if verbose: print " - found '%s'" % fname 265d9088983SAlbert ARIBAUD fnames.append(fname) 266d9088983SAlbert ARIBAUD return fnames 267827e37b5SSimon Glass 26817bce66cSSimon Glass def ScanPathEnv(self, fname): 26917bce66cSSimon Glass """Scan the PATH environment variable for a given filename. 27017bce66cSSimon Glass 27117bce66cSSimon Glass Args: 27217bce66cSSimon Glass fname: Filename to scan for 27317bce66cSSimon Glass Returns: 27417bce66cSSimon Glass List of matching pathanames, or [] if none 27517bce66cSSimon Glass """ 27617bce66cSSimon Glass pathname_list = [] 27717bce66cSSimon Glass for path in os.environ["PATH"].split(os.pathsep): 27817bce66cSSimon Glass path = path.strip('"') 27917bce66cSSimon Glass pathname = os.path.join(path, fname) 28017bce66cSSimon Glass if os.path.exists(pathname): 28117bce66cSSimon Glass pathname_list.append(pathname) 28217bce66cSSimon Glass return pathname_list 283827e37b5SSimon Glass 284fc3fe1c2SSimon Glass def Scan(self, verbose): 285fc3fe1c2SSimon Glass """Scan for available toolchains and select the best for each arch. 286fc3fe1c2SSimon Glass 287fc3fe1c2SSimon Glass We look for all the toolchains we can file, figure out the 288fc3fe1c2SSimon Glass architecture for each, and whether it works. Then we select the 289fc3fe1c2SSimon Glass highest priority toolchain for each arch. 290fc3fe1c2SSimon Glass 291fc3fe1c2SSimon Glass Args: 292fc3fe1c2SSimon Glass verbose: True to print out progress information 293fc3fe1c2SSimon Glass """ 294fc3fe1c2SSimon Glass if verbose: print 'Scanning for tool chains' 29517bce66cSSimon Glass for name, value in self.prefixes: 29617bce66cSSimon Glass if verbose: print " - scanning prefix '%s'" % value 29717bce66cSSimon Glass if os.path.exists(value): 29817bce66cSSimon Glass self.Add(value, True, verbose, PRIORITY_FULL_PREFIX, name) 29917bce66cSSimon Glass continue 30017bce66cSSimon Glass fname = value + 'gcc' 30117bce66cSSimon Glass if os.path.exists(fname): 30217bce66cSSimon Glass self.Add(fname, True, verbose, PRIORITY_PREFIX_GCC, name) 30317bce66cSSimon Glass continue 30417bce66cSSimon Glass fname_list = self.ScanPathEnv(fname) 30517bce66cSSimon Glass for f in fname_list: 30617bce66cSSimon Glass self.Add(f, True, verbose, PRIORITY_PREFIX_GCC_PATH, name) 30717bce66cSSimon Glass if not fname_list: 30817bce66cSSimon Glass raise ValueError, ("No tool chain found for prefix '%s'" % 30917bce66cSSimon Glass value) 310fc3fe1c2SSimon Glass for path in self.paths: 311fc3fe1c2SSimon Glass if verbose: print " - scanning path '%s'" % path 312d9088983SAlbert ARIBAUD fnames = self.ScanPath(path, verbose) 313d9088983SAlbert ARIBAUD for fname in fnames: 314fc3fe1c2SSimon Glass self.Add(fname, True, verbose) 315fc3fe1c2SSimon Glass 316fc3fe1c2SSimon Glass def List(self): 317fc3fe1c2SSimon Glass """List out the selected toolchains for each architecture""" 318713bea38SSimon Glass col = terminal.Color() 319713bea38SSimon Glass print col.Color(col.BLUE, 'List of available toolchains (%d):' % 320713bea38SSimon Glass len(self.toolchains)) 321fc3fe1c2SSimon Glass if len(self.toolchains): 322fc3fe1c2SSimon Glass for key, value in sorted(self.toolchains.iteritems()): 323fc3fe1c2SSimon Glass print '%-10s: %s' % (key, value.gcc) 324fc3fe1c2SSimon Glass else: 325fc3fe1c2SSimon Glass print 'None' 326fc3fe1c2SSimon Glass 327fc3fe1c2SSimon Glass def Select(self, arch): 328fc3fe1c2SSimon Glass """Returns the toolchain for a given architecture 329fc3fe1c2SSimon Glass 330fc3fe1c2SSimon Glass Args: 331fc3fe1c2SSimon Glass args: Name of architecture (e.g. 'arm', 'ppc_8xx') 332fc3fe1c2SSimon Glass 333fc3fe1c2SSimon Glass returns: 334fc3fe1c2SSimon Glass toolchain object, or None if none found 335fc3fe1c2SSimon Glass """ 3369b83bfdcSSimon Glass for tag, value in bsettings.GetItems('toolchain-alias'): 3379b83bfdcSSimon Glass if arch == tag: 3389b83bfdcSSimon Glass for alias in value.split(): 3399b83bfdcSSimon Glass if alias in self.toolchains: 3409b83bfdcSSimon Glass return self.toolchains[alias] 341fc3fe1c2SSimon Glass 342fc3fe1c2SSimon Glass if not arch in self.toolchains: 343fc3fe1c2SSimon Glass raise ValueError, ("No tool chain found for arch '%s'" % arch) 344fc3fe1c2SSimon Glass return self.toolchains[arch] 3454281ad8eSSimon Glass 3464281ad8eSSimon Glass def ResolveReferences(self, var_dict, args): 3474281ad8eSSimon Glass """Resolve variable references in a string 3484281ad8eSSimon Glass 3494281ad8eSSimon Glass This converts ${blah} within the string to the value of blah. 3504281ad8eSSimon Glass This function works recursively. 3514281ad8eSSimon Glass 3524281ad8eSSimon Glass Args: 3534281ad8eSSimon Glass var_dict: Dictionary containing variables and their values 3544281ad8eSSimon Glass args: String containing make arguments 3554281ad8eSSimon Glass Returns: 3564281ad8eSSimon Glass Resolved string 3574281ad8eSSimon Glass 3584281ad8eSSimon Glass >>> bsettings.Setup() 3594281ad8eSSimon Glass >>> tcs = Toolchains() 3604281ad8eSSimon Glass >>> tcs.Add('fred', False) 3614281ad8eSSimon Glass >>> var_dict = {'oblique' : 'OBLIQUE', 'first' : 'fi${second}rst', \ 3624281ad8eSSimon Glass 'second' : '2nd'} 3634281ad8eSSimon Glass >>> tcs.ResolveReferences(var_dict, 'this=${oblique}_set') 3644281ad8eSSimon Glass 'this=OBLIQUE_set' 3654281ad8eSSimon Glass >>> tcs.ResolveReferences(var_dict, 'this=${oblique}_set${first}nd') 3664281ad8eSSimon Glass 'this=OBLIQUE_setfi2ndrstnd' 3674281ad8eSSimon Glass """ 368f60c9d4fSSimon Glass re_var = re.compile('(\$\{[-_a-z0-9A-Z]{1,}\})') 3694281ad8eSSimon Glass 3704281ad8eSSimon Glass while True: 3714281ad8eSSimon Glass m = re_var.search(args) 3724281ad8eSSimon Glass if not m: 3734281ad8eSSimon Glass break 3744281ad8eSSimon Glass lookup = m.group(0)[2:-1] 3754281ad8eSSimon Glass value = var_dict.get(lookup, '') 3764281ad8eSSimon Glass args = args[:m.start(0)] + value + args[m.end(0):] 3774281ad8eSSimon Glass return args 3784281ad8eSSimon Glass 3794281ad8eSSimon Glass def GetMakeArguments(self, board): 3804281ad8eSSimon Glass """Returns 'make' arguments for a given board 3814281ad8eSSimon Glass 3824281ad8eSSimon Glass The flags are in a section called 'make-flags'. Flags are named 3834281ad8eSSimon Glass after the target they represent, for example snapper9260=TESTING=1 3844281ad8eSSimon Glass will pass TESTING=1 to make when building the snapper9260 board. 3854281ad8eSSimon Glass 3864281ad8eSSimon Glass References to other boards can be added in the string also. For 3874281ad8eSSimon Glass example: 3884281ad8eSSimon Glass 3894281ad8eSSimon Glass [make-flags] 3904281ad8eSSimon Glass at91-boards=ENABLE_AT91_TEST=1 3914281ad8eSSimon Glass snapper9260=${at91-boards} BUILD_TAG=442 3924281ad8eSSimon Glass snapper9g45=${at91-boards} BUILD_TAG=443 3934281ad8eSSimon Glass 3944281ad8eSSimon Glass This will return 'ENABLE_AT91_TEST=1 BUILD_TAG=442' for snapper9260 3954281ad8eSSimon Glass and 'ENABLE_AT91_TEST=1 BUILD_TAG=443' for snapper9g45. 3964281ad8eSSimon Glass 3974281ad8eSSimon Glass A special 'target' variable is set to the board target. 3984281ad8eSSimon Glass 3994281ad8eSSimon Glass Args: 4004281ad8eSSimon Glass board: Board object for the board to check. 4014281ad8eSSimon Glass Returns: 4024281ad8eSSimon Glass 'make' flags for that board, or '' if none 4034281ad8eSSimon Glass """ 4044281ad8eSSimon Glass self._make_flags['target'] = board.target 4054281ad8eSSimon Glass arg_str = self.ResolveReferences(self._make_flags, 4064281ad8eSSimon Glass self._make_flags.get(board.target, '')) 4074281ad8eSSimon Glass args = arg_str.split(' ') 4084281ad8eSSimon Glass i = 0 4094281ad8eSSimon Glass while i < len(args): 4104281ad8eSSimon Glass if not args[i]: 4114281ad8eSSimon Glass del args[i] 4124281ad8eSSimon Glass else: 4134281ad8eSSimon Glass i += 1 4144281ad8eSSimon Glass return args 415827e37b5SSimon Glass 416827e37b5SSimon Glass def LocateArchUrl(self, fetch_arch): 417827e37b5SSimon Glass """Find a toolchain available online 418827e37b5SSimon Glass 419827e37b5SSimon Glass Look in standard places for available toolchains. At present the 420827e37b5SSimon Glass only standard place is at kernel.org. 421827e37b5SSimon Glass 422827e37b5SSimon Glass Args: 423827e37b5SSimon Glass arch: Architecture to look for, or 'list' for all 424827e37b5SSimon Glass Returns: 425827e37b5SSimon Glass If fetch_arch is 'list', a tuple: 426827e37b5SSimon Glass Machine architecture (e.g. x86_64) 427827e37b5SSimon Glass List of toolchains 428827e37b5SSimon Glass else 429827e37b5SSimon Glass URL containing this toolchain, if avaialble, else None 430827e37b5SSimon Glass """ 431827e37b5SSimon Glass arch = command.OutputOneLine('uname', '-m') 432827e37b5SSimon Glass base = 'https://www.kernel.org/pub/tools/crosstool/files/bin' 433*4c58d273SDaniel Schwierzeck versions = ['7.3.0', '6.4.0', '4.9.4'] 434827e37b5SSimon Glass links = [] 435827e37b5SSimon Glass for version in versions: 436827e37b5SSimon Glass url = '%s/%s/%s/' % (base, arch, version) 437827e37b5SSimon Glass print 'Checking: %s' % url 438827e37b5SSimon Glass response = urllib2.urlopen(url) 439827e37b5SSimon Glass html = response.read() 440827e37b5SSimon Glass parser = MyHTMLParser(fetch_arch) 441827e37b5SSimon Glass parser.feed(html) 442827e37b5SSimon Glass if fetch_arch == 'list': 443827e37b5SSimon Glass links += parser.links 444827e37b5SSimon Glass elif parser.arch_link: 445827e37b5SSimon Glass return url + parser.arch_link 446827e37b5SSimon Glass if fetch_arch == 'list': 447827e37b5SSimon Glass return arch, links 448827e37b5SSimon Glass return None 449827e37b5SSimon Glass 450827e37b5SSimon Glass def Download(self, url): 451827e37b5SSimon Glass """Download a file to a temporary directory 452827e37b5SSimon Glass 453827e37b5SSimon Glass Args: 454827e37b5SSimon Glass url: URL to download 455827e37b5SSimon Glass Returns: 456827e37b5SSimon Glass Tuple: 457827e37b5SSimon Glass Temporary directory name 458827e37b5SSimon Glass Full path to the downloaded archive file in that directory, 459827e37b5SSimon Glass or None if there was an error while downloading 460827e37b5SSimon Glass """ 461ad24ebacSSimon Glass print 'Downloading: %s' % url 462827e37b5SSimon Glass leaf = url.split('/')[-1] 463827e37b5SSimon Glass tmpdir = tempfile.mkdtemp('.buildman') 464827e37b5SSimon Glass response = urllib2.urlopen(url) 465827e37b5SSimon Glass fname = os.path.join(tmpdir, leaf) 466827e37b5SSimon Glass fd = open(fname, 'wb') 467827e37b5SSimon Glass meta = response.info() 468ad24ebacSSimon Glass size = int(meta.getheaders('Content-Length')[0]) 469827e37b5SSimon Glass done = 0 470827e37b5SSimon Glass block_size = 1 << 16 471827e37b5SSimon Glass status = '' 472827e37b5SSimon Glass 473827e37b5SSimon Glass # Read the file in chunks and show progress as we go 474827e37b5SSimon Glass while True: 475827e37b5SSimon Glass buffer = response.read(block_size) 476827e37b5SSimon Glass if not buffer: 477827e37b5SSimon Glass print chr(8) * (len(status) + 1), '\r', 478827e37b5SSimon Glass break 479827e37b5SSimon Glass 480827e37b5SSimon Glass done += len(buffer) 481827e37b5SSimon Glass fd.write(buffer) 482ad24ebacSSimon Glass status = r'%10d MiB [%3d%%]' % (done / 1024 / 1024, 483827e37b5SSimon Glass done * 100 / size) 484827e37b5SSimon Glass status = status + chr(8) * (len(status) + 1) 485827e37b5SSimon Glass print status, 486827e37b5SSimon Glass sys.stdout.flush() 487827e37b5SSimon Glass fd.close() 488827e37b5SSimon Glass if done != size: 489827e37b5SSimon Glass print 'Error, failed to download' 490827e37b5SSimon Glass os.remove(fname) 491827e37b5SSimon Glass fname = None 492827e37b5SSimon Glass return tmpdir, fname 493827e37b5SSimon Glass 494827e37b5SSimon Glass def Unpack(self, fname, dest): 495827e37b5SSimon Glass """Unpack a tar file 496827e37b5SSimon Glass 497827e37b5SSimon Glass Args: 498827e37b5SSimon Glass fname: Filename to unpack 499827e37b5SSimon Glass dest: Destination directory 500827e37b5SSimon Glass Returns: 501827e37b5SSimon Glass Directory name of the first entry in the archive, without the 502827e37b5SSimon Glass trailing / 503827e37b5SSimon Glass """ 504827e37b5SSimon Glass stdout = command.Output('tar', 'xvfJ', fname, '-C', dest) 505827e37b5SSimon Glass return stdout.splitlines()[0][:-1] 506827e37b5SSimon Glass 507827e37b5SSimon Glass def TestSettingsHasPath(self, path): 5082289b276SSimon Glass """Check if buildman will find this toolchain 509827e37b5SSimon Glass 510827e37b5SSimon Glass Returns: 511827e37b5SSimon Glass True if the path is in settings, False if not 512827e37b5SSimon Glass """ 51380e6a487SSimon Glass paths = self.GetPathList(False) 514827e37b5SSimon Glass return path in paths 515827e37b5SSimon Glass 516827e37b5SSimon Glass def ListArchs(self): 517827e37b5SSimon Glass """List architectures with available toolchains to download""" 518827e37b5SSimon Glass host_arch, archives = self.LocateArchUrl('list') 519827e37b5SSimon Glass re_arch = re.compile('[-a-z0-9.]*_([^-]*)-.*') 520827e37b5SSimon Glass arch_set = set() 521827e37b5SSimon Glass for archive in archives: 522827e37b5SSimon Glass # Remove the host architecture from the start 523827e37b5SSimon Glass arch = re_arch.match(archive[len(host_arch):]) 524827e37b5SSimon Glass if arch: 525827e37b5SSimon Glass arch_set.add(arch.group(1)) 526827e37b5SSimon Glass return sorted(arch_set) 527827e37b5SSimon Glass 528827e37b5SSimon Glass def FetchAndInstall(self, arch): 529827e37b5SSimon Glass """Fetch and install a new toolchain 530827e37b5SSimon Glass 531827e37b5SSimon Glass arch: 532827e37b5SSimon Glass Architecture to fetch, or 'list' to list 533827e37b5SSimon Glass """ 534827e37b5SSimon Glass # Fist get the URL for this architecture 535713bea38SSimon Glass col = terminal.Color() 536713bea38SSimon Glass print col.Color(col.BLUE, "Downloading toolchain for arch '%s'" % arch) 537827e37b5SSimon Glass url = self.LocateArchUrl(arch) 538827e37b5SSimon Glass if not url: 539827e37b5SSimon Glass print ("Cannot find toolchain for arch '%s' - use 'list' to list" % 540827e37b5SSimon Glass arch) 541827e37b5SSimon Glass return 2 542827e37b5SSimon Glass home = os.environ['HOME'] 543827e37b5SSimon Glass dest = os.path.join(home, '.buildman-toolchains') 544827e37b5SSimon Glass if not os.path.exists(dest): 545827e37b5SSimon Glass os.mkdir(dest) 546827e37b5SSimon Glass 547827e37b5SSimon Glass # Download the tar file for this toolchain and unpack it 548827e37b5SSimon Glass tmpdir, tarfile = self.Download(url) 549827e37b5SSimon Glass if not tarfile: 550827e37b5SSimon Glass return 1 551713bea38SSimon Glass print col.Color(col.GREEN, 'Unpacking to: %s' % dest), 552827e37b5SSimon Glass sys.stdout.flush() 553827e37b5SSimon Glass path = self.Unpack(tarfile, dest) 554827e37b5SSimon Glass os.remove(tarfile) 555827e37b5SSimon Glass os.rmdir(tmpdir) 556827e37b5SSimon Glass print 557827e37b5SSimon Glass 558827e37b5SSimon Glass # Check that the toolchain works 559713bea38SSimon Glass print col.Color(col.GREEN, 'Testing') 560827e37b5SSimon Glass dirpath = os.path.join(dest, path) 5612a76a649SSimon Glass compiler_fname_list = self.ScanPath(dirpath, True) 5622a76a649SSimon Glass if not compiler_fname_list: 563827e37b5SSimon Glass print 'Could not locate C compiler - fetch failed.' 564827e37b5SSimon Glass return 1 5652a76a649SSimon Glass if len(compiler_fname_list) != 1: 566713bea38SSimon Glass print col.Color(col.RED, 'Warning, ambiguous toolchains: %s' % 567713bea38SSimon Glass ', '.join(compiler_fname_list)) 5682a76a649SSimon Glass toolchain = Toolchain(compiler_fname_list[0], True, True) 569827e37b5SSimon Glass 570827e37b5SSimon Glass # Make sure that it will be found by buildman 571827e37b5SSimon Glass if not self.TestSettingsHasPath(dirpath): 572827e37b5SSimon Glass print ("Adding 'download' to config file '%s'" % 573827e37b5SSimon Glass bsettings.config_fname) 574c8785c5bSSimon Glass bsettings.SetItem('toolchain', 'download', '%s/*/*' % dest) 575827e37b5SSimon Glass return 0 576