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)
34 # Find the CROSS_COMPILE prefix to use for U-Boot. For example,
35 # 'arm-linux-gnueabihf-gcc' turns into 'arm-linux-gnueabihf-'.
36 basename = os.path.basename(fname)
37 pos = basename.rfind('-')
38 self.cross = basename[:pos + 1] if pos != -1 else ''
40 # The architecture is the first part of the name
41 pos = self.cross.find('-')
42 self.arch = self.cross[:pos] if pos != -1 else 'sandbox'
44 env = self.MakeEnvironment(False)
46 # As a basic sanity check, run the C compiler with --version
47 cmd = [fname, '--version']
49 result = command.RunPipe([cmd], capture=True, env=env,
51 self.ok = result.return_code == 0
53 print 'Tool chain test: ',
58 print 'Command: ', cmd
63 self.priority = self.GetPriority(fname)
65 def GetPriority(self, fname):
66 """Return the priority of the toolchain.
68 Toolchains are ranked according to their suitability by their
72 fname: Filename of toolchain
74 Priority of toolchain, 0=highest, 20=lowest.
76 priority_list = ['-elf', '-unknown-linux-gnu', '-linux',
77 '-none-linux-gnueabi', '-uclinux', '-none-eabi',
78 '-gentoo-linux-gnu', '-linux-gnueabi', '-le-linux', '-uclinux']
79 for prio in range(len(priority_list)):
80 if priority_list[prio] in fname:
84 def MakeEnvironment(self, full_path):
85 """Returns an environment for using the toolchain.
87 Thie takes the current environment and adds CROSS_COMPILE so that
88 the tool chain will operate correctly.
91 full_path: Return the full path in CROSS_COMPILE and don't set
94 env = dict(os.environ)
96 env['CROSS_COMPILE'] = os.path.join(self.path, self.cross)
98 env['CROSS_COMPILE'] = self.cross
99 env['PATH'] = self.path + ':' + env['PATH']
105 """Manage a list of toolchains for building U-Boot
107 We select one toolchain for each architecture type
110 toolchains: Dict of Toolchain objects, keyed by architecture name
111 paths: List of paths to check for toolchains (may contain wildcards)
117 self._make_flags = dict(bsettings.GetItems('make-flags'))
119 def GetSettings(self):
120 toolchains = bsettings.GetItems('toolchain')
122 print ("Warning: No tool chains - please add a [toolchain] section"
123 " to your buildman config file %s. See README for details" %
124 bsettings.config_fname)
126 for name, value in toolchains:
128 self.paths += glob.glob(value)
130 self.paths.append(value)
132 def Add(self, fname, test=True, verbose=False):
133 """Add a toolchain to our list
135 We select the given toolchain as our preferred one for its
136 architecture if it is a higher priority than the others.
139 fname: Filename of toolchain's gcc driver
140 test: True to run the toolchain to test it
142 toolchain = Toolchain(fname, test, verbose)
143 add_it = toolchain.ok
144 if toolchain.arch in self.toolchains:
145 add_it = (toolchain.priority <
146 self.toolchains[toolchain.arch].priority)
148 self.toolchains[toolchain.arch] = toolchain
150 def Scan(self, verbose):
151 """Scan for available toolchains and select the best for each arch.
153 We look for all the toolchains we can file, figure out the
154 architecture for each, and whether it works. Then we select the
155 highest priority toolchain for each arch.
158 verbose: True to print out progress information
160 if verbose: print 'Scanning for tool chains'
161 for path in self.paths:
162 if verbose: print " - scanning path '%s'" % path
163 for subdir in ['.', 'bin', 'usr/bin']:
164 dirname = os.path.join(path, subdir)
165 if verbose: print " - looking in '%s'" % dirname
166 for fname in glob.glob(dirname + '/*gcc'):
167 if verbose: print " - found '%s'" % fname
168 self.Add(fname, True, verbose)
171 """List out the selected toolchains for each architecture"""
172 print 'List of available toolchains (%d):' % len(self.toolchains)
173 if len(self.toolchains):
174 for key, value in sorted(self.toolchains.iteritems()):
175 print '%-10s: %s' % (key, value.gcc)
179 def Select(self, arch):
180 """Returns the toolchain for a given architecture
183 args: Name of architecture (e.g. 'arm', 'ppc_8xx')
186 toolchain object, or None if none found
188 for tag, value in bsettings.GetItems('toolchain-alias'):
190 for alias in value.split():
191 if alias in self.toolchains:
192 return self.toolchains[alias]
194 if not arch in self.toolchains:
195 raise ValueError, ("No tool chain found for arch '%s'" % arch)
196 return self.toolchains[arch]
198 def ResolveReferences(self, var_dict, args):
199 """Resolve variable references in a string
201 This converts ${blah} within the string to the value of blah.
202 This function works recursively.
205 var_dict: Dictionary containing variables and their values
206 args: String containing make arguments
210 >>> bsettings.Setup()
211 >>> tcs = Toolchains()
212 >>> tcs.Add('fred', False)
213 >>> var_dict = {'oblique' : 'OBLIQUE', 'first' : 'fi${second}rst', \
215 >>> tcs.ResolveReferences(var_dict, 'this=${oblique}_set')
217 >>> tcs.ResolveReferences(var_dict, 'this=${oblique}_set${first}nd')
218 'this=OBLIQUE_setfi2ndrstnd'
220 re_var = re.compile('(\$\{[-_a-z0-9A-Z]{1,}\})')
223 m = re_var.search(args)
226 lookup = m.group(0)[2:-1]
227 value = var_dict.get(lookup, '')
228 args = args[:m.start(0)] + value + args[m.end(0):]
231 def GetMakeArguments(self, board):
232 """Returns 'make' arguments for a given board
234 The flags are in a section called 'make-flags'. Flags are named
235 after the target they represent, for example snapper9260=TESTING=1
236 will pass TESTING=1 to make when building the snapper9260 board.
238 References to other boards can be added in the string also. For
242 at91-boards=ENABLE_AT91_TEST=1
243 snapper9260=${at91-boards} BUILD_TAG=442
244 snapper9g45=${at91-boards} BUILD_TAG=443
246 This will return 'ENABLE_AT91_TEST=1 BUILD_TAG=442' for snapper9260
247 and 'ENABLE_AT91_TEST=1 BUILD_TAG=443' for snapper9g45.
249 A special 'target' variable is set to the board target.
252 board: Board object for the board to check.
254 'make' flags for that board, or '' if none
256 self._make_flags['target'] = board.target
257 arg_str = self.ResolveReferences(self._make_flags,
258 self._make_flags.get(board.target, ''))
259 args = arg_str.split(' ')