blob: e0a697037ee18c341d639488497411e1fb8f60a8 [file] [log] [blame]
Simon Glassfc3fe1c2013-04-03 11:07:16 +00001# 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]