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):
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
+ 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)
# 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']
+ 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 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
print result.stderr
else:
self.ok = True
- self.priority = self.GetPriority(fname)
def GetPriority(self, fname):
"""Return the priority of the toolchain.
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',
- '-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:
- 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
- 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)
+ wrapper = self.GetWrapper()
+
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:
- env['CROSS_COMPILE'] = self.cross
+ env['CROSS_COMPILE'] = wrapper + self.cross
env['PATH'] = self.path + ':' + env['PATH']
+ env['LC_ALL'] = 'C'
+
return env
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 = {}
+ self.prefixes = {}
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
+ 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')
- 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.append(value)
return paths
- def GetSettings(self):
- self.paths += self.GetPathList()
+ def GetSettings(self, show_warning=True):
+ """Get toolchain settings from the settings file.
+
+ 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):
+ 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
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
+ 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
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.
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)
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)
"""
arch = command.OutputOneLine('uname', '-m')
base = 'https://www.kernel.org/pub/tools/crosstool/files/bin'
- versions = ['4.6.3', '4.6.2', '4.5.1', '4.2.4']
+ versions = ['4.9.0', '4.6.3', '4.6.2', '4.5.1', '4.2.4']
links = []
for version in versions:
url = '%s/%s/%s/' % (base, arch, version)
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()
- size = int(meta.getheaders("Content-Length")[0])
+ size = int(meta.getheaders('Content-Length')[0])
done = 0
block_size = 1 << 16
status = ''
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,
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
"""
- paths = self.GetPathList()
+ paths = self.GetPathList(False)
return path in paths
def ListArchs(self):
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" %
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)
print
# Check that the toolchain works
- print 'Testing'
+ print col.Color(col.GREEN, 'Testing')
dirpath = os.path.join(dest, path)
- compiler_fname = self.ScanPath(dirpath, True)
- if not compiler_fname:
+ compiler_fname_list = self.ScanPath(dirpath, True)
+ if not compiler_fname_list:
print 'Could not locate C compiler - fetch failed.'
return 1
- toolchain = Toolchain(compiler_fname, True, True)
+ if len(compiler_fname_list) != 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)
- tools_dir = os.path.dirname(dirpath)
- bsettings.SetItem('toolchain', 'download', '%s/*' % tools_dir)
+ bsettings.SetItem('toolchain', 'download', '%s/*/*' % dest)
return 0