1fc3fe1c2SSimon Glass# Copyright (c) 2012 The Chromium OS Authors. 2fc3fe1c2SSimon Glass# 31a459660SWolfgang Denk# SPDX-License-Identifier: GPL-2.0+ 4fc3fe1c2SSimon Glass# 5fc3fe1c2SSimon Glass 6*4281ad8eSSimon 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) 33fc3fe1c2SSimon Glass self.cross = os.path.basename(fname)[:-3] 34fc3fe1c2SSimon Glass pos = self.cross.find('-') 35fc3fe1c2SSimon Glass self.arch = self.cross[:pos] if pos != -1 else 'sandbox' 36fc3fe1c2SSimon Glass 37fc3fe1c2SSimon Glass env = self.MakeEnvironment() 38fc3fe1c2SSimon Glass 39fc3fe1c2SSimon Glass # As a basic sanity check, run the C compiler with --version 40fc3fe1c2SSimon Glass cmd = [fname, '--version'] 41fc3fe1c2SSimon Glass if test: 42fc3fe1c2SSimon Glass result = command.RunPipe([cmd], capture=True, env=env) 43fc3fe1c2SSimon Glass self.ok = result.return_code == 0 44fc3fe1c2SSimon Glass if verbose: 45fc3fe1c2SSimon Glass print 'Tool chain test: ', 46fc3fe1c2SSimon Glass if self.ok: 47fc3fe1c2SSimon Glass print 'OK' 48fc3fe1c2SSimon Glass else: 49fc3fe1c2SSimon Glass print 'BAD' 50fc3fe1c2SSimon Glass print 'Command: ', cmd 51fc3fe1c2SSimon Glass print result.stdout 52fc3fe1c2SSimon Glass print result.stderr 53fc3fe1c2SSimon Glass else: 54fc3fe1c2SSimon Glass self.ok = True 55fc3fe1c2SSimon Glass self.priority = self.GetPriority(fname) 56fc3fe1c2SSimon Glass 57fc3fe1c2SSimon Glass def GetPriority(self, fname): 58fc3fe1c2SSimon Glass """Return the priority of the toolchain. 59fc3fe1c2SSimon Glass 60fc3fe1c2SSimon Glass Toolchains are ranked according to their suitability by their 61fc3fe1c2SSimon Glass filename prefix. 62fc3fe1c2SSimon Glass 63fc3fe1c2SSimon Glass Args: 64fc3fe1c2SSimon Glass fname: Filename of toolchain 65fc3fe1c2SSimon Glass Returns: 66fc3fe1c2SSimon Glass Priority of toolchain, 0=highest, 20=lowest. 67fc3fe1c2SSimon Glass """ 68fc3fe1c2SSimon Glass priority_list = ['-elf', '-unknown-linux-gnu', '-linux', '-elf', 69fc3fe1c2SSimon Glass '-none-linux-gnueabi', '-uclinux', '-none-eabi', 70fc3fe1c2SSimon Glass '-gentoo-linux-gnu', '-linux-gnueabi', '-le-linux', '-uclinux'] 71fc3fe1c2SSimon Glass for prio in range(len(priority_list)): 72fc3fe1c2SSimon Glass if priority_list[prio] in fname: 73fc3fe1c2SSimon Glass return prio 74fc3fe1c2SSimon Glass return prio 75fc3fe1c2SSimon Glass 76fc3fe1c2SSimon Glass def MakeEnvironment(self): 77fc3fe1c2SSimon Glass """Returns an environment for using the toolchain. 78fc3fe1c2SSimon Glass 79fc3fe1c2SSimon Glass Thie takes the current environment, adds CROSS_COMPILE and 80fc3fe1c2SSimon Glass augments PATH so that the toolchain will operate correctly. 81fc3fe1c2SSimon Glass """ 82fc3fe1c2SSimon Glass env = dict(os.environ) 83fc3fe1c2SSimon Glass env['CROSS_COMPILE'] = self.cross 84fc3fe1c2SSimon Glass env['PATH'] += (':' + self.path) 85fc3fe1c2SSimon Glass return env 86fc3fe1c2SSimon Glass 87fc3fe1c2SSimon Glass 88fc3fe1c2SSimon Glassclass Toolchains: 89fc3fe1c2SSimon Glass """Manage a list of toolchains for building U-Boot 90fc3fe1c2SSimon Glass 91fc3fe1c2SSimon Glass We select one toolchain for each architecture type 92fc3fe1c2SSimon Glass 93fc3fe1c2SSimon Glass Public members: 94fc3fe1c2SSimon Glass toolchains: Dict of Toolchain objects, keyed by architecture name 95fc3fe1c2SSimon Glass paths: List of paths to check for toolchains (may contain wildcards) 96fc3fe1c2SSimon Glass """ 97fc3fe1c2SSimon Glass 98fc3fe1c2SSimon Glass def __init__(self): 99fc3fe1c2SSimon Glass self.toolchains = {} 100fc3fe1c2SSimon Glass self.paths = [] 101*4281ad8eSSimon Glass toolchains = bsettings.GetItems('toolchain') 102*4281ad8eSSimon Glass if not toolchains: 103*4281ad8eSSimon Glass print ("Warning: No tool chains - please add a [toolchain] section" 104*4281ad8eSSimon Glass " to your buildman config file %s. See README for details" % 105*4281ad8eSSimon Glass config_fname) 106*4281ad8eSSimon Glass 107*4281ad8eSSimon Glass for name, value in toolchains: 108fc3fe1c2SSimon Glass if '*' in value: 109fc3fe1c2SSimon Glass self.paths += glob.glob(value) 110fc3fe1c2SSimon Glass else: 111fc3fe1c2SSimon Glass self.paths.append(value) 112*4281ad8eSSimon Glass self._make_flags = dict(bsettings.GetItems('make-flags')) 113fc3fe1c2SSimon Glass 114fc3fe1c2SSimon Glass def Add(self, fname, test=True, verbose=False): 115fc3fe1c2SSimon Glass """Add a toolchain to our list 116fc3fe1c2SSimon Glass 117fc3fe1c2SSimon Glass We select the given toolchain as our preferred one for its 118fc3fe1c2SSimon Glass architecture if it is a higher priority than the others. 119fc3fe1c2SSimon Glass 120fc3fe1c2SSimon Glass Args: 121fc3fe1c2SSimon Glass fname: Filename of toolchain's gcc driver 122fc3fe1c2SSimon Glass test: True to run the toolchain to test it 123fc3fe1c2SSimon Glass """ 124fc3fe1c2SSimon Glass toolchain = Toolchain(fname, test, verbose) 125fc3fe1c2SSimon Glass add_it = toolchain.ok 126fc3fe1c2SSimon Glass if toolchain.arch in self.toolchains: 127fc3fe1c2SSimon Glass add_it = (toolchain.priority < 128fc3fe1c2SSimon Glass self.toolchains[toolchain.arch].priority) 129fc3fe1c2SSimon Glass if add_it: 130fc3fe1c2SSimon Glass self.toolchains[toolchain.arch] = toolchain 131fc3fe1c2SSimon Glass 132fc3fe1c2SSimon Glass def Scan(self, verbose): 133fc3fe1c2SSimon Glass """Scan for available toolchains and select the best for each arch. 134fc3fe1c2SSimon Glass 135fc3fe1c2SSimon Glass We look for all the toolchains we can file, figure out the 136fc3fe1c2SSimon Glass architecture for each, and whether it works. Then we select the 137fc3fe1c2SSimon Glass highest priority toolchain for each arch. 138fc3fe1c2SSimon Glass 139fc3fe1c2SSimon Glass Args: 140fc3fe1c2SSimon Glass verbose: True to print out progress information 141fc3fe1c2SSimon Glass """ 142fc3fe1c2SSimon Glass if verbose: print 'Scanning for tool chains' 143fc3fe1c2SSimon Glass for path in self.paths: 144fc3fe1c2SSimon Glass if verbose: print " - scanning path '%s'" % path 145fc3fe1c2SSimon Glass for subdir in ['.', 'bin', 'usr/bin']: 146fc3fe1c2SSimon Glass dirname = os.path.join(path, subdir) 147fc3fe1c2SSimon Glass if verbose: print " - looking in '%s'" % dirname 148fc3fe1c2SSimon Glass for fname in glob.glob(dirname + '/*gcc'): 149fc3fe1c2SSimon Glass if verbose: print " - found '%s'" % fname 150fc3fe1c2SSimon Glass self.Add(fname, True, verbose) 151fc3fe1c2SSimon Glass 152fc3fe1c2SSimon Glass def List(self): 153fc3fe1c2SSimon Glass """List out the selected toolchains for each architecture""" 154fc3fe1c2SSimon Glass print 'List of available toolchains (%d):' % len(self.toolchains) 155fc3fe1c2SSimon Glass if len(self.toolchains): 156fc3fe1c2SSimon Glass for key, value in sorted(self.toolchains.iteritems()): 157fc3fe1c2SSimon Glass print '%-10s: %s' % (key, value.gcc) 158fc3fe1c2SSimon Glass else: 159fc3fe1c2SSimon Glass print 'None' 160fc3fe1c2SSimon Glass 161fc3fe1c2SSimon Glass def Select(self, arch): 162fc3fe1c2SSimon Glass """Returns the toolchain for a given architecture 163fc3fe1c2SSimon Glass 164fc3fe1c2SSimon Glass Args: 165fc3fe1c2SSimon Glass args: Name of architecture (e.g. 'arm', 'ppc_8xx') 166fc3fe1c2SSimon Glass 167fc3fe1c2SSimon Glass returns: 168fc3fe1c2SSimon Glass toolchain object, or None if none found 169fc3fe1c2SSimon Glass """ 170fc3fe1c2SSimon Glass for name, value in bsettings.GetItems('toolchain-alias'): 171fc3fe1c2SSimon Glass if arch == name: 172fc3fe1c2SSimon Glass arch = value 173fc3fe1c2SSimon Glass 174fc3fe1c2SSimon Glass if not arch in self.toolchains: 175fc3fe1c2SSimon Glass raise ValueError, ("No tool chain found for arch '%s'" % arch) 176fc3fe1c2SSimon Glass return self.toolchains[arch] 177*4281ad8eSSimon Glass 178*4281ad8eSSimon Glass def ResolveReferences(self, var_dict, args): 179*4281ad8eSSimon Glass """Resolve variable references in a string 180*4281ad8eSSimon Glass 181*4281ad8eSSimon Glass This converts ${blah} within the string to the value of blah. 182*4281ad8eSSimon Glass This function works recursively. 183*4281ad8eSSimon Glass 184*4281ad8eSSimon Glass Args: 185*4281ad8eSSimon Glass var_dict: Dictionary containing variables and their values 186*4281ad8eSSimon Glass args: String containing make arguments 187*4281ad8eSSimon Glass Returns: 188*4281ad8eSSimon Glass Resolved string 189*4281ad8eSSimon Glass 190*4281ad8eSSimon Glass >>> bsettings.Setup() 191*4281ad8eSSimon Glass >>> tcs = Toolchains() 192*4281ad8eSSimon Glass >>> tcs.Add('fred', False) 193*4281ad8eSSimon Glass >>> var_dict = {'oblique' : 'OBLIQUE', 'first' : 'fi${second}rst', \ 194*4281ad8eSSimon Glass 'second' : '2nd'} 195*4281ad8eSSimon Glass >>> tcs.ResolveReferences(var_dict, 'this=${oblique}_set') 196*4281ad8eSSimon Glass 'this=OBLIQUE_set' 197*4281ad8eSSimon Glass >>> tcs.ResolveReferences(var_dict, 'this=${oblique}_set${first}nd') 198*4281ad8eSSimon Glass 'this=OBLIQUE_setfi2ndrstnd' 199*4281ad8eSSimon Glass """ 200*4281ad8eSSimon Glass re_var = re.compile('(\$\{[a-z0-9A-Z]{1,}\})') 201*4281ad8eSSimon Glass 202*4281ad8eSSimon Glass while True: 203*4281ad8eSSimon Glass m = re_var.search(args) 204*4281ad8eSSimon Glass if not m: 205*4281ad8eSSimon Glass break 206*4281ad8eSSimon Glass lookup = m.group(0)[2:-1] 207*4281ad8eSSimon Glass value = var_dict.get(lookup, '') 208*4281ad8eSSimon Glass args = args[:m.start(0)] + value + args[m.end(0):] 209*4281ad8eSSimon Glass return args 210*4281ad8eSSimon Glass 211*4281ad8eSSimon Glass def GetMakeArguments(self, board): 212*4281ad8eSSimon Glass """Returns 'make' arguments for a given board 213*4281ad8eSSimon Glass 214*4281ad8eSSimon Glass The flags are in a section called 'make-flags'. Flags are named 215*4281ad8eSSimon Glass after the target they represent, for example snapper9260=TESTING=1 216*4281ad8eSSimon Glass will pass TESTING=1 to make when building the snapper9260 board. 217*4281ad8eSSimon Glass 218*4281ad8eSSimon Glass References to other boards can be added in the string also. For 219*4281ad8eSSimon Glass example: 220*4281ad8eSSimon Glass 221*4281ad8eSSimon Glass [make-flags] 222*4281ad8eSSimon Glass at91-boards=ENABLE_AT91_TEST=1 223*4281ad8eSSimon Glass snapper9260=${at91-boards} BUILD_TAG=442 224*4281ad8eSSimon Glass snapper9g45=${at91-boards} BUILD_TAG=443 225*4281ad8eSSimon Glass 226*4281ad8eSSimon Glass This will return 'ENABLE_AT91_TEST=1 BUILD_TAG=442' for snapper9260 227*4281ad8eSSimon Glass and 'ENABLE_AT91_TEST=1 BUILD_TAG=443' for snapper9g45. 228*4281ad8eSSimon Glass 229*4281ad8eSSimon Glass A special 'target' variable is set to the board target. 230*4281ad8eSSimon Glass 231*4281ad8eSSimon Glass Args: 232*4281ad8eSSimon Glass board: Board object for the board to check. 233*4281ad8eSSimon Glass Returns: 234*4281ad8eSSimon Glass 'make' flags for that board, or '' if none 235*4281ad8eSSimon Glass """ 236*4281ad8eSSimon Glass self._make_flags['target'] = board.target 237*4281ad8eSSimon Glass arg_str = self.ResolveReferences(self._make_flags, 238*4281ad8eSSimon Glass self._make_flags.get(board.target, '')) 239*4281ad8eSSimon Glass args = arg_str.split(' ') 240*4281ad8eSSimon Glass i = 0 241*4281ad8eSSimon Glass while i < len(args): 242*4281ad8eSSimon Glass if not args[i]: 243*4281ad8eSSimon Glass del args[i] 244*4281ad8eSSimon Glass else: 245*4281ad8eSSimon Glass i += 1 246*4281ad8eSSimon Glass return args 247