1 # Copyright (c) 2012 The Chromium OS Authors.
3 # SPDX-License-Identifier: GPL-2.0+
17 gcc: Full path to C compiler
18 path: Directory path containing C compiler
19 cross: Cross compile string, e.g. 'arm-linux-'
20 arch: Architecture of toolchain as determined from the first
21 component of the filename. E.g. arm-linux-gcc becomes arm
24 def __init__(self, fname, test, verbose=False):
25 """Create a new toolchain object.
28 fname: Filename of the gcc component
29 test: True to run the toolchain to test it
32 self.path = os.path.dirname(fname)
33 self.cross = os.path.basename(fname)[:-3]
34 pos = self.cross.find('-')
35 self.arch = self.cross[:pos] if pos != -1 else 'sandbox'
37 env = self.MakeEnvironment()
39 # As a basic sanity check, run the C compiler with --version
40 cmd = [fname, '--version']
42 result = command.RunPipe([cmd], capture=True, env=env,
44 self.ok = result.return_code == 0
46 print 'Tool chain test: ',
51 print 'Command: ', cmd
56 self.priority = self.GetPriority(fname)
58 def GetPriority(self, fname):
59 """Return the priority of the toolchain.
61 Toolchains are ranked according to their suitability by their
65 fname: Filename of toolchain
67 Priority of toolchain, 0=highest, 20=lowest.
69 priority_list = ['-elf', '-unknown-linux-gnu', '-linux',
70 '-none-linux-gnueabi', '-uclinux', '-none-eabi',
71 '-gentoo-linux-gnu', '-linux-gnueabi', '-le-linux', '-uclinux']
72 for prio in range(len(priority_list)):
73 if priority_list[prio] in fname:
77 def MakeEnvironment(self):
78 """Returns an environment for using the toolchain.
80 Thie takes the current environment, adds CROSS_COMPILE and
81 augments PATH so that the toolchain will operate correctly.
83 env = dict(os.environ)
84 env['CROSS_COMPILE'] = self.cross
85 env['PATH'] += (':' + self.path)
90 """Manage a list of toolchains for building U-Boot
92 We select one toolchain for each architecture type
95 toolchains: Dict of Toolchain objects, keyed by architecture name
96 paths: List of paths to check for toolchains (may contain wildcards)
102 self._make_flags = dict(bsettings.GetItems('make-flags'))
104 def GetSettings(self):
105 toolchains = bsettings.GetItems('toolchain')
107 print ("Warning: No tool chains - please add a [toolchain] section"
108 " to your buildman config file %s. See README for details" %
109 bsettings.config_fname)
111 for name, value in toolchains:
113 self.paths += glob.glob(value)
115 self.paths.append(value)
117 def Add(self, fname, test=True, verbose=False):
118 """Add a toolchain to our list
120 We select the given toolchain as our preferred one for its
121 architecture if it is a higher priority than the others.
124 fname: Filename of toolchain's gcc driver
125 test: True to run the toolchain to test it
127 toolchain = Toolchain(fname, test, verbose)
128 add_it = toolchain.ok
129 if toolchain.arch in self.toolchains:
130 add_it = (toolchain.priority <
131 self.toolchains[toolchain.arch].priority)
133 self.toolchains[toolchain.arch] = toolchain
135 def Scan(self, verbose):
136 """Scan for available toolchains and select the best for each arch.
138 We look for all the toolchains we can file, figure out the
139 architecture for each, and whether it works. Then we select the
140 highest priority toolchain for each arch.
143 verbose: True to print out progress information
145 if verbose: print 'Scanning for tool chains'
146 for path in self.paths:
147 if verbose: print " - scanning path '%s'" % path
148 for subdir in ['.', 'bin', 'usr/bin']:
149 dirname = os.path.join(path, subdir)
150 if verbose: print " - looking in '%s'" % dirname
151 for fname in glob.glob(dirname + '/*gcc'):
152 if verbose: print " - found '%s'" % fname
153 self.Add(fname, True, verbose)
156 """List out the selected toolchains for each architecture"""
157 print 'List of available toolchains (%d):' % len(self.toolchains)
158 if len(self.toolchains):
159 for key, value in sorted(self.toolchains.iteritems()):
160 print '%-10s: %s' % (key, value.gcc)
164 def Select(self, arch):
165 """Returns the toolchain for a given architecture
168 args: Name of architecture (e.g. 'arm', 'ppc_8xx')
171 toolchain object, or None if none found
173 for name, value in bsettings.GetItems('toolchain-alias'):
177 if not arch in self.toolchains:
178 raise ValueError, ("No tool chain found for arch '%s'" % arch)
179 return self.toolchains[arch]
181 def ResolveReferences(self, var_dict, args):
182 """Resolve variable references in a string
184 This converts ${blah} within the string to the value of blah.
185 This function works recursively.
188 var_dict: Dictionary containing variables and their values
189 args: String containing make arguments
193 >>> bsettings.Setup()
194 >>> tcs = Toolchains()
195 >>> tcs.Add('fred', False)
196 >>> var_dict = {'oblique' : 'OBLIQUE', 'first' : 'fi${second}rst', \
198 >>> tcs.ResolveReferences(var_dict, 'this=${oblique}_set')
200 >>> tcs.ResolveReferences(var_dict, 'this=${oblique}_set${first}nd')
201 'this=OBLIQUE_setfi2ndrstnd'
203 re_var = re.compile('(\$\{[-_a-z0-9A-Z]{1,}\})')
206 m = re_var.search(args)
209 lookup = m.group(0)[2:-1]
210 value = var_dict.get(lookup, '')
211 args = args[:m.start(0)] + value + args[m.end(0):]
214 def GetMakeArguments(self, board):
215 """Returns 'make' arguments for a given board
217 The flags are in a section called 'make-flags'. Flags are named
218 after the target they represent, for example snapper9260=TESTING=1
219 will pass TESTING=1 to make when building the snapper9260 board.
221 References to other boards can be added in the string also. For
225 at91-boards=ENABLE_AT91_TEST=1
226 snapper9260=${at91-boards} BUILD_TAG=442
227 snapper9g45=${at91-boards} BUILD_TAG=443
229 This will return 'ENABLE_AT91_TEST=1 BUILD_TAG=442' for snapper9260
230 and 'ENABLE_AT91_TEST=1 BUILD_TAG=443' for snapper9g45.
232 A special 'target' variable is set to the board target.
235 board: Board object for the board to check.
237 'make' flags for that board, or '' if none
239 self._make_flags['target'] = board.target
240 arg_str = self.ResolveReferences(self._make_flags,
241 self._make_flags.get(board.target, ''))
242 args = arg_str.split(' ')