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