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 8fc3fe1c2SSimon Glassimport os 9fc3fe1c2SSimon Glass 10fc3fe1c2SSimon Glassimport bsettings 11fc3fe1c2SSimon Glassimport command 12fc3fe1c2SSimon Glass 13fc3fe1c2SSimon Glassclass Toolchain: 14fc3fe1c2SSimon Glass """A single toolchain 15fc3fe1c2SSimon Glass 16fc3fe1c2SSimon Glass Public members: 17fc3fe1c2SSimon Glass gcc: Full path to C compiler 18fc3fe1c2SSimon Glass path: Directory path containing C compiler 19fc3fe1c2SSimon Glass cross: Cross compile string, e.g. 'arm-linux-' 20fc3fe1c2SSimon Glass arch: Architecture of toolchain as determined from the first 21fc3fe1c2SSimon Glass component of the filename. E.g. arm-linux-gcc becomes arm 22fc3fe1c2SSimon Glass """ 23fc3fe1c2SSimon Glass 24fc3fe1c2SSimon Glass def __init__(self, fname, test, verbose=False): 25fc3fe1c2SSimon Glass """Create a new toolchain object. 26fc3fe1c2SSimon Glass 27fc3fe1c2SSimon Glass Args: 28fc3fe1c2SSimon Glass fname: Filename of the gcc component 29fc3fe1c2SSimon Glass test: True to run the toolchain to test it 30fc3fe1c2SSimon Glass """ 31fc3fe1c2SSimon Glass self.gcc = fname 32fc3fe1c2SSimon Glass self.path = os.path.dirname(fname) 33b5324123SSimon Glass 34b5324123SSimon Glass # Find the CROSS_COMPILE prefix to use for U-Boot. For example, 35b5324123SSimon Glass # 'arm-linux-gnueabihf-gcc' turns into 'arm-linux-gnueabihf-'. 36b5324123SSimon Glass basename = os.path.basename(fname) 37b5324123SSimon Glass pos = basename.rfind('-') 38b5324123SSimon Glass self.cross = basename[:pos + 1] if pos != -1 else '' 39b5324123SSimon Glass 40b5324123SSimon Glass # The architecture is the first part of the name 41fc3fe1c2SSimon Glass pos = self.cross.find('-') 42fc3fe1c2SSimon Glass self.arch = self.cross[:pos] if pos != -1 else 'sandbox' 43fc3fe1c2SSimon Glass 44bb1501f2SSimon Glass env = self.MakeEnvironment(False) 45fc3fe1c2SSimon Glass 46fc3fe1c2SSimon Glass # As a basic sanity check, run the C compiler with --version 47fc3fe1c2SSimon Glass cmd = [fname, '--version'] 48fc3fe1c2SSimon Glass if test: 498bb2bddcSStephen Warren result = command.RunPipe([cmd], capture=True, env=env, 508bb2bddcSStephen Warren raise_on_error=False) 51fc3fe1c2SSimon Glass self.ok = result.return_code == 0 52fc3fe1c2SSimon Glass if verbose: 53fc3fe1c2SSimon Glass print 'Tool chain test: ', 54fc3fe1c2SSimon Glass if self.ok: 55fc3fe1c2SSimon Glass print 'OK' 56fc3fe1c2SSimon Glass else: 57fc3fe1c2SSimon Glass print 'BAD' 58fc3fe1c2SSimon Glass print 'Command: ', cmd 59fc3fe1c2SSimon Glass print result.stdout 60fc3fe1c2SSimon Glass print result.stderr 61fc3fe1c2SSimon Glass else: 62fc3fe1c2SSimon Glass self.ok = True 63fc3fe1c2SSimon Glass self.priority = self.GetPriority(fname) 64fc3fe1c2SSimon Glass 65fc3fe1c2SSimon Glass def GetPriority(self, fname): 66fc3fe1c2SSimon Glass """Return the priority of the toolchain. 67fc3fe1c2SSimon Glass 68fc3fe1c2SSimon Glass Toolchains are ranked according to their suitability by their 69fc3fe1c2SSimon Glass filename prefix. 70fc3fe1c2SSimon Glass 71fc3fe1c2SSimon Glass Args: 72fc3fe1c2SSimon Glass fname: Filename of toolchain 73fc3fe1c2SSimon Glass Returns: 74fc3fe1c2SSimon Glass Priority of toolchain, 0=highest, 20=lowest. 75fc3fe1c2SSimon Glass """ 768708267fSMasahiro Yamada priority_list = ['-elf', '-unknown-linux-gnu', '-linux', 77fc3fe1c2SSimon Glass '-none-linux-gnueabi', '-uclinux', '-none-eabi', 78fc3fe1c2SSimon Glass '-gentoo-linux-gnu', '-linux-gnueabi', '-le-linux', '-uclinux'] 79fc3fe1c2SSimon Glass for prio in range(len(priority_list)): 80fc3fe1c2SSimon Glass if priority_list[prio] in fname: 81fc3fe1c2SSimon Glass return prio 82fc3fe1c2SSimon Glass return prio 83fc3fe1c2SSimon Glass 84bb1501f2SSimon Glass def MakeEnvironment(self, full_path): 85fc3fe1c2SSimon Glass """Returns an environment for using the toolchain. 86fc3fe1c2SSimon Glass 87bb1501f2SSimon Glass Thie takes the current environment and adds CROSS_COMPILE so that 88bb1501f2SSimon Glass the tool chain will operate correctly. 89bb1501f2SSimon Glass 90bb1501f2SSimon Glass Args: 91bb1501f2SSimon Glass full_path: Return the full path in CROSS_COMPILE and don't set 92bb1501f2SSimon Glass PATH 93fc3fe1c2SSimon Glass """ 94fc3fe1c2SSimon Glass env = dict(os.environ) 95bb1501f2SSimon Glass if full_path: 96bb1501f2SSimon Glass env['CROSS_COMPILE'] = os.path.join(self.path, self.cross) 97bb1501f2SSimon Glass else: 98fc3fe1c2SSimon Glass env['CROSS_COMPILE'] = self.cross 99f210b587SSimon Glass env['PATH'] = self.path + ':' + env['PATH'] 100bb1501f2SSimon Glass 101fc3fe1c2SSimon Glass return env 102fc3fe1c2SSimon Glass 103fc3fe1c2SSimon Glass 104fc3fe1c2SSimon Glassclass Toolchains: 105fc3fe1c2SSimon Glass """Manage a list of toolchains for building U-Boot 106fc3fe1c2SSimon Glass 107fc3fe1c2SSimon Glass We select one toolchain for each architecture type 108fc3fe1c2SSimon Glass 109fc3fe1c2SSimon Glass Public members: 110fc3fe1c2SSimon Glass toolchains: Dict of Toolchain objects, keyed by architecture name 111fc3fe1c2SSimon Glass paths: List of paths to check for toolchains (may contain wildcards) 112fc3fe1c2SSimon Glass """ 113fc3fe1c2SSimon Glass 114fc3fe1c2SSimon Glass def __init__(self): 115fc3fe1c2SSimon Glass self.toolchains = {} 116fc3fe1c2SSimon Glass self.paths = [] 117d4144e45SSimon Glass self._make_flags = dict(bsettings.GetItems('make-flags')) 118d4144e45SSimon Glass 119d4144e45SSimon Glass def GetSettings(self): 1204281ad8eSSimon Glass toolchains = bsettings.GetItems('toolchain') 1214281ad8eSSimon Glass if not toolchains: 1224281ad8eSSimon Glass print ("Warning: No tool chains - please add a [toolchain] section" 1234281ad8eSSimon Glass " to your buildman config file %s. See README for details" % 1241826a18dSMasahiro Yamada bsettings.config_fname) 1254281ad8eSSimon Glass 1264281ad8eSSimon Glass for name, value in toolchains: 127fc3fe1c2SSimon Glass if '*' in value: 128fc3fe1c2SSimon Glass self.paths += glob.glob(value) 129fc3fe1c2SSimon Glass else: 130fc3fe1c2SSimon Glass self.paths.append(value) 131fc3fe1c2SSimon Glass 132fc3fe1c2SSimon Glass def Add(self, fname, test=True, verbose=False): 133fc3fe1c2SSimon Glass """Add a toolchain to our list 134fc3fe1c2SSimon Glass 135fc3fe1c2SSimon Glass We select the given toolchain as our preferred one for its 136fc3fe1c2SSimon Glass architecture if it is a higher priority than the others. 137fc3fe1c2SSimon Glass 138fc3fe1c2SSimon Glass Args: 139fc3fe1c2SSimon Glass fname: Filename of toolchain's gcc driver 140fc3fe1c2SSimon Glass test: True to run the toolchain to test it 141fc3fe1c2SSimon Glass """ 142fc3fe1c2SSimon Glass toolchain = Toolchain(fname, test, verbose) 143fc3fe1c2SSimon Glass add_it = toolchain.ok 144fc3fe1c2SSimon Glass if toolchain.arch in self.toolchains: 145fc3fe1c2SSimon Glass add_it = (toolchain.priority < 146fc3fe1c2SSimon Glass self.toolchains[toolchain.arch].priority) 147fc3fe1c2SSimon Glass if add_it: 148fc3fe1c2SSimon Glass self.toolchains[toolchain.arch] = toolchain 149fc3fe1c2SSimon Glass 150fc3fe1c2SSimon Glass def Scan(self, verbose): 151fc3fe1c2SSimon Glass """Scan for available toolchains and select the best for each arch. 152fc3fe1c2SSimon Glass 153fc3fe1c2SSimon Glass We look for all the toolchains we can file, figure out the 154fc3fe1c2SSimon Glass architecture for each, and whether it works. Then we select the 155fc3fe1c2SSimon Glass highest priority toolchain for each arch. 156fc3fe1c2SSimon Glass 157fc3fe1c2SSimon Glass Args: 158fc3fe1c2SSimon Glass verbose: True to print out progress information 159fc3fe1c2SSimon Glass """ 160fc3fe1c2SSimon Glass if verbose: print 'Scanning for tool chains' 161fc3fe1c2SSimon Glass for path in self.paths: 162fc3fe1c2SSimon Glass if verbose: print " - scanning path '%s'" % path 163fc3fe1c2SSimon Glass for subdir in ['.', 'bin', 'usr/bin']: 164fc3fe1c2SSimon Glass dirname = os.path.join(path, subdir) 165fc3fe1c2SSimon Glass if verbose: print " - looking in '%s'" % dirname 166fc3fe1c2SSimon Glass for fname in glob.glob(dirname + '/*gcc'): 167fc3fe1c2SSimon Glass if verbose: print " - found '%s'" % fname 168fc3fe1c2SSimon Glass self.Add(fname, True, verbose) 169fc3fe1c2SSimon Glass 170fc3fe1c2SSimon Glass def List(self): 171fc3fe1c2SSimon Glass """List out the selected toolchains for each architecture""" 172fc3fe1c2SSimon Glass print 'List of available toolchains (%d):' % len(self.toolchains) 173fc3fe1c2SSimon Glass if len(self.toolchains): 174fc3fe1c2SSimon Glass for key, value in sorted(self.toolchains.iteritems()): 175fc3fe1c2SSimon Glass print '%-10s: %s' % (key, value.gcc) 176fc3fe1c2SSimon Glass else: 177fc3fe1c2SSimon Glass print 'None' 178fc3fe1c2SSimon Glass 179fc3fe1c2SSimon Glass def Select(self, arch): 180fc3fe1c2SSimon Glass """Returns the toolchain for a given architecture 181fc3fe1c2SSimon Glass 182fc3fe1c2SSimon Glass Args: 183fc3fe1c2SSimon Glass args: Name of architecture (e.g. 'arm', 'ppc_8xx') 184fc3fe1c2SSimon Glass 185fc3fe1c2SSimon Glass returns: 186fc3fe1c2SSimon Glass toolchain object, or None if none found 187fc3fe1c2SSimon Glass """ 188*9b83bfdcSSimon Glass for tag, value in bsettings.GetItems('toolchain-alias'): 189*9b83bfdcSSimon Glass if arch == tag: 190*9b83bfdcSSimon Glass for alias in value.split(): 191*9b83bfdcSSimon Glass if alias in self.toolchains: 192*9b83bfdcSSimon Glass return self.toolchains[alias] 193fc3fe1c2SSimon Glass 194fc3fe1c2SSimon Glass if not arch in self.toolchains: 195fc3fe1c2SSimon Glass raise ValueError, ("No tool chain found for arch '%s'" % arch) 196fc3fe1c2SSimon Glass return self.toolchains[arch] 1974281ad8eSSimon Glass 1984281ad8eSSimon Glass def ResolveReferences(self, var_dict, args): 1994281ad8eSSimon Glass """Resolve variable references in a string 2004281ad8eSSimon Glass 2014281ad8eSSimon Glass This converts ${blah} within the string to the value of blah. 2024281ad8eSSimon Glass This function works recursively. 2034281ad8eSSimon Glass 2044281ad8eSSimon Glass Args: 2054281ad8eSSimon Glass var_dict: Dictionary containing variables and their values 2064281ad8eSSimon Glass args: String containing make arguments 2074281ad8eSSimon Glass Returns: 2084281ad8eSSimon Glass Resolved string 2094281ad8eSSimon Glass 2104281ad8eSSimon Glass >>> bsettings.Setup() 2114281ad8eSSimon Glass >>> tcs = Toolchains() 2124281ad8eSSimon Glass >>> tcs.Add('fred', False) 2134281ad8eSSimon Glass >>> var_dict = {'oblique' : 'OBLIQUE', 'first' : 'fi${second}rst', \ 2144281ad8eSSimon Glass 'second' : '2nd'} 2154281ad8eSSimon Glass >>> tcs.ResolveReferences(var_dict, 'this=${oblique}_set') 2164281ad8eSSimon Glass 'this=OBLIQUE_set' 2174281ad8eSSimon Glass >>> tcs.ResolveReferences(var_dict, 'this=${oblique}_set${first}nd') 2184281ad8eSSimon Glass 'this=OBLIQUE_setfi2ndrstnd' 2194281ad8eSSimon Glass """ 220f60c9d4fSSimon Glass re_var = re.compile('(\$\{[-_a-z0-9A-Z]{1,}\})') 2214281ad8eSSimon Glass 2224281ad8eSSimon Glass while True: 2234281ad8eSSimon Glass m = re_var.search(args) 2244281ad8eSSimon Glass if not m: 2254281ad8eSSimon Glass break 2264281ad8eSSimon Glass lookup = m.group(0)[2:-1] 2274281ad8eSSimon Glass value = var_dict.get(lookup, '') 2284281ad8eSSimon Glass args = args[:m.start(0)] + value + args[m.end(0):] 2294281ad8eSSimon Glass return args 2304281ad8eSSimon Glass 2314281ad8eSSimon Glass def GetMakeArguments(self, board): 2324281ad8eSSimon Glass """Returns 'make' arguments for a given board 2334281ad8eSSimon Glass 2344281ad8eSSimon Glass The flags are in a section called 'make-flags'. Flags are named 2354281ad8eSSimon Glass after the target they represent, for example snapper9260=TESTING=1 2364281ad8eSSimon Glass will pass TESTING=1 to make when building the snapper9260 board. 2374281ad8eSSimon Glass 2384281ad8eSSimon Glass References to other boards can be added in the string also. For 2394281ad8eSSimon Glass example: 2404281ad8eSSimon Glass 2414281ad8eSSimon Glass [make-flags] 2424281ad8eSSimon Glass at91-boards=ENABLE_AT91_TEST=1 2434281ad8eSSimon Glass snapper9260=${at91-boards} BUILD_TAG=442 2444281ad8eSSimon Glass snapper9g45=${at91-boards} BUILD_TAG=443 2454281ad8eSSimon Glass 2464281ad8eSSimon Glass This will return 'ENABLE_AT91_TEST=1 BUILD_TAG=442' for snapper9260 2474281ad8eSSimon Glass and 'ENABLE_AT91_TEST=1 BUILD_TAG=443' for snapper9g45. 2484281ad8eSSimon Glass 2494281ad8eSSimon Glass A special 'target' variable is set to the board target. 2504281ad8eSSimon Glass 2514281ad8eSSimon Glass Args: 2524281ad8eSSimon Glass board: Board object for the board to check. 2534281ad8eSSimon Glass Returns: 2544281ad8eSSimon Glass 'make' flags for that board, or '' if none 2554281ad8eSSimon Glass """ 2564281ad8eSSimon Glass self._make_flags['target'] = board.target 2574281ad8eSSimon Glass arg_str = self.ResolveReferences(self._make_flags, 2584281ad8eSSimon Glass self._make_flags.get(board.target, '')) 2594281ad8eSSimon Glass args = arg_str.split(' ') 2604281ad8eSSimon Glass i = 0 2614281ad8eSSimon Glass while i < len(args): 2624281ad8eSSimon Glass if not args[i]: 2634281ad8eSSimon Glass del args[i] 2644281ad8eSSimon Glass else: 2654281ad8eSSimon Glass i += 1 2664281ad8eSSimon Glass return args 267