]> git.sur5r.net Git - u-boot/blobdiff - tools/buildman/toolchain.py
edison: Disable CONFIG_USB_HOST_ETHER
[u-boot] / tools / buildman / toolchain.py
index e33e10532ee9171897426f8e817bb112396083dc..2076323d5d39825f17b0460d09ce3dd383bc50b3 100644 (file)
@@ -13,6 +13,10 @@ import urllib2
 
 import bsettings
 import command
 
 import bsettings
 import command
+import terminal
+
+(PRIORITY_FULL_PREFIX, PRIORITY_PREFIX_GCC, PRIORITY_PREFIX_GCC_PATH,
+    PRIORITY_CALC) = range(4)
 
 # Simple class to collect links from a page
 class MyHTMLParser(HTMLParser):
 
 # Simple class to collect links from a page
 class MyHTMLParser(HTMLParser):
@@ -50,13 +54,18 @@ class Toolchain:
         cross: Cross compile string, e.g. 'arm-linux-'
         arch: Architecture of toolchain as determined from the first
                 component of the filename. E.g. arm-linux-gcc becomes arm
         cross: Cross compile string, e.g. 'arm-linux-'
         arch: Architecture of toolchain as determined from the first
                 component of the filename. E.g. arm-linux-gcc becomes arm
+        priority: Toolchain priority (0=highest, 20=lowest)
     """
     """
-    def __init__(self, fname, test, verbose=False):
+    def __init__(self, fname, test, verbose=False, priority=PRIORITY_CALC,
+                 arch=None):
         """Create a new toolchain object.
 
         Args:
             fname: Filename of the gcc component
             test: True to run the toolchain to test it
         """Create a new toolchain object.
 
         Args:
             fname: Filename of the gcc component
             test: True to run the toolchain to test it
+            verbose: True to print out the information
+            priority: Priority to use for this toolchain, or PRIORITY_CALC to
+                calculate it
         """
         self.gcc = fname
         self.path = os.path.dirname(fname)
         """
         self.gcc = fname
         self.path = os.path.dirname(fname)
@@ -69,12 +78,19 @@ class Toolchain:
 
         # The architecture is the first part of the name
         pos = self.cross.find('-')
 
         # The architecture is the first part of the name
         pos = self.cross.find('-')
-        self.arch = self.cross[:pos] if pos != -1 else 'sandbox'
+        if arch:
+            self.arch = arch
+        else:
+            self.arch = self.cross[:pos] if pos != -1 else 'sandbox'
 
         env = self.MakeEnvironment(False)
 
         # As a basic sanity check, run the C compiler with --version
         cmd = [fname, '--version']
 
         env = self.MakeEnvironment(False)
 
         # As a basic sanity check, run the C compiler with --version
         cmd = [fname, '--version']
+        if priority == PRIORITY_CALC:
+            self.priority = self.GetPriority(fname)
+        else:
+            self.priority = priority
         if test:
             result = command.RunPipe([cmd], capture=True, env=env,
                                      raise_on_error=False)
         if test:
             result = command.RunPipe([cmd], capture=True, env=env,
                                      raise_on_error=False)
@@ -82,7 +98,8 @@ class Toolchain:
             if verbose:
                 print 'Tool chain test: ',
                 if self.ok:
             if verbose:
                 print 'Tool chain test: ',
                 if self.ok:
-                    print 'OK'
+                    print "OK, arch='%s', priority %d" % (self.arch,
+                                                          self.priority)
                 else:
                     print 'BAD'
                     print 'Command: ', cmd
                 else:
                     print 'BAD'
                     print 'Command: ', cmd
@@ -90,7 +107,6 @@ class Toolchain:
                     print result.stderr
         else:
             self.ok = True
                     print result.stderr
         else:
             self.ok = True
-        self.priority = self.GetPriority(fname)
 
     def GetPriority(self, fname):
         """Return the priority of the toolchain.
 
     def GetPriority(self, fname):
         """Return the priority of the toolchain.
