]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - tools/buildman/toolchain.py
Merge branch 'master' of git://git.denx.de/u-boot-arm
[karo-tx-uboot.git] / tools / buildman / toolchain.py
1 # Copyright (c) 2012 The Chromium OS Authors.
2 #
3 # SPDX-License-Identifier:      GPL-2.0+
4 #
5
6 import re
7 import glob
8 import os
9
10 import bsettings
11 import command
12
13 class Toolchain:
14     """A single toolchain
15
16     Public members:
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
22     """
23
24     def __init__(self, fname, test, verbose=False):
25         """Create a new toolchain object.
26
27         Args:
28             fname: Filename of the gcc component
29             test: True to run the toolchain to test it
30         """
31         self.gcc = fname
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'
36
37         env = self.MakeEnvironment()
38
39         # As a basic sanity check, run the C compiler with --version
40         cmd = [fname, '--version']
41         if test:
42             result = command.RunPipe([cmd], capture=True, env=env,
43                                      raise_on_error=False)
44             self.ok = result.return_code == 0
45             if verbose:
46                 print 'Tool chain test: ',
47                 if self.ok:
48                     print 'OK'
49                 else:
50                     print 'BAD'
51                     print 'Command: ', cmd
52                     print result.stdout
53                     print result.stderr
54         else:
55             self.ok = True
56         self.priority = self.GetPriority(fname)
57
58     def GetPriority(self, fname):
59         """Return the priority of the toolchain.
60
61         Toolchains are ranked according to their suitability by their
62         filename prefix.
63
64         Args:
65             fname: Filename of toolchain
66         Returns:
67             Priority of toolchain, 0=highest, 20=lowest.
68         """
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:
74                 return prio
75         return prio
76
77     def MakeEnvironment(self):
78         """Returns an environment for using the toolchain.
79
80         Thie takes the current environment, adds CROSS_COMPILE and
81         augments PATH so that the toolchain will operate correctly.
82         """
83         env = dict(os.environ)
84         env['CROSS_COMPILE'] = self.cross
85         env['PATH'] += (':' + self.path)
86         return env
87
88
89 class Toolchains:
90     """Manage a list of toolchains for building U-Boot
91
92     We select one toolchain for each architecture type
93
94     Public members:
95         toolchains: Dict of Toolchain objects, keyed by architecture name
96         paths: List of paths to check for toolchains (may contain wildcards)
97     """
98
99     def __init__(self):
100         self.toolchains = {}
101         self.paths = []
102         self._make_flags = dict(bsettings.GetItems('make-flags'))
103
104     def GetSettings(self):
105         toolchains = bsettings.GetItems('toolchain')
106         if not toolchains:
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)
110
111         for name, value in toolchains:
112             if '*' in value:
113                 self.paths += glob.glob(value)
114             else:
115                 self.paths.append(value)
116
117     def Add(self, fname, test=True, verbose=False):
118         """Add a toolchain to our list
119
120         We select the given toolchain as our preferred one for its
121         architecture if it is a higher priority than the others.
122
123         Args:
124             fname: Filename of toolchain's gcc driver
125             test: True to run the toolchain to test it
126         """
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)
132         if add_it:
133             self.toolchains[toolchain.arch] = toolchain
134
135     def Scan(self, verbose):
136         """Scan for available toolchains and select the best for each arch.
137
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.
141
142         Args:
143             verbose: True to print out progress information
144         """
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)
154
155     def List(self):
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)
161         else:
162             print 'None'
163
164     def Select(self, arch):
165         """Returns the toolchain for a given architecture
166
167         Args:
168             args: Name of architecture (e.g. 'arm', 'ppc_8xx')
169
170         returns:
171             toolchain object, or None if none found
172         """
173         for name, value in bsettings.GetItems('toolchain-alias'):
174             if arch == name:
175                 arch = value
176
177         if not arch in self.toolchains:
178             raise ValueError, ("No tool chain found for arch '%s'" % arch)
179         return self.toolchains[arch]
180
181     def ResolveReferences(self, var_dict, args):
182         """Resolve variable references in a string
183
184         This converts ${blah} within the string to the value of blah.
185         This function works recursively.
186
187         Args:
188             var_dict: Dictionary containing variables and their values
189             args: String containing make arguments
190         Returns:
191             Resolved string
192
193         >>> bsettings.Setup()
194         >>> tcs = Toolchains()
195         >>> tcs.Add('fred', False)
196         >>> var_dict = {'oblique' : 'OBLIQUE', 'first' : 'fi${second}rst', \
197                         'second' : '2nd'}
198         >>> tcs.ResolveReferences(var_dict, 'this=${oblique}_set')
199         'this=OBLIQUE_set'
200         >>> tcs.ResolveReferences(var_dict, 'this=${oblique}_set${first}nd')
201         'this=OBLIQUE_setfi2ndrstnd'
202         """
203         re_var = re.compile('(\$\{[-_a-z0-9A-Z]{1,}\})')
204
205         while True:
206             m = re_var.search(args)
207             if not m:
208                 break
209             lookup = m.group(0)[2:-1]
210             value = var_dict.get(lookup, '')
211             args = args[:m.start(0)] + value + args[m.end(0):]
212         return args
213
214     def GetMakeArguments(self, board):
215         """Returns 'make' arguments for a given board
216
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.
220
221         References to other boards can be added in the string also. For
222         example:
223
224         [make-flags]
225         at91-boards=ENABLE_AT91_TEST=1
226         snapper9260=${at91-boards} BUILD_TAG=442
227         snapper9g45=${at91-boards} BUILD_TAG=443
228
229         This will return 'ENABLE_AT91_TEST=1 BUILD_TAG=442' for snapper9260
230         and 'ENABLE_AT91_TEST=1 BUILD_TAG=443' for snapper9g45.
231
232         A special 'target' variable is set to the board target.
233
234         Args:
235             board: Board object for the board to check.
236         Returns:
237             'make' flags for that board, or '' if none
238         """
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(' ')
243         i = 0
244         while i < len(args):
245             if not args[i]:
246                 del args[i]
247             else:
248                 i += 1
249         return args