xref: /openbmc/u-boot/tools/buildman/toolchain.py (revision 03efcb05)
1# Copyright (c) 2012 The Chromium OS Authors.
2#
3# SPDX-License-Identifier:	GPL-2.0+
4#
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]
170