xref: /rk3399_rockchip-uboot/tools/buildman/toolchain.py (revision f210b58734b750fcab3d4fef6477a6eaf39b5d51)
1fc3fe1c2SSimon Glass# Copyright (c) 2012 The Chromium OS Authors.
2fc3fe1c2SSimon Glass#
31a459660SWolfgang Denk# SPDX-License-Identifier:	GPL-2.0+
4fc3fe1c2SSimon Glass#
5fc3fe1c2SSimon Glass
64281ad8eSSimon Glassimport re
7fc3fe1c2SSimon Glassimport glob
8fc3fe1c2SSimon Glassimport os
9fc3fe1c2SSimon Glass
10fc3fe1c2SSimon Glassimport bsettings
11fc3fe1c2SSimon Glassimport command
12fc3fe1c2SSimon Glass
13fc3fe1c2SSimon Glassclass Toolchain:
14fc3fe1c2SSimon Glass    """A single toolchain
15fc3fe1c2SSimon Glass
16fc3fe1c2SSimon Glass    Public members:
17fc3fe1c2SSimon Glass        gcc: Full path to C compiler
18fc3fe1c2SSimon Glass        path: Directory path containing C compiler
19fc3fe1c2SSimon Glass        cross: Cross compile string, e.g. 'arm-linux-'
20fc3fe1c2SSimon Glass        arch: Architecture of toolchain as determined from the first
21fc3fe1c2SSimon Glass                component of the filename. E.g. arm-linux-gcc becomes arm
22fc3fe1c2SSimon Glass    """
23fc3fe1c2SSimon Glass
24fc3fe1c2SSimon Glass    def __init__(self, fname, test, verbose=False):
25fc3fe1c2SSimon Glass        """Create a new toolchain object.
26fc3fe1c2SSimon Glass
27fc3fe1c2SSimon Glass        Args:
28fc3fe1c2SSimon Glass            fname: Filename of the gcc component
29fc3fe1c2SSimon Glass            test: True to run the toolchain to test it
30fc3fe1c2SSimon Glass        """
31fc3fe1c2SSimon Glass        self.gcc = fname
32fc3fe1c2SSimon Glass        self.path = os.path.dirname(fname)
33b5324123SSimon Glass
34b5324123SSimon Glass        # Find the CROSS_COMPILE prefix to use for U-Boot. For example,
35b5324123SSimon Glass        # 'arm-linux-gnueabihf-gcc' turns into 'arm-linux-gnueabihf-'.
36b5324123SSimon Glass        basename = os.path.basename(fname)
37b5324123SSimon Glass        pos = basename.rfind('-')
38b5324123SSimon Glass        self.cross = basename[:pos + 1] if pos != -1 else ''
39b5324123SSimon Glass
40b5324123SSimon Glass        # The architecture is the first part of the name
41fc3fe1c2SSimon Glass        pos = self.cross.find('-')
42fc3fe1c2SSimon Glass        self.arch = self.cross[:pos] if pos != -1 else 'sandbox'
43fc3fe1c2SSimon Glass
44fc3fe1c2SSimon Glass        env = self.MakeEnvironment()
45fc3fe1c2SSimon Glass
46fc3fe1c2SSimon Glass        # As a basic sanity check, run the C compiler with --version
47fc3fe1c2SSimon Glass        cmd = [fname, '--version']
48fc3fe1c2SSimon Glass        if test:
498bb2bddcSStephen Warren            result = command.RunPipe([cmd], capture=True, env=env,
508bb2bddcSStephen Warren                                     raise_on_error=False)
51fc3fe1c2SSimon Glass            self.ok = result.return_code == 0
52fc3fe1c2SSimon Glass            if verbose:
53fc3fe1c2SSimon Glass                print 'Tool chain test: ',
54fc3fe1c2SSimon Glass                if self.ok:
55fc3fe1c2SSimon Glass                    print 'OK'
56fc3fe1c2SSimon Glass                else:
57fc3fe1c2SSimon Glass                    print 'BAD'
58fc3fe1c2SSimon Glass                    print 'Command: ', cmd
59fc3fe1c2SSimon Glass                    print result.stdout
60fc3fe1c2SSimon Glass                    print result.stderr
61fc3fe1c2SSimon Glass        else:
62fc3fe1c2SSimon Glass            self.ok = True
63fc3fe1c2SSimon Glass        self.priority = self.GetPriority(fname)
64fc3fe1c2SSimon Glass
65fc3fe1c2SSimon Glass    def GetPriority(self, fname):
66fc3fe1c2SSimon Glass        """Return the priority of the toolchain.
67fc3fe1c2SSimon Glass
68fc3fe1c2SSimon Glass        Toolchains are ranked according to their suitability by their
69fc3fe1c2SSimon Glass        filename prefix.
70fc3fe1c2SSimon Glass
71fc3fe1c2SSimon Glass        Args:
72fc3fe1c2SSimon Glass            fname: Filename of toolchain
73fc3fe1c2SSimon Glass        Returns:
74fc3fe1c2SSimon Glass            Priority of toolchain, 0=highest, 20=lowest.
75fc3fe1c2SSimon Glass        """
768708267fSMasahiro Yamada        priority_list = ['-elf', '-unknown-linux-gnu', '-linux',
77fc3fe1c2SSimon Glass            '-none-linux-gnueabi', '-uclinux', '-none-eabi',
78fc3fe1c2SSimon Glass            '-gentoo-linux-gnu', '-linux-gnueabi', '-le-linux', '-uclinux']
79fc3fe1c2SSimon Glass        for prio in range(len(priority_list)):
80fc3fe1c2SSimon Glass            if priority_list[prio] in fname:
81fc3fe1c2SSimon Glass                return prio
82fc3fe1c2SSimon Glass        return prio
83fc3fe1c2SSimon Glass
84fc3fe1c2SSimon Glass    def MakeEnvironment(self):
85fc3fe1c2SSimon Glass        """Returns an environment for using the toolchain.
86fc3fe1c2SSimon Glass
87fc3fe1c2SSimon Glass        Thie takes the current environment, adds CROSS_COMPILE and
88fc3fe1c2SSimon Glass        augments PATH so that the toolchain will operate correctly.
89fc3fe1c2SSimon Glass        """
90fc3fe1c2SSimon Glass        env = dict(os.environ)
91fc3fe1c2SSimon Glass        env['CROSS_COMPILE'] = self.cross
92*f210b587SSimon Glass        env['PATH'] = self.path + ':' + env['PATH']
93fc3fe1c2SSimon Glass        return env
94fc3fe1c2SSimon Glass
95fc3fe1c2SSimon Glass
96fc3fe1c2SSimon Glassclass Toolchains:
97fc3fe1c2SSimon Glass    """Manage a list of toolchains for building U-Boot
98fc3fe1c2SSimon Glass
99fc3fe1c2SSimon Glass    We select one toolchain for each architecture type
100fc3fe1c2SSimon Glass
101fc3fe1c2SSimon Glass    Public members:
102fc3fe1c2SSimon Glass        toolchains: Dict of Toolchain objects, keyed by architecture name
103fc3fe1c2SSimon Glass        paths: List of paths to check for toolchains (may contain wildcards)
104fc3fe1c2SSimon Glass    """
105fc3fe1c2SSimon Glass
106fc3fe1c2SSimon Glass    def __init__(self):
107fc3fe1c2SSimon Glass        self.toolchains = {}
108fc3fe1c2SSimon Glass        self.paths = []
109d4144e45SSimon Glass        self._make_flags = dict(bsettings.GetItems('make-flags'))
110d4144e45SSimon Glass
111d4144e45SSimon Glass    def GetSettings(self):
1124281ad8eSSimon Glass        toolchains = bsettings.GetItems('toolchain')
1134281ad8eSSimon Glass        if not toolchains:
1144281ad8eSSimon Glass            print ("Warning: No tool chains - please add a [toolchain] section"
1154281ad8eSSimon Glass                 " to your buildman config file %s. See README for details" %
1161826a18dSMasahiro Yamada                 bsettings.config_fname)
1174281ad8eSSimon Glass
1184281ad8eSSimon Glass        for name, value in toolchains:
119fc3fe1c2SSimon Glass            if '*' in value:
120fc3fe1c2SSimon Glass                self.paths += glob.glob(value)
121fc3fe1c2SSimon Glass            else:
122fc3fe1c2SSimon Glass                self.paths.append(value)
123fc3fe1c2SSimon Glass
124fc3fe1c2SSimon Glass    def Add(self, fname, test=True, verbose=False):
125fc3fe1c2SSimon Glass        """Add a toolchain to our list
126fc3fe1c2SSimon Glass
127fc3fe1c2SSimon Glass        We select the given toolchain as our preferred one for its
128fc3fe1c2SSimon Glass        architecture if it is a higher priority than the others.
129fc3fe1c2SSimon Glass
130fc3fe1c2SSimon Glass        Args:
131fc3fe1c2SSimon Glass            fname: Filename of toolchain's gcc driver
132fc3fe1c2SSimon Glass            test: True to run the toolchain to test it
133fc3fe1c2SSimon Glass        """
134fc3fe1c2SSimon Glass        toolchain = Toolchain(fname, test, verbose)
135fc3fe1c2SSimon Glass        add_it = toolchain.ok
136fc3fe1c2SSimon Glass        if toolchain.arch in self.toolchains:
137fc3fe1c2SSimon Glass            add_it = (toolchain.priority <
138fc3fe1c2SSimon Glass                        self.toolchains[toolchain.arch].priority)
139fc3fe1c2SSimon Glass        if add_it:
140fc3fe1c2SSimon Glass            self.toolchains[toolchain.arch] = toolchain
141fc3fe1c2SSimon Glass
142fc3fe1c2SSimon Glass    def Scan(self, verbose):
143fc3fe1c2SSimon Glass        """Scan for available toolchains and select the best for each arch.
144fc3fe1c2SSimon Glass
145fc3fe1c2SSimon Glass        We look for all the toolchains we can file, figure out the
146fc3fe1c2SSimon Glass        architecture for each, and whether it works. Then we select the
147fc3fe1c2SSimon Glass        highest priority toolchain for each arch.
148fc3fe1c2SSimon Glass
149fc3fe1c2SSimon Glass        Args:
150fc3fe1c2SSimon Glass            verbose: True to print out progress information
151fc3fe1c2SSimon Glass        """
152fc3fe1c2SSimon Glass        if verbose: print 'Scanning for tool chains'
153fc3fe1c2SSimon Glass        for path in self.paths:
154fc3fe1c2SSimon Glass            if verbose: print "   - scanning path '%s'" % path
155fc3fe1c2SSimon Glass            for subdir in ['.', 'bin', 'usr/bin']:
156fc3fe1c2SSimon Glass                dirname = os.path.join(path, subdir)
157fc3fe1c2SSimon Glass                if verbose: print "      - looking in '%s'" % dirname
158fc3fe1c2SSimon Glass                for fname in glob.glob(dirname + '/*gcc'):
159fc3fe1c2SSimon Glass                    if verbose: print "         - found '%s'" % fname
160fc3fe1c2SSimon Glass                    self.Add(fname, True, verbose)
161fc3fe1c2SSimon Glass
162fc3fe1c2SSimon Glass    def List(self):
163fc3fe1c2SSimon Glass        """List out the selected toolchains for each architecture"""
164fc3fe1c2SSimon Glass        print 'List of available toolchains (%d):' % len(self.toolchains)
165fc3fe1c2SSimon Glass        if len(self.toolchains):
166fc3fe1c2SSimon Glass            for key, value in sorted(self.toolchains.iteritems()):
167fc3fe1c2SSimon Glass                print '%-10s: %s' % (key, value.gcc)
168fc3fe1c2SSimon Glass        else:
169fc3fe1c2SSimon Glass            print 'None'
170fc3fe1c2SSimon Glass
171fc3fe1c2SSimon Glass    def Select(self, arch):
172fc3fe1c2SSimon Glass        """Returns the toolchain for a given architecture
173fc3fe1c2SSimon Glass
174fc3fe1c2SSimon Glass        Args:
175fc3fe1c2SSimon Glass            args: Name of architecture (e.g. 'arm', 'ppc_8xx')
176fc3fe1c2SSimon Glass
177fc3fe1c2SSimon Glass        returns:
178fc3fe1c2SSimon Glass            toolchain object, or None if none found
179fc3fe1c2SSimon Glass        """
180fc3fe1c2SSimon Glass        for name, value in bsettings.GetItems('toolchain-alias'):
181fc3fe1c2SSimon Glass            if arch == name:
182fc3fe1c2SSimon Glass                arch = value
183fc3fe1c2SSimon Glass
184fc3fe1c2SSimon Glass        if not arch in self.toolchains:
185fc3fe1c2SSimon Glass            raise ValueError, ("No tool chain found for arch '%s'" % arch)
186fc3fe1c2SSimon Glass        return self.toolchains[arch]
1874281ad8eSSimon Glass
1884281ad8eSSimon Glass    def ResolveReferences(self, var_dict, args):
1894281ad8eSSimon Glass        """Resolve variable references in a string
1904281ad8eSSimon Glass
1914281ad8eSSimon Glass        This converts ${blah} within the string to the value of blah.
1924281ad8eSSimon Glass        This function works recursively.
1934281ad8eSSimon Glass
1944281ad8eSSimon Glass        Args:
1954281ad8eSSimon Glass            var_dict: Dictionary containing variables and their values
1964281ad8eSSimon Glass            args: String containing make arguments
1974281ad8eSSimon Glass        Returns:
1984281ad8eSSimon Glass            Resolved string
1994281ad8eSSimon Glass
2004281ad8eSSimon Glass        >>> bsettings.Setup()
2014281ad8eSSimon Glass        >>> tcs = Toolchains()
2024281ad8eSSimon Glass        >>> tcs.Add('fred', False)
2034281ad8eSSimon Glass        >>> var_dict = {'oblique' : 'OBLIQUE', 'first' : 'fi${second}rst', \
2044281ad8eSSimon Glass                        'second' : '2nd'}
2054281ad8eSSimon Glass        >>> tcs.ResolveReferences(var_dict, 'this=${oblique}_set')
2064281ad8eSSimon Glass        'this=OBLIQUE_set'
2074281ad8eSSimon Glass        >>> tcs.ResolveReferences(var_dict, 'this=${oblique}_set${first}nd')
2084281ad8eSSimon Glass        'this=OBLIQUE_setfi2ndrstnd'
2094281ad8eSSimon Glass        """
210f60c9d4fSSimon Glass        re_var = re.compile('(\$\{[-_a-z0-9A-Z]{1,}\})')
2114281ad8eSSimon Glass
2124281ad8eSSimon Glass        while True:
2134281ad8eSSimon Glass            m = re_var.search(args)
2144281ad8eSSimon Glass            if not m:
2154281ad8eSSimon Glass                break
2164281ad8eSSimon Glass            lookup = m.group(0)[2:-1]
2174281ad8eSSimon Glass            value = var_dict.get(lookup, '')
2184281ad8eSSimon Glass            args = args[:m.start(0)] + value + args[m.end(0):]
2194281ad8eSSimon Glass        return args
2204281ad8eSSimon Glass
2214281ad8eSSimon Glass    def GetMakeArguments(self, board):
2224281ad8eSSimon Glass        """Returns 'make' arguments for a given board
2234281ad8eSSimon Glass
2244281ad8eSSimon Glass        The flags are in a section called 'make-flags'. Flags are named
2254281ad8eSSimon Glass        after the target they represent, for example snapper9260=TESTING=1
2264281ad8eSSimon Glass        will pass TESTING=1 to make when building the snapper9260 board.
2274281ad8eSSimon Glass
2284281ad8eSSimon Glass        References to other boards can be added in the string also. For
2294281ad8eSSimon Glass        example:
2304281ad8eSSimon Glass
2314281ad8eSSimon Glass        [make-flags]
2324281ad8eSSimon Glass        at91-boards=ENABLE_AT91_TEST=1
2334281ad8eSSimon Glass        snapper9260=${at91-boards} BUILD_TAG=442
2344281ad8eSSimon Glass        snapper9g45=${at91-boards} BUILD_TAG=443
2354281ad8eSSimon Glass
2364281ad8eSSimon Glass        This will return 'ENABLE_AT91_TEST=1 BUILD_TAG=442' for snapper9260
2374281ad8eSSimon Glass        and 'ENABLE_AT91_TEST=1 BUILD_TAG=443' for snapper9g45.
2384281ad8eSSimon Glass
2394281ad8eSSimon Glass        A special 'target' variable is set to the board target.
2404281ad8eSSimon Glass
2414281ad8eSSimon Glass        Args:
2424281ad8eSSimon Glass            board: Board object for the board to check.
2434281ad8eSSimon Glass        Returns:
2444281ad8eSSimon Glass            'make' flags for that board, or '' if none
2454281ad8eSSimon Glass        """
2464281ad8eSSimon Glass        self._make_flags['target'] = board.target
2474281ad8eSSimon Glass        arg_str = self.ResolveReferences(self._make_flags,
2484281ad8eSSimon Glass                           self._make_flags.get(board.target, ''))
2494281ad8eSSimon Glass        args = arg_str.split(' ')
2504281ad8eSSimon Glass        i = 0
2514281ad8eSSimon Glass        while i < len(args):
2524281ad8eSSimon Glass            if not args[i]:
2534281ad8eSSimon Glass                del args[i]
2544281ad8eSSimon Glass            else:
2554281ad8eSSimon Glass                i += 1
2564281ad8eSSimon Glass        return args
257