@@ -101,33 +117,52 @@ class Toolchain:
         Args:
             fname: Filename of toolchain
         Returns:
         Args:
             fname: Filename of toolchain
         Returns:
-            Priority of toolchain, 0=highest, 20=lowest.
+            Priority of toolchain, PRIORITY_CALC=highest, 20=lowest.
         """
         priority_list = ['-elf', '-unknown-linux-gnu', '-linux',
         """
         priority_list = ['-elf', '-unknown-linux-gnu', '-linux',
-            '-none-linux-gnueabi', '-uclinux', '-none-eabi',
-            '-gentoo-linux-gnu', '-linux-gnueabi', '-le-linux', '-uclinux']
+            '-none-linux-gnueabi', '-none-linux-gnueabihf', '-uclinux',
+            '-none-eabi', '-gentoo-linux-gnu', '-linux-gnueabi',
+            '-linux-gnueabihf', '-le-linux', '-uclinux']
         for prio in range(len(priority_list)):
             if priority_list[prio] in fname:
         for prio in range(len(priority_list)):
             if priority_list[prio] in fname:
-                return prio
-        return prio
+                return PRIORITY_CALC + prio
+        return PRIORITY_CALC + prio
+
+    def GetWrapper(self, show_warning=True):
+        """Get toolchain wrapper from the setting file.
+        """
+       value = ''
+       for name, value in bsettings.GetItems('toolchain-wrapper'):
+            if not value:
+                print "Warning: Wrapper not found"
+        if value:
+            value = value + ' '
+
+        return value
 
     def MakeEnvironment(self, full_path):
         """Returns an environment for using the toolchain.
 
         Thie takes the current environment and adds CROSS_COMPILE so that
 
     def MakeEnvironment(self, full_path):
         """Returns an environment for using the toolchain.
 
         Thie takes the current environment and adds CROSS_COMPILE so that
-        the tool chain will operate correctly.
+        the tool chain will operate correctly. This also disables localized
+        output and possibly unicode encoded output of all build tools by
+        adding LC_ALL=C.
 
         Args:
             full_path: Return the full path in CROSS_COMPILE and don't set
                 PATH
         """
         env = dict(os.environ)
 
         Args:
             full_path: Return the full path in CROSS_COMPILE and don't set
                 PATH
         """
         env = dict(os.environ)
+        wrapper = self.GetWrapper()
+
         if full_path:
         if full_path:
-            env['CROSS_COMPILE'] = os.path.join(self.path, self.cross)
+            env['CROSS_COMPILE'] = wrapper + os.path.join(self.path, self.cross)
         else:
         else:
-            env['CROSS_COMPILE'] = self.cross
+            env['CROSS_COMPILE'] = wrapper + self.cross
             env['PATH'] = self.path + ':' + env['PATH']
 
             env['PATH'] = self.path + ':' + env['PATH']
 
+        env['LC_ALL'] = 'C'
+
         return env
 
 
         return env
 
 
@@ -138,26 +173,37 @@ class Toolchains:
 
     Public members:
         toolchains: Dict of Toolchain objects, keyed by architecture name
 
     Public members:
         toolchains: Dict of Toolchain objects, keyed by architecture name
+        prefixes: Dict of prefixes to check, keyed by architecture. This can
+            be a full path and toolchain prefix, for example
+            {'x86', 'opt/i386-linux/bin/i386-linux-'}, or the name of
+            something on the search path, for example
+            {'arm', 'arm-linux-gnueabihf-'}. Wildcards are not supported.
         paths: List of paths to check for toolchains (may contain wildcards)
     """
 
     def __init__(self):
         self.toolchains = {}
         paths: List of paths to check for toolchains (may contain wildcards)
     """
 
     def __init__(self):
         self.toolchains = {}
