1fc3fe1c2SSimon Glass# Copyright (c) 2012 The Chromium OS Authors. 2fc3fe1c2SSimon Glass# 31a459660SWolfgang Denk# SPDX-License-Identifier: GPL-2.0+ 4fc3fe1c2SSimon Glass# 5fc3fe1c2SSimon Glass 64281ad8eSSimon Glassimport re 7fc3fe1c2SSimon Glassimport glob 8827e37b5SSimon Glassfrom HTMLParser import HTMLParser 9fc3fe1c2SSimon Glassimport os 10827e37b5SSimon Glassimport sys 11827e37b5SSimon Glassimport tempfile 12827e37b5SSimon Glassimport urllib2 13fc3fe1c2SSimon Glass 14fc3fe1c2SSimon Glassimport bsettings 15fc3fe1c2SSimon Glassimport command 16713bea38SSimon Glassimport terminal 17fc3fe1c2SSimon Glass 1817bce66cSSimon Glass(PRIORITY_FULL_PREFIX, PRIORITY_PREFIX_GCC, PRIORITY_PREFIX_GCC_PATH, 1917bce66cSSimon Glass PRIORITY_CALC) = range(4) 20ff690df9SSimon Glass 21827e37b5SSimon Glass# Simple class to collect links from a page 22827e37b5SSimon Glassclass MyHTMLParser(HTMLParser): 23827e37b5SSimon Glass def __init__(self, arch): 24827e37b5SSimon Glass """Create a new parser 25827e37b5SSimon Glass 26827e37b5SSimon Glass After the parser runs, self.links will be set to a list of the links 27827e37b5SSimon Glass to .xz archives found in the page, and self.arch_link will be set to 28827e37b5SSimon Glass the one for the given architecture (or None if not found). 29827e37b5SSimon Glass 30827e37b5SSimon Glass Args: 31827e37b5SSimon Glass arch: Architecture to search for 32827e37b5SSimon Glass """ 33827e37b5SSimon Glass HTMLParser.__init__(self) 34827e37b5SSimon Glass self.arch_link = None 35827e37b5SSimon Glass self.links = [] 36827e37b5SSimon Glass self._match = '_%s-' % arch 37827e37b5SSimon Glass 38827e37b5SSimon Glass def handle_starttag(self, tag, attrs): 39827e37b5SSimon Glass if tag == 'a': 40827e37b5SSimon Glass for tag, value in attrs: 41827e37b5SSimon Glass if tag == 'href': 42827e37b5SSimon Glass if value and value.endswith('.xz'): 43827e37b5SSimon Glass self.links.append(value) 44827e37b5SSimon Glass if self._match in value: 45827e37b5SSimon Glass self.arch_link = value 46827e37b5SSimon Glass 47827e37b5SSimon Glass 48fc3fe1c2SSimon Glassclass Toolchain: 49fc3fe1c2SSimon Glass """A single toolchain 50fc3fe1c2SSimon Glass 51fc3fe1c2SSimon Glass Public members: 52fc3fe1c2SSimon Glass gcc: Full path to C compiler 53fc3fe1c2SSimon Glass path: Directory path containing C compiler 54fc3fe1c2SSimon Glass cross: Cross compile string, e.g. 'arm-linux-' 55fc3fe1c2SSimon Glass arch: Architecture of toolchain as determined from the first 56fc3fe1c2SSimon Glass component of the filename. E.g. arm-linux-gcc becomes arm 57ff690df9SSimon Glass priority: Toolchain priority (0=highest, 20=lowest) 58fc3fe1c2SSimon Glass """ 59608e399fSSimon Glass def __init__(self, fname, test, verbose=False, priority=PRIORITY_CALC, 60608e399fSSimon Glass arch=None): 61fc3fe1c2SSimon Glass """Create a new toolchain object. 62fc3fe1c2SSimon Glass 63fc3fe1c2SSimon Glass Args: 64fc3fe1c2SSimon Glass fname: Filename of the gcc component 65fc3fe1c2SSimon Glass test: True to run the toolchain to test it 66ad24ebacSSimon Glass verbose: True to print out the information 67ff690df9SSimon Glass priority: Priority to use for this toolchain, or PRIORITY_CALC to 68ff690df9SSimon Glass calculate it 69fc3fe1c2SSimon Glass """ 70fc3fe1c2SSimon Glass self.gcc = fname 71fc3fe1c2SSimon Glass self.path = os.path.dirname(fname) 72b5324123SSimon Glass 73b5324123SSimon Glass # Find the CROSS_COMPILE prefix to use for U-Boot. For example, 74b5324123SSimon Glass # 'arm-linux-gnueabihf-gcc' turns into 'arm-linux-gnueabihf-'. 75b5324123SSimon Glass basename = os.path.basename(fname) 76b5324123SSimon Glass pos = basename.rfind('-') 77b5324123SSimon Glass self.cross = basename[:pos + 1] if pos != -1 else '' 78b5324123SSimon Glass 79b5324123SSimon Glass # The architecture is the first part of the name 80fc3fe1c2SSimon Glass pos = self.cross.find('-') 81608e399fSSimon Glass if arch: 82608e399fSSimon Glass self.arch = arch 83608e399fSSimon Glass else: 84fc3fe1c2SSimon Glass self.arch = self.cross[:pos] if pos != -1 else 'sandbox' 85fc3fe1c2SSimon Glass 86bb1501f2SSimon Glass env = self.MakeEnvironment(False) 87fc3fe1c2SSimon Glass 88fc3fe1c2SSimon Glass # As a basic sanity check, run the C compiler with --version 89fc3fe1c2SSimon Glass cmd = [fname, '--version'] 90ff690df9SSimon Glass if priority == PRIORITY_CALC: 91ff690df9SSimon Glass self.priority = self.GetPriority(fname) 92ff690df9SSimon Glass else: 93ff690df9SSimon Glass self.priority = priority 94fc3fe1c2SSimon Glass if test: 958bb2bddcSStephen Warren result = command.RunPipe([cmd], capture=True, env=env, 968bb2bddcSStephen Warren raise_on_error=False) 97fc3fe1c2SSimon Glass self.ok = result.return_code == 0 98fc3fe1c2SSimon Glass if verbose: 99fc3fe1c2SSimon Glass print 'Tool chain test: ', 100fc3fe1c2SSimon Glass if self.ok: 101608e399fSSimon Glass print "OK, arch='%s', priority %d" % (self.arch, 102608e399fSSimon Glass self.priority) 103fc3fe1c2SSimon Glass else: 104fc3fe1c2SSimon Glass print 'BAD' 105fc3fe1c2SSimon Glass print 'Command: ', cmd 106fc3fe1c2SSimon Glass print result.stdout 107fc3fe1c2SSimon Glass print result.stderr 108fc3fe1c2SSimon Glass else: 109fc3fe1c2SSimon Glass self.ok = True 110fc3fe1c2SSimon Glass 111fc3fe1c2SSimon Glass def GetPriority(self, fname): 112fc3fe1c2SSimon Glass """Return the priority of the toolchain. 113fc3fe1c2SSimon Glass 114fc3fe1c2SSimon Glass Toolchains are ranked according to their suitability by their 115fc3fe1c2SSimon Glass filename prefix. 116fc3fe1c2SSimon Glass 117fc3fe1c2SSimon Glass Args: 118fc3fe1c2SSimon Glass fname: Filename of toolchain 119fc3fe1c2SSimon Glass Returns: 120ff690df9SSimon Glass Priority of toolchain, PRIORITY_CALC=highest, 20=lowest. 121fc3fe1c2SSimon Glass """ 1228708267fSMasahiro Yamada priority_list = ['-elf', '-unknown-linux-gnu', '-linux', 123fc3fe1c2SSimon Glass '-none-linux-gnueabi', '-uclinux', '-none-eabi', 124fc3fe1c2SSimon Glass '-gentoo-linux-gnu', '-linux-gnueabi', '-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 130*d5fe013cSYork Sun def GetWrapper(self, show_warning=True): 131*d5fe013cSYork Sun """Get toolchain wrapper from the setting file. 132*d5fe013cSYork Sun """ 133*d5fe013cSYork Sun value = '' 134*d5fe013cSYork Sun for name, value in bsettings.GetItems('toolchain-wrapper'): 135*d5fe013cSYork Sun if not value: 136*d5fe013cSYork Sun print "Warning: Wrapper not found" 137*d5fe013cSYork Sun if value: 138*d5fe013cSYork Sun value = value + ' ' 139*d5fe013cSYork Sun 140*d5fe013cSYork Sun return value 141*d5fe013cSYork 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 146bb1501f2SSimon Glass the tool chain will operate correctly. 147bb1501f2SSimon Glass 148bb1501f2SSimon Glass Args: 149bb1501f2SSimon Glass full_path: Return the full path in CROSS_COMPILE and don't set 150bb1501f2SSimon Glass PATH 151fc3fe1c2SSimon Glass """ 152fc3fe1c2SSimon Glass env = dict(os.environ) 153*d5fe013cSYork Sun wrapper = self.GetWrapper() 154*d5fe013cSYork Sun 155bb1501f2SSimon Glass if full_path: 156*d5fe013cSYork Sun env['CROSS_COMPILE'] = wrapper + os.path.join(self.path, self.cross) 157bb1501f2SSimon Glass else: 158*d5fe013cSYork Sun env['CROSS_COMPILE'] = wrapper + self.cross 159f210b587SSimon Glass env['PATH'] = self.path + ':' + env['PATH'] 160bb1501f2SSimon Glass 161fc3fe1c2SSimon Glass return env 162fc3fe1c2SSimon Glass 163fc3fe1c2SSimon Glass 164fc3fe1c2SSimon Glassclass Toolchains: 165fc3fe1c2SSimon Glass """Manage a list of toolchains for building U-Boot 166fc3fe1c2SSimon Glass 167fc3fe1c2SSimon Glass We select one toolchain for each architecture type 168fc3fe1c2SSimon Glass 169fc3fe1c2SSimon Glass Public members: 170fc3fe1c2SSimon Glass toolchains: Dict of Toolchain objects, keyed by architecture name 17117bce66cSSimon Glass prefixes: Dict of prefixes to check, keyed by architecture. This can 17217bce66cSSimon Glass be a full path and toolchain prefix, for example 17317bce66cSSimon Glass {'x86', 'opt/i386-linux/bin/i386-linux-'}, or the name of 17417bce66cSSimon Glass something on the search path, for example 17517bce66cSSimon Glass {'arm', 'arm-linux-gnueabihf-'}. Wildcards are not supported. 176fc3fe1c2SSimon Glass paths: List of paths to check for toolchains (may contain wildcards) 177fc3fe1c2SSimon Glass """ 178fc3fe1c2SSimon Glass 179fc3fe1c2SSimon Glass def __init__(self): 180fc3fe1c2SSimon Glass self.toolchains = {} 18117bce66cSSimon Glass self.prefixes = {} 182fc3fe1c2SSimon Glass self.paths = [] 183d4144e45SSimon Glass self._make_flags = dict(bsettings.GetItems('make-flags')) 184d4144e45SSimon Glass 18580e6a487SSimon Glass def GetPathList(self, show_warning=True): 186827e37b5SSimon Glass """Get a list of available toolchain paths 187827e37b5SSimon Glass 18880e6a487SSimon Glass Args: 18980e6a487SSimon Glass show_warning: True to show a warning if there are no tool chains. 19080e6a487SSimon Glass 191827e37b5SSimon Glass Returns: 192827e37b5SSimon Glass List of strings, each a path to a toolchain mentioned in the 193827e37b5SSimon Glass [toolchain] section of the settings file. 194827e37b5SSimon Glass """ 1954281ad8eSSimon Glass toolchains = bsettings.GetItems('toolchain') 19680e6a487SSimon Glass if show_warning and not toolchains: 197713bea38SSimon Glass print ("Warning: No tool chains. Please run 'buildman " 198713bea38SSimon Glass "--fetch-arch all' to download all available toolchains, or " 199713bea38SSimon Glass "add a [toolchain] section to your buildman config file " 200713bea38SSimon Glass "%s. See README for details" % 2011826a18dSMasahiro Yamada bsettings.config_fname) 2024281ad8eSSimon Glass 203827e37b5SSimon Glass paths = [] 2044281ad8eSSimon Glass for name, value in toolchains: 205fc3fe1c2SSimon Glass if '*' in value: 206827e37b5SSimon Glass paths += glob.glob(value) 207fc3fe1c2SSimon Glass else: 208827e37b5SSimon Glass paths.append(value) 209827e37b5SSimon Glass return paths 210827e37b5SSimon Glass 21180e6a487SSimon Glass def GetSettings(self, show_warning=True): 21280e6a487SSimon Glass """Get toolchain settings from the settings file. 21380e6a487SSimon Glass 21480e6a487SSimon Glass Args: 21580e6a487SSimon Glass show_warning: True to show a warning if there are no tool chains. 21680e6a487SSimon Glass """ 21717bce66cSSimon Glass self.prefixes = bsettings.GetItems('toolchain-prefix') 21880e6a487SSimon Glass self.paths += self.GetPathList(show_warning) 219fc3fe1c2SSimon Glass 220608e399fSSimon Glass def Add(self, fname, test=True, verbose=False, priority=PRIORITY_CALC, 221608e399fSSimon Glass arch=None): 222fc3fe1c2SSimon Glass """Add a toolchain to our list 223fc3fe1c2SSimon Glass 224fc3fe1c2SSimon Glass We select the given toolchain as our preferred one for its 225fc3fe1c2SSimon Glass architecture if it is a higher priority than the others. 226fc3fe1c2SSimon Glass 227fc3fe1c2SSimon Glass Args: 228fc3fe1c2SSimon Glass fname: Filename of toolchain's gcc driver 229fc3fe1c2SSimon Glass test: True to run the toolchain to test it 230ff690df9SSimon Glass priority: Priority to use for this toolchain 231608e399fSSimon Glass arch: Toolchain architecture, or None if not known 232fc3fe1c2SSimon Glass """ 233608e399fSSimon Glass toolchain = Toolchain(fname, test, verbose, priority, arch) 234fc3fe1c2SSimon Glass add_it = toolchain.ok 235fc3fe1c2SSimon Glass if toolchain.arch in self.toolchains: 236fc3fe1c2SSimon Glass add_it = (toolchain.priority < 237fc3fe1c2SSimon Glass self.toolchains[toolchain.arch].priority) 238fc3fe1c2SSimon Glass if add_it: 239fc3fe1c2SSimon Glass self.toolchains[toolchain.arch] = toolchain 240ff690df9SSimon Glass elif verbose: 241ff690df9SSimon Glass print ("Toolchain '%s' at priority %d will be ignored because " 242ff690df9SSimon Glass "another toolchain for arch '%s' has priority %d" % 243ff690df9SSimon Glass (toolchain.gcc, toolchain.priority, toolchain.arch, 244ff690df9SSimon Glass self.toolchains[toolchain.arch].priority)) 245fc3fe1c2SSimon Glass 246827e37b5SSimon Glass def ScanPath(self, path, verbose): 247827e37b5SSimon Glass """Scan a path for a valid toolchain 248827e37b5SSimon Glass 249827e37b5SSimon Glass Args: 250827e37b5SSimon Glass path: Path to scan 251827e37b5SSimon Glass verbose: True to print out progress information 252827e37b5SSimon Glass Returns: 253827e37b5SSimon Glass Filename of C compiler if found, else None 254827e37b5SSimon Glass """ 255d9088983SAlbert ARIBAUD fnames = [] 256827e37b5SSimon Glass for subdir in ['.', 'bin', 'usr/bin']: 257827e37b5SSimon Glass dirname = os.path.join(path, subdir) 258827e37b5SSimon Glass if verbose: print " - looking in '%s'" % dirname 259827e37b5SSimon Glass for fname in glob.glob(dirname + '/*gcc'): 260827e37b5SSimon Glass if verbose: print " - found '%s'" % fname 261d9088983SAlbert ARIBAUD fnames.append(fname) 262d9088983SAlbert ARIBAUD return fnames 263827e37b5SSimon Glass 26417bce66cSSimon Glass def ScanPathEnv(self, fname): 26517bce66cSSimon Glass """Scan the PATH environment variable for a given filename. 26617bce66cSSimon Glass 26717bce66cSSimon Glass Args: 26817bce66cSSimon Glass fname: Filename to scan for 26917bce66cSSimon Glass Returns: 27017bce66cSSimon Glass List of matching pathanames, or [] if none 27117bce66cSSimon Glass """ 27217bce66cSSimon Glass pathname_list = [] 27317bce66cSSimon Glass for path in os.environ["PATH"].split(os.pathsep): 27417bce66cSSimon Glass path = path.strip('"') 27517bce66cSSimon Glass pathname = os.path.join(path, fname) 27617bce66cSSimon Glass if os.path.exists(pathname): 27717bce66cSSimon Glass pathname_list.append(pathname) 27817bce66cSSimon Glass return pathname_list 279827e37b5SSimon Glass 280fc3fe1c2SSimon Glass def Scan(self, verbose): 281fc3fe1c2SSimon Glass """Scan for available toolchains and select the best for each arch. 282fc3fe1c2SSimon Glass 283fc3fe1c2SSimon Glass We look for all the toolchains we can file, figure out the 284fc3fe1c2SSimon Glass architecture for each, and whether it works. Then we select the 285fc3fe1c2SSimon Glass highest priority toolchain for each arch. 286fc3fe1c2SSimon Glass 287fc3fe1c2SSimon Glass Args: 288fc3fe1c2SSimon Glass verbose: True to print out progress information 289fc3fe1c2SSimon Glass """ 290fc3fe1c2SSimon Glass if verbose: print 'Scanning for tool chains' 29117bce66cSSimon Glass for name, value in self.prefixes: 29217bce66cSSimon Glass if verbose: print " - scanning prefix '%s'" % value 29317bce66cSSimon Glass if os.path.exists(value): 29417bce66cSSimon Glass self.Add(value, True, verbose, PRIORITY_FULL_PREFIX, name) 29517bce66cSSimon Glass continue 29617bce66cSSimon Glass fname = value + 'gcc' 29717bce66cSSimon Glass if os.path.exists(fname): 29817bce66cSSimon Glass self.Add(fname, True, verbose, PRIORITY_PREFIX_GCC, name) 29917bce66cSSimon Glass continue 30017bce66cSSimon Glass fname_list = self.ScanPathEnv(fname) 30117bce66cSSimon Glass for f in fname_list: 30217bce66cSSimon Glass self.Add(f, True, verbose, PRIORITY_PREFIX_GCC_PATH, name) 30317bce66cSSimon Glass if not fname_list: 30417bce66cSSimon Glass raise ValueError, ("No tool chain found for prefix '%s'" % 30517bce66cSSimon Glass value) 306fc3fe1c2SSimon Glass for path in self.paths: 307fc3fe1c2SSimon Glass if verbose: print " - scanning path '%s'" % path 308d9088983SAlbert ARIBAUD fnames = self.ScanPath(path, verbose) 309d9088983SAlbert ARIBAUD for fname in fnames: 310fc3fe1c2SSimon Glass self.Add(fname, True, verbose) 311fc3fe1c2SSimon Glass 312fc3fe1c2SSimon Glass def List(self): 313fc3fe1c2SSimon Glass """List out the selected toolchains for each architecture""" 314713bea38SSimon Glass col = terminal.Color() 315713bea38SSimon Glass print col.Color(col.BLUE, 'List of available toolchains (%d):' % 316713bea38SSimon Glass len(self.toolchains)) 317fc3fe1c2SSimon Glass if len(self.toolchains): 318fc3fe1c2SSimon Glass for key, value in sorted(self.toolchains.iteritems()): 319fc3fe1c2SSimon Glass print '%-10s: %s' % (key, value.gcc) 320fc3fe1c2SSimon Glass else: 321fc3fe1c2SSimon Glass print 'None' 322fc3fe1c2SSimon Glass 323fc3fe1c2SSimon Glass def Select(self, arch): 324fc3fe1c2SSimon Glass """Returns the toolchain for a given architecture 325fc3fe1c2SSimon Glass 326fc3fe1c2SSimon Glass Args: 327fc3fe1c2SSimon Glass args: Name of architecture (e.g. 'arm', 'ppc_8xx') 328fc3fe1c2SSimon Glass 329fc3fe1c2SSimon Glass returns: 330fc3fe1c2SSimon Glass toolchain object, or None if none found 331fc3fe1c2SSimon Glass """ 3329b83bfdcSSimon Glass for tag, value in bsettings.GetItems('toolchain-alias'): 3339b83bfdcSSimon Glass if arch == tag: 3349b83bfdcSSimon Glass for alias in value.split(): 3359b83bfdcSSimon Glass if alias in self.toolchains: 3369b83bfdcSSimon Glass return self.toolchains[alias] 337fc3fe1c2SSimon Glass 338fc3fe1c2SSimon Glass if not arch in self.toolchains: 339fc3fe1c2SSimon Glass raise ValueError, ("No tool chain found for arch '%s'" % arch) 340fc3fe1c2SSimon Glass return self.toolchains[arch] 3414281ad8eSSimon Glass 3424281ad8eSSimon Glass def ResolveReferences(self, var_dict, args): 3434281ad8eSSimon Glass """Resolve variable references in a string 3444281ad8eSSimon Glass 3454281ad8eSSimon Glass This converts ${blah} within the string to the value of blah. 3464281ad8eSSimon Glass This function works recursively. 3474281ad8eSSimon Glass 3484281ad8eSSimon Glass Args: 3494281ad8eSSimon Glass var_dict: Dictionary containing variables and their values 3504281ad8eSSimon Glass args: String containing make arguments 3514281ad8eSSimon Glass Returns: 3524281ad8eSSimon Glass Resolved string 3534281ad8eSSimon Glass 3544281ad8eSSimon Glass >>> bsettings.Setup() 3554281ad8eSSimon Glass >>> tcs = Toolchains() 3564281ad8eSSimon Glass >>> tcs.Add('fred', False) 3574281ad8eSSimon Glass >>> var_dict = {'oblique' : 'OBLIQUE', 'first' : 'fi${second}rst', \ 3584281ad8eSSimon Glass 'second' : '2nd'} 3594281ad8eSSimon Glass >>> tcs.ResolveReferences(var_dict, 'this=${oblique}_set') 3604281ad8eSSimon Glass 'this=OBLIQUE_set' 3614281ad8eSSimon Glass >>> tcs.ResolveReferences(var_dict, 'this=${oblique}_set${first}nd') 3624281ad8eSSimon Glass 'this=OBLIQUE_setfi2ndrstnd' 3634281ad8eSSimon Glass """ 364f60c9d4fSSimon Glass re_var = re.compile('(\$\{[-_a-z0-9A-Z]{1,}\})') 3654281ad8eSSimon Glass 3664281ad8eSSimon Glass while True: 3674281ad8eSSimon Glass m = re_var.search(args) 3684281ad8eSSimon Glass if not m: 3694281ad8eSSimon Glass break 3704281ad8eSSimon Glass lookup = m.group(0)[2:-1] 3714281ad8eSSimon Glass value = var_dict.get(lookup, '') 3724281ad8eSSimon Glass args = args[:m.start(0)] + value + args[m.end(0):] 3734281ad8eSSimon Glass return args 3744281ad8eSSimon Glass 3754281ad8eSSimon Glass def GetMakeArguments(self, board): 3764281ad8eSSimon Glass """Returns 'make' arguments for a given board 3774281ad8eSSimon Glass 3784281ad8eSSimon Glass The flags are in a section called 'make-flags'. Flags are named 3794281ad8eSSimon Glass after the target they represent, for example snapper9260=TESTING=1 3804281ad8eSSimon Glass will pass TESTING=1 to make when building the snapper9260 board. 3814281ad8eSSimon Glass 3824281ad8eSSimon Glass References to other boards can be added in the string also. For 3834281ad8eSSimon Glass example: 3844281ad8eSSimon Glass 3854281ad8eSSimon Glass [make-flags] 3864281ad8eSSimon Glass at91-boards=ENABLE_AT91_TEST=1 3874281ad8eSSimon Glass snapper9260=${at91-boards} BUILD_TAG=442 3884281ad8eSSimon Glass snapper9g45=${at91-boards} BUILD_TAG=443 3894281ad8eSSimon Glass 3904281ad8eSSimon Glass This will return 'ENABLE_AT91_TEST=1 BUILD_TAG=442' for snapper9260 3914281ad8eSSimon Glass and 'ENABLE_AT91_TEST=1 BUILD_TAG=443' for snapper9g45. 3924281ad8eSSimon Glass 3934281ad8eSSimon Glass A special 'target' variable is set to the board target. 3944281ad8eSSimon Glass 3954281ad8eSSimon Glass Args: 3964281ad8eSSimon Glass board: Board object for the board to check. 3974281ad8eSSimon Glass Returns: 3984281ad8eSSimon Glass 'make' flags for that board, or '' if none 3994281ad8eSSimon Glass """ 4004281ad8eSSimon Glass self._make_flags['target'] = board.target 4014281ad8eSSimon Glass arg_str = self.ResolveReferences(self._make_flags, 4024281ad8eSSimon Glass self._make_flags.get(board.target, '')) 4034281ad8eSSimon Glass args = arg_str.split(' ') 4044281ad8eSSimon Glass i = 0 4054281ad8eSSimon Glass while i < len(args): 4064281ad8eSSimon Glass if not args[i]: 4074281ad8eSSimon Glass del args[i] 4084281ad8eSSimon Glass else: 4094281ad8eSSimon Glass i += 1 4104281ad8eSSimon Glass return args 411827e37b5SSimon Glass 412827e37b5SSimon Glass def LocateArchUrl(self, fetch_arch): 413827e37b5SSimon Glass """Find a toolchain available online 414827e37b5SSimon Glass 415827e37b5SSimon Glass Look in standard places for available toolchains. At present the 416827e37b5SSimon Glass only standard place is at kernel.org. 417827e37b5SSimon Glass 418827e37b5SSimon Glass Args: 419827e37b5SSimon Glass arch: Architecture to look for, or 'list' for all 420827e37b5SSimon Glass Returns: 421827e37b5SSimon Glass If fetch_arch is 'list', a tuple: 422827e37b5SSimon Glass Machine architecture (e.g. x86_64) 423827e37b5SSimon Glass List of toolchains 424827e37b5SSimon Glass else 425827e37b5SSimon Glass URL containing this toolchain, if avaialble, else None 426827e37b5SSimon Glass """ 427827e37b5SSimon Glass arch = command.OutputOneLine('uname', '-m') 428827e37b5SSimon Glass base = 'https://www.kernel.org/pub/tools/crosstool/files/bin' 4291246231cSMichal Simek versions = ['4.9.0', '4.6.3', '4.6.2', '4.5.1', '4.2.4'] 430827e37b5SSimon Glass links = [] 431827e37b5SSimon Glass for version in versions: 432827e37b5SSimon Glass url = '%s/%s/%s/' % (base, arch, version) 433827e37b5SSimon Glass print 'Checking: %s' % url 434827e37b5SSimon Glass response = urllib2.urlopen(url) 435827e37b5SSimon Glass html = response.read() 436827e37b5SSimon Glass parser = MyHTMLParser(fetch_arch) 437827e37b5SSimon Glass parser.feed(html) 438827e37b5SSimon Glass if fetch_arch == 'list': 439827e37b5SSimon Glass links += parser.links 440827e37b5SSimon Glass elif parser.arch_link: 441827e37b5SSimon Glass return url + parser.arch_link 442827e37b5SSimon Glass if fetch_arch == 'list': 443827e37b5SSimon Glass return arch, links 444827e37b5SSimon Glass return None 445827e37b5SSimon Glass 446827e37b5SSimon Glass def Download(self, url): 447827e37b5SSimon Glass """Download a file to a temporary directory 448827e37b5SSimon Glass 449827e37b5SSimon Glass Args: 450827e37b5SSimon Glass url: URL to download 451827e37b5SSimon Glass Returns: 452827e37b5SSimon Glass Tuple: 453827e37b5SSimon Glass Temporary directory name 454827e37b5SSimon Glass Full path to the downloaded archive file in that directory, 455827e37b5SSimon Glass or None if there was an error while downloading 456827e37b5SSimon Glass """ 457ad24ebacSSimon Glass print 'Downloading: %s' % url 458827e37b5SSimon Glass leaf = url.split('/')[-1] 459827e37b5SSimon Glass tmpdir = tempfile.mkdtemp('.buildman') 460827e37b5SSimon Glass response = urllib2.urlopen(url) 461827e37b5SSimon Glass fname = os.path.join(tmpdir, leaf) 462827e37b5SSimon Glass fd = open(fname, 'wb') 463827e37b5SSimon Glass meta = response.info() 464ad24ebacSSimon Glass size = int(meta.getheaders('Content-Length')[0]) 465827e37b5SSimon Glass done = 0 466827e37b5SSimon Glass block_size = 1 << 16 467827e37b5SSimon Glass status = '' 468827e37b5SSimon Glass 469827e37b5SSimon Glass # Read the file in chunks and show progress as we go 470827e37b5SSimon Glass while True: 471827e37b5SSimon Glass buffer = response.read(block_size) 472827e37b5SSimon Glass if not buffer: 473827e37b5SSimon Glass print chr(8) * (len(status) + 1), '\r', 474827e37b5SSimon Glass break 475827e37b5SSimon Glass 476827e37b5SSimon Glass done += len(buffer) 477827e37b5SSimon Glass fd.write(buffer) 478ad24ebacSSimon Glass status = r'%10d MiB [%3d%%]' % (done / 1024 / 1024, 479827e37b5SSimon Glass done * 100 / size) 480827e37b5SSimon Glass status = status + chr(8) * (len(status) + 1) 481827e37b5SSimon Glass print status, 482827e37b5SSimon Glass sys.stdout.flush() 483827e37b5SSimon Glass fd.close() 484827e37b5SSimon Glass if done != size: 485827e37b5SSimon Glass print 'Error, failed to download' 486827e37b5SSimon Glass os.remove(fname) 487827e37b5SSimon Glass fname = None 488827e37b5SSimon Glass return tmpdir, fname 489827e37b5SSimon Glass 490827e37b5SSimon Glass def Unpack(self, fname, dest): 491827e37b5SSimon Glass """Unpack a tar file 492827e37b5SSimon Glass 493827e37b5SSimon Glass Args: 494827e37b5SSimon Glass fname: Filename to unpack 495827e37b5SSimon Glass dest: Destination directory 496827e37b5SSimon Glass Returns: 497827e37b5SSimon Glass Directory name of the first entry in the archive, without the 498827e37b5SSimon Glass trailing / 499827e37b5SSimon Glass """ 500827e37b5SSimon Glass stdout = command.Output('tar', 'xvfJ', fname, '-C', dest) 501827e37b5SSimon Glass return stdout.splitlines()[0][:-1] 502827e37b5SSimon Glass 503827e37b5SSimon Glass def TestSettingsHasPath(self, path): 5042289b276SSimon Glass """Check if buildman will find this toolchain 505827e37b5SSimon Glass 506827e37b5SSimon Glass Returns: 507827e37b5SSimon Glass True if the path is in settings, False if not 508827e37b5SSimon Glass """ 50980e6a487SSimon Glass paths = self.GetPathList(False) 510827e37b5SSimon Glass return path in paths 511827e37b5SSimon Glass 512827e37b5SSimon Glass def ListArchs(self): 513827e37b5SSimon Glass """List architectures with available toolchains to download""" 514827e37b5SSimon Glass host_arch, archives = self.LocateArchUrl('list') 515827e37b5SSimon Glass re_arch = re.compile('[-a-z0-9.]*_([^-]*)-.*') 516827e37b5SSimon Glass arch_set = set() 517827e37b5SSimon Glass for archive in archives: 518827e37b5SSimon Glass # Remove the host architecture from the start 519827e37b5SSimon Glass arch = re_arch.match(archive[len(host_arch):]) 520827e37b5SSimon Glass if arch: 521827e37b5SSimon Glass arch_set.add(arch.group(1)) 522827e37b5SSimon Glass return sorted(arch_set) 523827e37b5SSimon Glass 524827e37b5SSimon Glass def FetchAndInstall(self, arch): 525827e37b5SSimon Glass """Fetch and install a new toolchain 526827e37b5SSimon Glass 527827e37b5SSimon Glass arch: 528827e37b5SSimon Glass Architecture to fetch, or 'list' to list 529827e37b5SSimon Glass """ 530827e37b5SSimon Glass # Fist get the URL for this architecture 531713bea38SSimon Glass col = terminal.Color() 532713bea38SSimon Glass print col.Color(col.BLUE, "Downloading toolchain for arch '%s'" % arch) 533827e37b5SSimon Glass url = self.LocateArchUrl(arch) 534827e37b5SSimon Glass if not url: 535827e37b5SSimon Glass print ("Cannot find toolchain for arch '%s' - use 'list' to list" % 536827e37b5SSimon Glass arch) 537827e37b5SSimon Glass return 2 538827e37b5SSimon Glass home = os.environ['HOME'] 539827e37b5SSimon Glass dest = os.path.join(home, '.buildman-toolchains') 540827e37b5SSimon Glass if not os.path.exists(dest): 541827e37b5SSimon Glass os.mkdir(dest) 542827e37b5SSimon Glass 543827e37b5SSimon Glass # Download the tar file for this toolchain and unpack it 544827e37b5SSimon Glass tmpdir, tarfile = self.Download(url) 545827e37b5SSimon Glass if not tarfile: 546827e37b5SSimon Glass return 1 547713bea38SSimon Glass print col.Color(col.GREEN, 'Unpacking to: %s' % dest), 548827e37b5SSimon Glass sys.stdout.flush() 549827e37b5SSimon Glass path = self.Unpack(tarfile, dest) 550827e37b5SSimon Glass os.remove(tarfile) 551827e37b5SSimon Glass os.rmdir(tmpdir) 552827e37b5SSimon Glass print 553827e37b5SSimon Glass 554827e37b5SSimon Glass # Check that the toolchain works 555713bea38SSimon Glass print col.Color(col.GREEN, 'Testing') 556827e37b5SSimon Glass dirpath = os.path.join(dest, path) 5572a76a649SSimon Glass compiler_fname_list = self.ScanPath(dirpath, True) 5582a76a649SSimon Glass if not compiler_fname_list: 559827e37b5SSimon Glass print 'Could not locate C compiler - fetch failed.' 560827e37b5SSimon Glass return 1 5612a76a649SSimon Glass if len(compiler_fname_list) != 1: 562713bea38SSimon Glass print col.Color(col.RED, 'Warning, ambiguous toolchains: %s' % 563713bea38SSimon Glass ', '.join(compiler_fname_list)) 5642a76a649SSimon Glass toolchain = Toolchain(compiler_fname_list[0], True, True) 565827e37b5SSimon Glass 566827e37b5SSimon Glass # Make sure that it will be found by buildman 567827e37b5SSimon Glass if not self.TestSettingsHasPath(dirpath): 568827e37b5SSimon Glass print ("Adding 'download' to config file '%s'" % 569827e37b5SSimon Glass bsettings.config_fname) 570c8785c5bSSimon Glass bsettings.SetItem('toolchain', 'download', '%s/*/*' % dest) 571827e37b5SSimon Glass return 0 572