]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - tools/buildman/toolchain.py
Merge branch 'tom' of git://git.denx.de/u-boot-x86
[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         toolchains = bsettings.GetItems('toolchain')
103         if not toolchains:
104             print ("Warning: No tool chains - please add a [toolchain] section"
105                  " to your buildman config file %s. See README for details" %
106                  bsettings.config_fname)
107
108         for name, value in toolchains:
109             if '*' in value:
110                 self.paths += glob.glob(value)
111             else:
112                 self.paths.append(value)
113         self._make_flags = dict(bsettings.GetItems('make-flags'))
114
115     def Add(self, fname, test=True, verbose=False):
116         """Add a toolchain to our list
117
118         We select the given toolchain as our preferred one for its
119         architecture if it is a higher priority than the others.
120
121         Args:
122             fname: Filename of toolchain's gcc driver
123             test: True to run the toolchain to test it
124         """
125         toolchain = Toolchain(fname, test, verbose)
126         add_it = toolchain.ok
127         if toolchain.arch in self.toolchains:
128             add_it = (toolchain.priority <
129                         self.toolchains[toolchain.arch].priority)
130         if add_it:
131             self.toolchains[toolchain.arch] = toolchain
132
133     def Scan(self, verbose):
134         """Scan for available toolchains and select the best for each arch.
135
136         We look for all the toolchains we can file, figure out the
137         architecture for each, and whether it works. Then we select the
138         highest priority toolchain for each arch.
139
140         Args:
141             verbose: True to print out progress information
142         """
143         if verbose: print 'Scanning for tool chains'
144         for path in self.paths:
145             if verbose: print "   - scanning path '%s'" % path
146             for subdir in ['.', 'bin', 'usr/bin']:
147                 dirname = os.path.join(path, subdir)
148                 if verbose: print "      - looking in '%s'" % dirname
149                 for fname in glob.glob(dirname + '/*gcc'):
150                     if verbose: print "         - found '%s'" % fname
151                     self.Add(fname, True, verbose)
152
153     def List(self):
154         """List out the selected toolchains for each architecture"""
155         print 'List of available toolchains (%d):' % len(self.toolchains)
156         if len(self.toolchains):
157             for key, value in sorted(self.toolchains.iteritems()):
158                 print '%-10s: %s' % (key, value.gcc)
159         else:
160             print 'None'
161
162     def Select(self, arch):
163         """Returns the toolchain for a given architecture
164
165         Args:
166             args: Name of architecture (e.g. 'arm', 'ppc_8xx')
167
168         returns:
169             toolchain object, or None if none found
170         """
171         for name, value in bsettings.GetItems('toolchain-alias'):
172             if arch == name:
173                 arch = value
174
175         if not arch in self.toolchains:
176             raise ValueError, ("No tool chain found for arch '%s'" % arch)
177         return self.toolchains[arch]
178
179     def ResolveReferences(self, var_dict, args):
180         """Resolve variable references in a string
181
182         This converts ${blah} within the string to the value of blah.
183         This function works recursively.
184
185         Args:
186             var_dict: Dictionary containing variables and their values
187             args: String containing make arguments
188         Returns:
189             Resolved string
190
191         >>> bsettings.Setup()
192         >>> tcs = Toolchains()
193         >>> tcs.Add('fred', False)
194         >>> var_dict = {'oblique' : 'OBLIQUE', 'first' : 'fi${second}rst', \
195                         'second' : '2nd'}
196         >>> tcs.ResolveReferences(var_dict, 'this=${oblique}_set')
197         'this=OBLIQUE_set'
198         >>> tcs.ResolveReferences(var_dict, 'this=${oblique}_set${first}nd')
199         'this=OBLIQUE_setfi2ndrstnd'
200         """
201         re_var = re.compile('(\$\{[a-z0-9A-Z]{1,}\})')
202
203         while True:
204             m = re_var.search(args)
205             if not m:
206                 break
207             lookup = m.group(0)[2:-1]
208             value = var_dict.get(lookup, '')
209             args = args[:m.start(0)] + value + args[m.end(0):]
210         return args
211
212     def GetMakeArguments(self, board):
213         """Returns 'make' arguments for a given board
214
215         The flags are in a section called 'make-flags'. Flags are named
216         after the target they represent, for example snapper9260=TESTING=1
217         will pass TESTING=1 to make when building the snapper9260 board.
218
219         References to other boards can be added in the string also. For
220         example:
221
222         [make-flags]
223         at91-boards=ENABLE_AT91_TEST=1
224         snapper9260=${at91-boards} BUILD_TAG=442
225         snapper9g45=${at91-boards} BUILD_TAG=443
226
227         This will return 'ENABLE_AT91_TEST=1 BUILD_TAG=442' for snapper9260
228         and 'ENABLE_AT91_TEST=1 BUILD_TAG=443' for snapper9g45.
229
230         A special 'target' variable is set to the board target.
231
232         Args:
233             board: Board object for the board to check.
234         Returns:
235             'make' flags for that board, or '' if none
236         """
237         self._make_flags['target'] = board.target
238         arg_str = self.ResolveReferences(self._make_flags,
239                            self._make_flags.get(board.target, ''))
240         args = arg_str.split(' ')
241         i = 0
242         while i < len(args):
243             if not args[i]:
244                 del args[i]
245             else:
246                 i += 1
247         return args