+        self.prefixes = {}
         self.paths = []
         self._make_flags = dict(bsettings.GetItems('make-flags'))
 
         self.paths = []
         self._make_flags = dict(bsettings.GetItems('make-flags'))
 
-    def GetPathList(self):
+    def GetPathList(self, show_warning=True):
         """Get a list of available toolchain paths
 
         """Get a list of available toolchain paths
 
+        Args:
+            show_warning: True to show a warning if there are no tool chains.
+
         Returns:
             List of strings, each a path to a toolchain mentioned in the
             [toolchain] section of the settings file.
         """
         toolchains = bsettings.GetItems('toolchain')
         Returns:
             List of strings, each a path to a toolchain mentioned in the
             [toolchain] section of the settings file.
         """
         toolchains = bsettings.GetItems('toolchain')
-        if not toolchains:
-            print ("Warning: No tool chains - please add a [toolchain] section"
-                 " to your buildman config file %s. See README for details" %
-                 bsettings.config_fname)
+        if show_warning and not toolchains:
+            print ("Warning: No tool chains. Please run 'buildman "
+                   "--fetch-arch all' to download all available toolchains, or "
+                   "add a [toolchain] section to your buildman config file "
+                   "%s. See README for details" %
+                   bsettings.config_fname)
 
         paths = []
         for name, value in toolchains:
 
         paths = []
         for name, value in toolchains:
@@ -167,10 +213,17 @@ class Toolchains:
                 paths.append(value)
         return paths
 
                 paths.append(value)
         return paths
 
-    def GetSettings(self):
-      self.paths += self.GetPathList()
+    def GetSettings(self, show_warning=True):
+        """Get toolchain settings from the settings file.
 
 
-    def Add(self, fname, test=True, verbose=False):
+        Args:
+            show_warning: True to show a warning if there are no tool chains.
+        """
+        self.prefixes = bsettings.GetItems('toolchain-prefix')
+        self.paths += self.GetPathList(show_warning)
+
+    def Add(self, fname, test=True, verbose=False, priority=PRIORITY_CALC,
+            arch=None):
         """Add a toolchain to our list
 
         We select the given toolchain as our preferred one for its
         """Add a toolchain to our list
 
         We select the given toolchain as our preferred one for its
@@ -179,14 +232,21 @@ class Toolchains:
         Args:
             fname: Filename of toolchain's gcc driver
             test: True to run the toolchain to test it
         Args:
             fname: Filename of toolchain's gcc driver
             test: True to run the toolchain to test it
+            priority: Priority to use for this toolchain
+            arch: Toolchain architecture, or None if not known
         """
         """
-        toolchain = Toolchain(fname, test, verbose)
+        toolchain = Toolchain(fname, test, verbose, priority, arch)
         add_it = toolchain.ok
         if toolchain.arch in self.toolchains:
             add_it = (toolchain.priority <
                         self.toolchains[toolchain.arch].priority)
         if add_it:
             self.toolchains[toolchain.arch] = toolchain
         add_it = toolchain.ok
         if toolchain.arch in self.toolchains:
             add_it = (toolchain.priority <
                         self.toolchains[toolchain.arch].priority)
         if add_it:
             self.toolchains[toolchain.arch] = toolchain
+        elif verbose:
+            print ("Toolchain '%s' at priority %d will be ignored because "
+                   "another toolchain for arch '%s' has priority %d" %
+                   (toolchain.gcc, toolchain.priority, toolchain.arch,
+                    self.toolchains[toolchain.arch].priority))
 
     def ScanPath(self, path, verbose):
         """Scan a path for a valid toolchain
 
     def ScanPath(self, path, verbose):
         """Scan a path for a valid toolchain
@@ -206,6 +266,21 @@ class Toolchains:
                 fnames.append(fname)
         return fnames
 
                 fnames.append(fname)
         return fnames
 
