1# Copyright (c) 2012 The Chromium OS Authors. 2# 3# SPDX-License-Identifier: GPL-2.0+ 4# 5 6import glob 7import os 8 9import bsettings 10import command 11 12class Toolchain: 13 """A single toolchain 14 15 Public members: 16 gcc: Full path to C compiler 17 path: Directory path containing C compiler 18 cross: Cross compile string, e.g. 'arm-linux-' 19 arch: Architecture of toolchain as determined from the first 20 component of the filename. E.g. arm-linux-gcc becomes arm 21 """ 22 23 def __init__(self, fname, test, verbose=False): 24 """Create a new toolchain object. 25 26 Args: 27 fname: Filename of the gcc component 28 test: True to run the toolchain to test it 29 """ 30 self.gcc = fname 31 self.path = os.path.dirname(fname) 32 self.cross = os.path.basename(fname)[:-3] 33 pos = self.cross.find('-') 34 self.arch = self.cross[:pos] if pos != -1 else 'sandbox' 35 36 env = self.MakeEnvironment() 37 38 # As a basic sanity check, run the C compiler with --version 39 cmd = [fname, '--version'] 40 if test: 41 result = command.RunPipe([cmd], capture=True, env=env) 42 self.ok = result.return_code == 0 43 if verbose: 44 print 'Tool chain test: ', 45 if self.ok: 46 print 'OK' 47 else: 48 print 'BAD' 49 print 'Command: ', cmd 50 print result.stdout 51 print result.stderr 52 else: 53 self.ok = True 54 self.priority = self.GetPriority(fname) 55 56 def GetPriority(self, fname): 57 """Return the priority of the toolchain. 58 59 Toolchains are ranked according to their suitability by their 60 filename prefix. 61 62 Args: 63 fname: Filename of toolchain 64 Returns: 65 Priority of toolchain, 0=highest, 20=lowest. 66 """ 67 priority_list = ['-elf', '-unknown-linux-gnu', '-linux', '-elf', 68 '-none-linux-gnueabi', '-uclinux', '-none-eabi', 69 '-gentoo-linux-gnu', '-linux-gnueabi', '-le-linux', '-uclinux'] 70 for prio in range(len(priority_list)): 71 if priority_list[prio] in fname: 72 return prio 73 return prio 74 75 def MakeEnvironment(self): 76 """Returns an environment for using the toolchain. 77 78 Thie takes the current environment, adds CROSS_COMPILE and 79 augments PATH so that the toolchain will operate correctly. 80 """ 81 env = dict(os.environ) 82 env['CROSS_COMPILE'] = self.cross 83 env['PATH'] += (':' + self.path) 84 return env 85 86 87class Toolchains: 88 """Manage a list of toolchains for building U-Boot 89 90 We select one toolchain for each architecture type 91 92 Public members: 93 toolchains: Dict of Toolchain objects, keyed by architecture name 94 paths: List of paths to check for toolchains (may contain wildcards) 95 """ 96 97 def __init__(self): 98 self.toolchains = {} 99 self.paths = [] 100 for name, value in bsettings.GetItems('toolchain'): 101 if '*' in value: 102 self.paths += glob.glob(value) 103 else: 104 self.paths.append(value) 105 106 107 def Add(self, fname, test=True, verbose=False): 108 """Add a toolchain to our list 109 110 We select the given toolchain as our preferred one for its 111 architecture if it is a higher priority than the others. 112 113 Args: 114 fname: Filename of toolchain's gcc driver 115 test: True to run the toolchain to test it 116 """ 117 toolchain = Toolchain(fname, test, verbose) 118 add_it = toolchain.ok 119 if toolchain.arch in self.toolchains: 120 add_it = (toolchain.priority < 121 self.toolchains[toolchain.arch].priority) 122 if add_it: 123 self.toolchains[toolchain.arch] = toolchain 124 125 def Scan(self, verbose): 126 """Scan for available toolchains and select the best for each arch. 127 128 We look for all the toolchains we can file, figure out the 129 architecture for each, and whether it works. Then we select the 130 highest priority toolchain for each arch. 131 132 Args: 133 verbose: True to print out progress information 134 """ 135 if verbose: print 'Scanning for tool chains' 136 for path in self.paths: 137 if verbose: print " - scanning path '%s'" % path 138 for subdir in ['.', 'bin', 'usr/bin']: 139 dirname = os.path.join(path, subdir) 140 if verbose: print " - looking in '%s'" % dirname 141 for fname in glob.glob(dirname + '/*gcc'): 142 if verbose: print " - found '%s'" % fname 143 self.Add(fname, True, verbose) 144 145 def List(self): 146 """List out the selected toolchains for each architecture""" 147 print 'List of available toolchains (%d):' % len(self.toolchains) 148 if len(self.toolchains): 149 for key, value in sorted(self.toolchains.iteritems()): 150 print '%-10s: %s' % (key, value.gcc) 151 else: 152 print 'None' 153 154 def Select(self, arch): 155 """Returns the toolchain for a given architecture 156 157 Args: 158 args: Name of architecture (e.g. 'arm', 'ppc_8xx') 159 160 returns: 161 toolchain object, or None if none found 162 """ 163 for name, value in bsettings.GetItems('toolchain-alias'): 164 if arch == name: 165 arch = value 166 167 if not arch in self.toolchains: 168 raise ValueError, ("No tool chain found for arch '%s'" % arch) 169 return self.toolchains[arch] 170