]>
Commit | Line | Data |
---|---|---|
fc3fe1c2 SG |
1 | # Copyright (c) 2012 The Chromium OS Authors. |
2 | # | |
1a459660 | 3 | # SPDX-License-Identifier: GPL-2.0+ |
fc3fe1c2 SG |
4 | # |
5 | ||
6 | import glob | |
7 | import os | |
8 | ||
9 | import bsettings | |
10 | import command | |
11 | ||
12 | class 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 | ||
87 | class 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] |