+    def ScanPathEnv(self, fname):
+        """Scan the PATH environment variable for a given filename.
+
+        Args:
+            fname: Filename to scan for
+        Returns:
+            List of matching pathanames, or [] if none
+        """
+        pathname_list = []
+        for path in os.environ["PATH"].split(os.pathsep):
+            path = path.strip('"')
+            pathname = os.path.join(path, fname)
+            if os.path.exists(pathname):
+                pathname_list.append(pathname)
+        return pathname_list
 
     def Scan(self, verbose):
         """Scan for available toolchains and select the best for each arch.
 
     def Scan(self, verbose):
         """Scan for available toolchains and select the best for each arch.
@@ -218,6 +293,21 @@ class Toolchains:
             verbose: True to print out progress information
         """
         if verbose: print 'Scanning for tool chains'
             verbose: True to print out progress information
         """
         if verbose: print 'Scanning for tool chains'
+        for name, value in self.prefixes:
+            if verbose: print "   - scanning prefix '%s'" % value
+            if os.path.exists(value):
+                self.Add(value, True, verbose, PRIORITY_FULL_PREFIX, name)
+                continue
+            fname = value + 'gcc'
+            if os.path.exists(fname):
+                self.Add(fname, True, verbose, PRIORITY_PREFIX_GCC, name)
+                continue
+            fname_list = self.ScanPathEnv(fname)
+            for f in fname_list:
+                self.Add(f, True, verbose, PRIORITY_PREFIX_GCC_PATH, name)
+            if not fname_list:
+                raise ValueError, ("No tool chain found for prefix '%s'" %
+                                   value)
         for path in self.paths:
             if verbose: print "   - scanning path '%s'" % path
             fnames = self.ScanPath(path, verbose)
         for path in self.paths:
             if verbose: print "   - scanning path '%s'" % path
             fnames = self.ScanPath(path, verbose)
@@ -226,7 +316,9 @@ class Toolchains:
 
     def List(self):
         """List out the selected toolchains for each architecture"""
 
     def List(self):
         """List out the selected toolchains for each architecture"""
-        print 'List of available toolchains (%d):' % len(self.toolchains)
+        col = terminal.Color()
+        print col.Color(col.BLUE, 'List of available toolchains (%d):' %
+                        len(self.toolchains))
         if len(self.toolchains):
             for key, value in sorted(self.toolchains.iteritems()):
                 print '%-10s: %s' % (key, value.gcc)
         if len(self.toolchains):
             for key, value in sorted(self.toolchains.iteritems()):
                 print '%-10s: %s' % (key, value.gcc)
@@ -367,14 +459,14 @@ class Toolchains:
                 Full path to the downloaded archive file in that directory,
                     or None if there was an error while downloading
         """
                 Full path to the downloaded archive file in that directory,
                     or None if there was an error while downloading
         """
-        print "Downloading: %s" % url
+        print 'Downloading: %s' % url
         leaf = url.split('/')[-1]
         tmpdir = tempfile.mkdtemp('.buildman')
         response = urllib2.urlopen(url)
         fname = os.path.join(tmpdir, leaf)
         fd = open(fname, 'wb')
         meta = response.info()
         leaf = url.split('/')[-1]
         tmpdir = tempfile.mkdtemp('.buildman')
         response = urllib2.urlopen(url)
         fname = os.path.join(tmpdir, leaf)
         fd = open(fname, 'wb')
         meta = response.info()
-        size = int(meta.getheaders("Content-Length")[0])
+        size = int(meta.getheaders('Content-Length')[0])
         done = 0
         block_size = 1 << 16
         status = ''
         done = 0
         block_size = 1 << 16
         status = ''
@@ -388,7 +480,7 @@ class Toolchains:
 
             done += len(buffer)
             fd.write(buffer)
 
             done += len(buffer)
             fd.write(buffer)
