blob: dfa1d00ce27a3d58dcb9eb2bce1d7c666e01c740 [file] [log] [blame]
Simon Glassfc3fe1c2013-04-03 11:07:16 +00001# Copyright (c) 2012 The Chromium OS Authors.
2#
Wolfgang Denk1a459662013-07-08 09:37:19 +02003# SPDX-License-Identifier: GPL-2.0+
Simon Glassfc3fe1c2013-04-03 11:07:16 +00004#
5
6import glob
7import os
8
9import bsettings
10import command
11
12class Toolchain:
13 """A single toolchain
14
15 Public members:
16 gcc: Full path to C compiler
17 path: Directory path containing C compiler
18 cross: Cross compile string, e.g. 'arm-linux-'
19 arch: Architecture of toolchain as determined from the first
20 component of the filename. E.g. arm-linux-gcc becomes arm
21 """
22
23 def __init__(self, fname, test, verbose=False):
24 """Create a new toolchain object.
25
26 Args:
27 fname: Filename of the gcc component
28 test: True to run the toolchain to test it
29 """
30 self.gcc = fname
31 self.path = os.path.dirname(fname)
32 self.cross = os.path.basename(fname)[:-3]
33 pos = self.cross.find('-')
34 self.arch = self.cross[:pos] if pos != -1 else 'sandbox'
35
36 env = self.MakeEnvironment()
37
38 # As a basic sanity check, run the C compiler with --version
39 cmd = [fname, '--version']
40 if test:
41 result = command.RunPipe([cmd], capture=True, env=env)
42 self.ok = result.return_code == 0
43 if verbose:
44 print 'Tool chain test: ',
45 if self.ok:
46 print 'OK'
47 else:
48 print 'BAD'
49 print 'Command: ', cmd
50 print result.stdout
51 print result.stderr
52 else:
53 self.ok = True
54 self.priority = self.GetPriority(fname)
55
56 def GetPriority(self, fname):
57 """Return the priority of the toolchain.
58
59 Toolchains are ranked according to their suitability by their
60 filename prefix.
61
62 Args:
63 fname: Filename of toolchain
64 Returns:
65 Priority of toolchain, 0=highest, 20=lowest.
66 """
67 priority_list = ['-elf', '-unknown-linux-gnu', '-linux', '-elf',
68 '-none-linux-gnueabi', '-uclinux', '-none-eabi',
69 '-gentoo-linux-gnu', '-linux-gnueabi', '-le-linux', '-uclinux']
70 for prio in range(len(priority_list)):
71 if priority_list[prio] in fname:
72 return prio
73 return prio
74
75 def MakeEnvironment(self):
76 """Returns an environment for using the toolchain.
77
78 Thie takes the current environment, adds CROSS_COMPILE and
79 augments PATH so that the toolchain will operate correctly.
80 """
81 env = dict(os.environ)
82 env['CROSS_COMPILE'] = self.cross
83 env['PATH'] += (':' + self.path)
84 return env
85
86
87class Toolchains:
88 """Manage a list of toolchains for building U-Boot
89
90 We select one toolchain for each architecture type
91
92 Public members:
93 toolchains: Dict of Toolchain objects, keyed by architecture name
94 paths: List of paths to check for toolchains (may contain wildcards)
95 """
96
97 def __init__(self):
98 self.toolchains = {}
99 self.paths = []
100 for name, value in bsettings.GetItems('toolchain'):
101 if '*' in value:
102 self.paths += glob.glob(value)
103 else:
104 self.paths.append(value)
105
106
107 def Add(self, fname, test=True, verbose=False):
108 """Add a toolchain to our list
109
110 We select the given toolchain as our preferred one for its
111 architecture if it is a higher priority than the others.
112
113 Args:
114 fname: Filename of toolchain's gcc driver
115 test: True to run the toolchain to test it
116 """
117 toolchain = Toolchain(fname, test, verbose)
118 add_it = toolchain.ok
119 if toolchain.arch in self.toolchains:
120 add_it = (toolchain.priority <
121 self.toolchains[toolchain.arch].priority)
122 if add_it:
123 self.toolchains[toolchain.arch] = toolchain
124
125 def Scan(self, verbose):
126 """Scan for available toolchains and select the best for each arch.
127
128 We look for all the toolchains we can file, figure out the
129 architecture for each, and whether it works. Then we select the
130 highest priority toolchain for each arch.
131
132 Args:
133 verbose: True to print out progress information
134 """
135 if verbose: print 'Scanning for tool chains'
136 for path in self.paths:
137 if verbose: print " - scanning path '%s'" % path
138 for subdir in ['.', 'bin', 'usr/bin']:
139 dirname = os.path.join(path, subdir)
140 if verbose: print " - looking in '%s'" % dirname
141 for fname in glob.glob(dirname + '/*gcc'):
142 if verbose: print " - found '%s'" % fname
143 self.Add(fname, True, verbose)
144
145 def List(self):
146 """List out the selected toolchains for each architecture"""
147 print 'List of available toolchains (%d):' % len(self.toolchains)
148 if len(self.toolchains):
149 for key, value in sorted(self.toolchains.iteritems()):
150 print '%-10s: %s' % (key, value.gcc)
151 else:
152 print 'None'
153
154 def Select(self, arch):
155 """Returns the toolchain for a given architecture
156
157 Args:
158 args: Name of architecture (e.g. 'arm', 'ppc_8xx')
159
160 returns:
161 toolchain object, or None if none found
162 """
163 for name, value in bsettings.GetItems('toolchain-alias'):
164 if arch == name:
165 arch = value
166
167 if not arch in self.toolchains:
168 raise ValueError, ("No tool chain found for arch '%s'" % arch)
169 return self.toolchains[arch]