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