-            status = r"%10d MiB  [%3d%%]" % (done / 1024 / 1024,
+            status = r'%10d MiB  [%3d%%]' % (done / 1024 / 1024,
                                              done * 100 / size)
             status = status + chr(8) * (len(status) + 1)
             print status,
                                              done * 100 / size)
             status = status + chr(8) * (len(status) + 1)
             print status,
@@ -414,12 +506,12 @@ class Toolchains:
         return stdout.splitlines()[0][:-1]
 
     def TestSettingsHasPath(self, path):
         return stdout.splitlines()[0][:-1]
 
     def TestSettingsHasPath(self, path):
-        """Check if builmand will find this toolchain
+        """Check if buildman will find this toolchain
 
         Returns:
             True if the path is in settings, False if not
         """
 
         Returns:
             True if the path is in settings, False if not
         """
-        paths = self.GetPathList()
+        paths = self.GetPathList(False)
         return path in paths
 
     def ListArchs(self):
         return path in paths
 
     def ListArchs(self):
@@ -441,6 +533,8 @@ class Toolchains:
             Architecture to fetch, or 'list' to list
         """
         # Fist get the URL for this architecture
             Architecture to fetch, or 'list' to list
         """
         # Fist get the URL for this architecture
+        col = terminal.Color()
+        print col.Color(col.BLUE, "Downloading toolchain for arch '%s'" % arch)
         url = self.LocateArchUrl(arch)
         if not url:
             print ("Cannot find toolchain for arch '%s' - use 'list' to list" %
         url = self.LocateArchUrl(arch)
         if not url:
             print ("Cannot find toolchain for arch '%s' - use 'list' to list" %
@@ -455,7 +549,7 @@ class Toolchains:
         tmpdir, tarfile = self.Download(url)
         if not tarfile:
             return 1
         tmpdir, tarfile = self.Download(url)
         if not tarfile:
             return 1
-        print 'Unpacking to: %s' % dest,
+        print col.Color(col.GREEN, 'Unpacking to: %s' % dest),
         sys.stdout.flush()
         path = self.Unpack(tarfile, dest)
         os.remove(tarfile)
         sys.stdout.flush()
         path = self.Unpack(tarfile, dest)
         os.remove(tarfile)
@@ -463,22 +557,20 @@ class Toolchains:
         print
 
         # Check that the toolchain works
         print
 
         # Check that the toolchain works
-        print 'Testing'
+        print col.Color(col.GREEN, 'Testing')
         dirpath = os.path.join(dest, path)
         compiler_fname_list = self.ScanPath(dirpath, True)
         if not compiler_fname_list:
             print 'Could not locate C compiler - fetch failed.'
             return 1
         if len(compiler_fname_list) != 1:
         dirpath = os.path.join(dest, path)
         compiler_fname_list = self.ScanPath(dirpath, True)
         if not compiler_fname_list:
             print 'Could not locate C compiler - fetch failed.'
             return 1
         if len(compiler_fname_list) != 1:
-            print ('Internal error, ambiguous toolchains: %s' %
-                   (', '.join(compiler_fname)))
-            return 1
+            print col.Color(col.RED, 'Warning, ambiguous toolchains: %s' %
+                            ', '.join(compiler_fname_list))
         toolchain = Toolchain(compiler_fname_list[0], True, True)
 
         # Make sure that it will be found by buildman
         if not self.TestSettingsHasPath(dirpath):
             print ("Adding 'download' to config file '%s'" %
                    bsettings.config_fname)
         toolchain = Toolchain(compiler_fname_list[0], True, True)
 
         # Make sure that it will be found by buildman
         if not self.TestSettingsHasPath(dirpath):
             print ("Adding 'download' to config file '%s'" %
                    bsettings.config_fname)
-            tools_dir = os.path.dirname(dirpath)
-            bsettings.SetItem('toolchain', 'download', '%s/*' % tools_dir)
+            bsettings.SetItem('toolchain', 'download', '%s/*/*' % dest)
         return 0
         return 0