blob: 1c8f47bc465286779e42e764b101323d3ffc7fd0 [file] [log] [blame]
Zdenek Behan508dcce2011-12-05 15:39:32 +01001# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
Mike Frysinger750c5f52014-09-16 16:16:57 -04005"""This script manages the installed toolchains in the chroot."""
Zdenek Behan508dcce2011-12-05 15:39:32 +01006
Mike Frysinger383367e2014-09-16 15:06:17 -04007from __future__ import print_function
8
Zdenek Behan508dcce2011-12-05 15:39:32 +01009import copy
Mike Frysinger3ed47722017-08-08 14:59:08 -040010import errno
Mike Frysinger35247af2012-11-16 18:58:06 -050011import glob
Mike Frysinger3ed47722017-08-08 14:59:08 -040012import hashlib
Mike Frysinger7ccee992012-06-01 21:27:59 -040013import json
Zdenek Behan508dcce2011-12-05 15:39:32 +010014import os
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -070015import re
Zdenek Behan508dcce2011-12-05 15:39:32 +010016
Aviv Keshetb7519e12016-10-04 00:50:00 -070017from chromite.lib import constants
Mike Frysinger506e75f2012-12-17 14:21:13 -050018from chromite.lib import commandline
Brian Harring503f3ab2012-03-09 21:39:41 -080019from chromite.lib import cros_build_lib
Ralph Nathan03047282015-03-23 11:09:32 -070020from chromite.lib import cros_logging as logging
Brian Harringaf019fb2012-05-10 15:06:13 -070021from chromite.lib import osutils
Mike Frysinger35247af2012-11-16 18:58:06 -050022from chromite.lib import parallel
David James27ac4ae2012-12-03 23:16:15 -080023from chromite.lib import toolchain
Mike Frysinger35247af2012-11-16 18:58:06 -050024
25# Needs to be after chromite imports.
26import lddtree
Zdenek Behan508dcce2011-12-05 15:39:32 +010027
Mike Frysinger31596002012-12-03 23:54:24 -050028if cros_build_lib.IsInsideChroot():
29 # Only import portage after we've checked that we're inside the chroot.
30 # Outside may not have portage, in which case the above may not happen.
31 # We'll check in main() if the operation needs portage.
Don Garrett25f309a2014-03-19 14:02:12 -070032 # pylint: disable=F0401
Mike Frysinger31596002012-12-03 23:54:24 -050033 import portage
Zdenek Behan508dcce2011-12-05 15:39:32 +010034
35
Matt Tennantf1e30972012-03-02 16:30:07 -080036EMERGE_CMD = os.path.join(constants.CHROMITE_BIN_DIR, 'parallel_emerge')
Zdenek Behan508dcce2011-12-05 15:39:32 +010037PACKAGE_STABLE = '[stable]'
Zdenek Behan4eb6fd22012-03-12 17:00:56 +010038
39CHROMIUMOS_OVERLAY = '/usr/local/portage/chromiumos'
Christopher Wileyb22c0712015-06-02 10:37:03 -070040ECLASS_OVERLAY = '/usr/local/portage/eclass-overlay'
Zdenek Behan4eb6fd22012-03-12 17:00:56 +010041STABLE_OVERLAY = '/usr/local/portage/stable'
42CROSSDEV_OVERLAY = '/usr/local/portage/crossdev'
Zdenek Behan508dcce2011-12-05 15:39:32 +010043
44
45# TODO: The versions are stored here very much like in setup_board.
46# The goal for future is to differentiate these using a config file.
47# This is done essentially by messing with GetDesiredPackageVersions()
48DEFAULT_VERSION = PACKAGE_STABLE
49DEFAULT_TARGET_VERSION_MAP = {
Zdenek Behan508dcce2011-12-05 15:39:32 +010050}
51TARGET_VERSION_MAP = {
Zdenek Behan508dcce2011-12-05 15:39:32 +010052}
Rahul Chaudhry4b803052015-05-13 15:25:56 -070053
Mike Frysinger66bfde52017-09-12 16:42:57 -040054# The exact list of host toolchain packages we care about. These are the
55# packages that bots/devs install only from binpkgs and rely on the SDK bot
56# (chromiumos-sdk) to validate+uprev.
57#
58# These also need to be manually kept in sync with update_chroot.
59#
60# We don't use crossdev to manage the host toolchain for us, especially since
61# we diverge significantly now (with llvm/clang/etc...), and we don't need or
62# want crossdev managing /etc/portage config files for the sdk
63HOST_PACKAGES = (
64 'dev-lang/go',
65 'sys-devel/binutils',
66 'sys-devel/clang',
67 'sys-devel/gcc',
68 'sys-devel/llvm',
69 'sys-kernel/linux-headers',
70 'sys-libs/glibc',
71 'sys-libs/libcxx',
72 'sys-libs/libcxxabi',
73)
74
Rahul Chaudhry4b803052015-05-13 15:25:56 -070075# Enable the Go compiler for these targets.
76TARGET_GO_ENABLED = (
77 'x86_64-cros-linux-gnu',
Rahul Chaudhry4b803052015-05-13 15:25:56 -070078 'armv7a-cros-linux-gnueabi',
79)
80CROSSDEV_GO_ARGS = ['--ex-pkg', 'dev-lang/go']
81
Manoj Gupta1b5642e2017-03-08 16:44:12 -080082# Enable llvm's compiler-rt for these targets.
83TARGET_COMPILER_RT_ENABLED = (
84 'armv7a-cros-linux-gnueabi',
Manoj Gupta946abb42017-04-12 14:27:19 -070085 'aarch64-cros-linux-gnu',
Manoj Gupta1b5642e2017-03-08 16:44:12 -080086)
87CROSSDEV_COMPILER_RT_ARGS = ['--ex-pkg', 'sys-libs/compiler-rt']
88
Manoj Gupta946abb42017-04-12 14:27:19 -070089TARGET_LLVM_PKGS_ENABLED = (
90 'armv7a-cros-linux-gnueabi',
91 'aarch64-cros-linux-gnu',
92 'x86_64-cros-linux-gnu',
93)
94
95LLVM_PKGS_TABLE = {
Yunlian Jiangbb2a3d32017-04-26 14:44:09 -070096 'ex_libcxxabi' : ['--ex-pkg', 'sys-libs/libcxxabi'],
97 'ex_libcxx' : ['--ex-pkg', 'sys-libs/libcxx'],
Manoj Gupta946abb42017-04-12 14:27:19 -070098}
99
Zdenek Behan508dcce2011-12-05 15:39:32 +0100100# Overrides for {gcc,binutils}-config, pick a package with particular suffix.
101CONFIG_TARGET_SUFFIXES = {
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500102 'binutils' : {
Mike Frysinger8a83c622015-05-28 00:35:05 -0400103 'armv6j-cros-linux-gnueabi': '-gold',
Han Shen43b84422015-02-19 11:38:13 -0800104 'armv7a-cros-linux-gnueabi': '-gold',
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500105 'i686-pc-linux-gnu' : '-gold',
106 'x86_64-cros-linux-gnu' : '-gold',
107 },
Zdenek Behan508dcce2011-12-05 15:39:32 +0100108}
Zdenek Behan508dcce2011-12-05 15:39:32 +0100109# Global per-run cache that will be filled ondemand in by GetPackageMap()
110# function as needed.
111target_version_map = {
112}
113
114
David James66a09c42012-11-05 13:31:38 -0800115class Crossdev(object):
116 """Class for interacting with crossdev and caching its output."""
117
118 _CACHE_FILE = os.path.join(CROSSDEV_OVERLAY, '.configured.json')
119 _CACHE = {}
Han Shene23782f2016-02-18 12:20:00 -0800120 # Packages that needs separate handling, in addition to what we have from
121 # crossdev.
122 MANUAL_PKGS = {
Manoj Guptaf0a602e2017-08-02 10:25:45 -0700123 'clang': 'sys-devel',
Han Shene23782f2016-02-18 12:20:00 -0800124 'llvm': 'sys-devel',
Manoj Gupta20cfc6c2017-07-19 15:49:55 -0700125 'libcxxabi': 'sys-libs',
126 'libcxx': 'sys-libs',
Han Shene23782f2016-02-18 12:20:00 -0800127 }
David James66a09c42012-11-05 13:31:38 -0800128
129 @classmethod
130 def Load(cls, reconfig):
Mike Frysinger3ed47722017-08-08 14:59:08 -0400131 """Load crossdev cache from disk.
132
133 We invalidate the cache when crossdev updates or this script changes.
134 """
David James90239b92012-11-05 15:31:34 -0800135 crossdev_version = GetStablePackageVersion('sys-devel/crossdev', True)
Mike Frysinger3ed47722017-08-08 14:59:08 -0400136 # If we run the compiled/cached .pyc file, we'll read/hash that when we
137 # really always want to track the source .py file.
138 script = os.path.abspath(__file__)
139 if script.endswith('.pyc'):
140 script = script[:-1]
141 setup_toolchains_hash = hashlib.md5(osutils.ReadFile(script)).hexdigest()
142
143 cls._CACHE = {
144 'crossdev_version': crossdev_version,
145 'setup_toolchains_hash': setup_toolchains_hash,
146 }
147
148 logging.debug('cache: checking file: %s', cls._CACHE_FILE)
149 if reconfig:
150 logging.debug('cache: forcing regen due to reconfig')
151 return
152
153 try:
154 file_data = osutils.ReadFile(cls._CACHE_FILE)
155 except IOError as e:
156 if e.errno != errno.ENOENT:
157 logging.warning('cache: reading failed: %s', e)
158 osutils.SafeUnlink(cls._CACHE_FILE)
159 return
160
161 try:
162 data = json.loads(file_data)
163 except ValueError as e:
164 logging.warning('cache: ignoring invalid content: %s', e)
165 return
166
167 if crossdev_version != data.get('crossdev_version'):
168 logging.debug('cache: rebuilding after crossdev upgrade')
169 elif setup_toolchains_hash != data.get('setup_toolchains_hash'):
170 logging.debug('cache: rebuilding after cros_setup_toolchains change')
171 else:
172 logging.debug('cache: content is up-to-date!')
173 cls._CACHE = data
David James66a09c42012-11-05 13:31:38 -0800174
175 @classmethod
176 def Save(cls):
177 """Store crossdev cache on disk."""
178 # Save the cache from the successful run.
179 with open(cls._CACHE_FILE, 'w') as f:
180 json.dump(cls._CACHE, f)
181
182 @classmethod
183 def GetConfig(cls, target):
184 """Returns a map of crossdev provided variables about a tuple."""
185 CACHE_ATTR = '_target_tuple_map'
186
187 val = cls._CACHE.setdefault(CACHE_ATTR, {})
188 if not target in val:
David James66a09c42012-11-05 13:31:38 -0800189 if target == 'host':
Mike Frysinger66bfde52017-09-12 16:42:57 -0400190 conf = {
191 'crosspkgs': [],
192 'target': toolchain.GetHostTuple(),
193 }
194 manual_pkgs = dict((pkg, cat) for cat, pkg in
195 [x.split('/') for x in HOST_PACKAGES])
196 else:
197 # Build the crossdev command.
198 cmd = ['crossdev', '--show-target-cfg', '--ex-gdb']
199 if target in TARGET_COMPILER_RT_ENABLED:
200 cmd.extend(CROSSDEV_COMPILER_RT_ARGS)
201 if target in TARGET_GO_ENABLED:
202 cmd.extend(CROSSDEV_GO_ARGS)
203 if target in TARGET_LLVM_PKGS_ENABLED:
204 for pkg in LLVM_PKGS_TABLE:
205 cmd.extend(LLVM_PKGS_TABLE[pkg])
206 cmd.extend(['-t', target])
207 # Catch output of crossdev.
208 out = cros_build_lib.RunCommand(
209 cmd, print_cmd=False, redirect_stdout=True).output.splitlines()
210 # List of tuples split at the first '=', converted into dict.
211 conf = dict((k, cros_build_lib.ShellUnquote(v))
212 for k, v in (x.split('=', 1) for x in out))
213 conf['crosspkgs'] = conf['crosspkgs'].split()
Han Shene23782f2016-02-18 12:20:00 -0800214
Mike Frysinger66bfde52017-09-12 16:42:57 -0400215 manual_pkgs = cls.MANUAL_PKGS
216
217 for pkg, cat in manual_pkgs.items():
Mike Frysinger3bba5032016-09-20 14:15:04 -0400218 conf[pkg + '_pn'] = pkg
219 conf[pkg + '_category'] = cat
220 if pkg not in conf['crosspkgs']:
221 conf['crosspkgs'].append(pkg)
Han Shene23782f2016-02-18 12:20:00 -0800222
223 val[target] = conf
224
David James66a09c42012-11-05 13:31:38 -0800225 return val[target]
226
227 @classmethod
228 def UpdateTargets(cls, targets, usepkg, config_only=False):
229 """Calls crossdev to initialize a cross target.
230
231 Args:
Don Garrett25f309a2014-03-19 14:02:12 -0700232 targets: The list of targets to initialize using crossdev.
233 usepkg: Copies the commandline opts.
234 config_only: Just update.
David James66a09c42012-11-05 13:31:38 -0800235 """
236 configured_targets = cls._CACHE.setdefault('configured_targets', [])
237
238 cmdbase = ['crossdev', '--show-fail-log']
239 cmdbase.extend(['--env', 'FEATURES=splitdebug'])
240 # Pick stable by default, and override as necessary.
241 cmdbase.extend(['-P', '--oneshot'])
242 if usepkg:
243 cmdbase.extend(['-P', '--getbinpkg',
244 '-P', '--usepkgonly',
245 '--without-headers'])
246
Christopher Wileyb22c0712015-06-02 10:37:03 -0700247 overlays = ' '.join((CHROMIUMOS_OVERLAY, ECLASS_OVERLAY, STABLE_OVERLAY))
David James66a09c42012-11-05 13:31:38 -0800248 cmdbase.extend(['--overlays', overlays])
249 cmdbase.extend(['--ov-output', CROSSDEV_OVERLAY])
250
251 for target in targets:
252 if config_only and target in configured_targets:
253 continue
254
255 cmd = cmdbase + ['-t', target]
256
257 for pkg in GetTargetPackages(target):
258 if pkg == 'gdb':
259 # Gdb does not have selectable versions.
260 cmd.append('--ex-gdb')
Manoj Guptab8181562017-05-21 10:18:59 -0700261 elif pkg == 'ex_compiler-rt':
262 cmd.extend(CROSSDEV_COMPILER_RT_ARGS)
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700263 elif pkg == 'ex_go':
264 # Go does not have selectable versions.
265 cmd.extend(CROSSDEV_GO_ARGS)
Manoj Gupta946abb42017-04-12 14:27:19 -0700266 elif pkg in LLVM_PKGS_TABLE:
267 cmd.extend(LLVM_PKGS_TABLE[pkg])
Han Shene23782f2016-02-18 12:20:00 -0800268 elif pkg in cls.MANUAL_PKGS:
269 pass
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700270 else:
271 # The first of the desired versions is the "primary" one.
272 version = GetDesiredPackageVersions(target, pkg)[0]
273 cmd.extend(['--%s' % pkg, version])
David James66a09c42012-11-05 13:31:38 -0800274
275 cmd.extend(targets[target]['crossdev'].split())
276 if config_only:
277 # In this case we want to just quietly reinit
278 cmd.append('--init-target')
279 cros_build_lib.RunCommand(cmd, print_cmd=False, redirect_stdout=True)
280 else:
281 cros_build_lib.RunCommand(cmd)
282
283 configured_targets.append(target)
284
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100285
Zdenek Behan508dcce2011-12-05 15:39:32 +0100286def GetPackageMap(target):
287 """Compiles a package map for the given target from the constants.
288
289 Uses a cache in target_version_map, that is dynamically filled in as needed,
290 since here everything is static data and the structuring is for ease of
291 configurability only.
292
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500293 Args:
294 target: The target for which to return a version map
Zdenek Behan508dcce2011-12-05 15:39:32 +0100295
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500296 Returns:
297 A map between packages and desired versions in internal format
298 (using the PACKAGE_* constants)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100299 """
300 if target in target_version_map:
301 return target_version_map[target]
302
303 # Start from copy of the global defaults.
304 result = copy.copy(DEFAULT_TARGET_VERSION_MAP)
305
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100306 for pkg in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100307 # prefer any specific overrides
308 if pkg in TARGET_VERSION_MAP.get(target, {}):
309 result[pkg] = TARGET_VERSION_MAP[target][pkg]
310 else:
311 # finally, if not already set, set a sane default
312 result.setdefault(pkg, DEFAULT_VERSION)
313 target_version_map[target] = result
314 return result
315
316
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100317def GetTargetPackages(target):
318 """Returns a list of packages for a given target."""
David James66a09c42012-11-05 13:31:38 -0800319 conf = Crossdev.GetConfig(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100320 # Undesired packages are denoted by empty ${pkg}_pn variable.
Han Shene23782f2016-02-18 12:20:00 -0800321 return [x for x in conf['crosspkgs'] if conf.get(x+'_pn')]
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100322
323
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100324# Portage helper functions:
325def GetPortagePackage(target, package):
326 """Returns a package name for the given target."""
David James66a09c42012-11-05 13:31:38 -0800327 conf = Crossdev.GetConfig(target)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100328 # Portage category:
Han Shene23782f2016-02-18 12:20:00 -0800329 if target == 'host' or package in Crossdev.MANUAL_PKGS:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100330 category = conf[package + '_category']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100331 else:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100332 category = conf['category']
333 # Portage package:
334 pn = conf[package + '_pn']
335 # Final package name:
Mike Frysinger422faf42014-11-12 23:16:48 -0500336 assert category
337 assert pn
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100338 return '%s/%s' % (category, pn)
339
340
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700341def PortageTrees(root):
342 """Return the portage trees for a given root."""
343 if root == '/':
344 return portage.db['/']
345 # The portage logic requires the path always end in a slash.
346 root = root.rstrip('/') + '/'
347 return portage.create_trees(target_root=root, config_root=root)[root]
348
349
350def GetInstalledPackageVersions(atom, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100351 """Extracts the list of current versions of a target, package pair.
352
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500353 Args:
354 atom: The atom to operate on (e.g. sys-devel/gcc)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700355 root: The root to check for installed packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100356
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500357 Returns:
358 The list of versions of the package currently installed.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100359 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100360 versions = []
Mike Frysinger506e75f2012-12-17 14:21:13 -0500361 # pylint: disable=E1101
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700362 for pkg in PortageTrees(root)['vartree'].dbapi.match(atom, use_cache=0):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100363 version = portage.versions.cpv_getversion(pkg)
364 versions.append(version)
365 return versions
366
367
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700368def GetStablePackageVersion(atom, installed, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100369 """Extracts the current stable version for a given package.
370
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500371 Args:
372 atom: The target/package to operate on eg. i686-pc-linux-gnu,gcc
373 installed: Whether we want installed packages or ebuilds
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700374 root: The root to use when querying packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100375
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500376 Returns:
377 A string containing the latest version.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100378 """
David James90239b92012-11-05 15:31:34 -0800379 pkgtype = 'vartree' if installed else 'porttree'
Mike Frysinger506e75f2012-12-17 14:21:13 -0500380 # pylint: disable=E1101
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700381 cpv = portage.best(PortageTrees(root)[pkgtype].dbapi.match(atom, use_cache=0))
David James90239b92012-11-05 15:31:34 -0800382 return portage.versions.cpv_getversion(cpv) if cpv else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100383
384
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700385def VersionListToNumeric(target, package, versions, installed, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100386 """Resolves keywords in a given version list for a particular package.
387
388 Resolving means replacing PACKAGE_STABLE with the actual number.
389
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500390 Args:
391 target: The target to operate on (e.g. i686-pc-linux-gnu)
392 package: The target/package to operate on (e.g. gcc)
393 versions: List of versions to resolve
394 installed: Query installed packages
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700395 root: The install root to use; ignored if |installed| is False.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100396
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500397 Returns:
398 List of purely numeric versions equivalent to argument
Zdenek Behan508dcce2011-12-05 15:39:32 +0100399 """
400 resolved = []
David James90239b92012-11-05 15:31:34 -0800401 atom = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700402 if not installed:
403 root = '/'
Zdenek Behan508dcce2011-12-05 15:39:32 +0100404 for version in versions:
405 if version == PACKAGE_STABLE:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700406 resolved.append(GetStablePackageVersion(atom, installed, root=root))
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400407 else:
Zdenek Behan508dcce2011-12-05 15:39:32 +0100408 resolved.append(version)
409 return resolved
410
411
412def GetDesiredPackageVersions(target, package):
413 """Produces the list of desired versions for each target, package pair.
414
415 The first version in the list is implicitly treated as primary, ie.
416 the version that will be initialized by crossdev and selected.
417
418 If the version is PACKAGE_STABLE, it really means the current version which
419 is emerged by using the package atom with no particular version key.
420 Since crossdev unmasks all packages by default, this will actually
421 mean 'unstable' in most cases.
422
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500423 Args:
424 target: The target to operate on (e.g. i686-pc-linux-gnu)
425 package: The target/package to operate on (e.g. gcc)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100426
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500427 Returns:
428 A list composed of either a version string, PACKAGE_STABLE
Zdenek Behan508dcce2011-12-05 15:39:32 +0100429 """
430 packagemap = GetPackageMap(target)
431
432 versions = []
433 if package in packagemap:
434 versions.append(packagemap[package])
435
436 return versions
437
438
439def TargetIsInitialized(target):
440 """Verifies if the given list of targets has been correctly initialized.
441
442 This determines whether we have to call crossdev while emerging
443 toolchain packages or can do it using emerge. Emerge is naturally
444 preferred, because all packages can be updated in a single pass.
445
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500446 Args:
447 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100448
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500449 Returns:
450 True if |target| is completely initialized, else False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100451 """
452 # Check if packages for the given target all have a proper version.
453 try:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100454 for package in GetTargetPackages(target):
David James66a09c42012-11-05 13:31:38 -0800455 atom = GetPortagePackage(target, package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100456 # Do we even want this package && is it initialized?
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400457 if not (GetStablePackageVersion(atom, True) and
458 GetStablePackageVersion(atom, False)):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100459 return False
460 return True
461 except cros_build_lib.RunCommandError:
462 # Fails - The target has likely never been initialized before.
463 return False
464
465
466def RemovePackageMask(target):
467 """Removes a package.mask file for the given platform.
468
469 The pre-existing package.mask files can mess with the keywords.
470
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500471 Args:
472 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100473 """
474 maskfile = os.path.join('/etc/portage/package.mask', 'cross-' + target)
Brian Harringaf019fb2012-05-10 15:06:13 -0700475 osutils.SafeUnlink(maskfile)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100476
477
Zdenek Behan508dcce2011-12-05 15:39:32 +0100478# Main functions performing the actual update steps.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700479def RebuildLibtool(root='/'):
Mike Frysingerc880a962013-11-08 13:59:06 -0500480 """Rebuild libtool as needed
481
482 Libtool hardcodes full paths to internal gcc files, so whenever we upgrade
483 gcc, libtool will break. We can't use binary packages either as those will
484 most likely be compiled against the previous version of gcc.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700485
486 Args:
487 root: The install root where we want libtool rebuilt.
Mike Frysingerc880a962013-11-08 13:59:06 -0500488 """
489 needs_update = False
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700490 with open(os.path.join(root, 'usr/bin/libtool')) as f:
Mike Frysingerc880a962013-11-08 13:59:06 -0500491 for line in f:
492 # Look for a line like:
493 # sys_lib_search_path_spec="..."
494 # It'll be a list of paths and gcc will be one of them.
495 if line.startswith('sys_lib_search_path_spec='):
496 line = line.rstrip()
497 for path in line.split('=', 1)[1].strip('"').split():
Mike Frysinger3bba5032016-09-20 14:15:04 -0400498 root_path = os.path.join(root, path.lstrip(os.path.sep))
499 logging.debug('Libtool: checking %s', root_path)
500 if not os.path.exists(root_path):
501 logging.info('Rebuilding libtool after gcc upgrade')
502 logging.info(' %s', line)
503 logging.info(' missing path: %s', path)
Mike Frysingerc880a962013-11-08 13:59:06 -0500504 needs_update = True
505 break
506
507 if needs_update:
508 break
509
510 if needs_update:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700511 cmd = [EMERGE_CMD, '--oneshot']
512 if root != '/':
513 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
514 cmd.append('sys-devel/libtool')
Mike Frysingerc880a962013-11-08 13:59:06 -0500515 cros_build_lib.RunCommand(cmd)
Mike Frysinger3bba5032016-09-20 14:15:04 -0400516 else:
517 logging.debug('Libtool is up-to-date; no need to rebuild')
Mike Frysingerc880a962013-11-08 13:59:06 -0500518
519
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700520def UpdateTargets(targets, usepkg, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100521 """Determines which packages need update/unmerge and defers to portage.
522
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500523 Args:
524 targets: The list of targets to update
525 usepkg: Copies the commandline option
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700526 root: The install root in which we want packages updated.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100527 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100528 # For each target, we do two things. Figure out the list of updates,
529 # and figure out the appropriate keywords/masks. Crossdev will initialize
530 # these, but they need to be regenerated on every update.
Mike Frysinger3bba5032016-09-20 14:15:04 -0400531 logging.info('Determining required toolchain updates...')
David James90239b92012-11-05 15:31:34 -0800532 mergemap = {}
Zdenek Behan508dcce2011-12-05 15:39:32 +0100533 for target in targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400534 logging.debug('Updating target %s', target)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100535 # Record the highest needed version for each target, for masking purposes.
536 RemovePackageMask(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100537 for package in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100538 # Portage name for the package
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400539 logging.debug(' Checking package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100540 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700541 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100542 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200543 desired_num = VersionListToNumeric(target, package, desired, False)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100544 mergemap[pkg] = set(desired_num).difference(current)
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400545 logging.debug(' %s -> %s', current, desired_num)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100546
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400547 packages = [pkg for pkg, vers in mergemap.items() if vers]
Zdenek Behan508dcce2011-12-05 15:39:32 +0100548 if not packages:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400549 logging.info('Nothing to update!')
David Jamesf8c672f2012-11-06 13:38:11 -0800550 return False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100551
Mike Frysinger3bba5032016-09-20 14:15:04 -0400552 logging.info('Updating packages:')
553 logging.info('%s', packages)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100554
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100555 cmd = [EMERGE_CMD, '--oneshot', '--update']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100556 if usepkg:
557 cmd.extend(['--getbinpkg', '--usepkgonly'])
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700558 if root != '/':
559 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100560
561 cmd.extend(packages)
562 cros_build_lib.RunCommand(cmd)
David Jamesf8c672f2012-11-06 13:38:11 -0800563 return True
Zdenek Behan508dcce2011-12-05 15:39:32 +0100564
565
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700566def CleanTargets(targets, root='/'):
567 """Unmerges old packages that are assumed unnecessary.
568
569 Args:
570 targets: The list of targets to clean up.
571 root: The install root in which we want packages cleaned up.
572 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100573 unmergemap = {}
574 for target in targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400575 logging.debug('Cleaning target %s', target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100576 for package in GetTargetPackages(target):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400577 logging.debug(' Cleaning package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100578 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700579 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100580 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2fcb0aa2015-05-21 14:51:41 -0700581 # NOTE: This refers to installed packages (vartree) rather than the
582 # Portage version (porttree and/or bintree) when determining the current
583 # version. While this isn't the most accurate thing to do, it is probably
584 # a good simple compromise, which should have the desired result of
585 # uninstalling everything but the latest installed version. In
586 # particular, using the bintree (--usebinpkg) requires a non-trivial
587 # binhost sync and is probably more complex than useful.
Zdenek Behan699ddd32012-04-13 07:14:08 +0200588 desired_num = VersionListToNumeric(target, package, desired, True)
589 if not set(desired_num).issubset(current):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400590 logging.warning('Error detecting stable version for %s, '
591 'skipping clean!', pkg)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200592 return
Zdenek Behan508dcce2011-12-05 15:39:32 +0100593 unmergemap[pkg] = set(current).difference(desired_num)
594
595 # Cleaning doesn't care about consistency and rebuilding package.* files.
596 packages = []
597 for pkg, vers in unmergemap.iteritems():
598 packages.extend('=%s-%s' % (pkg, ver) for ver in vers if ver != '9999')
599
600 if packages:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400601 logging.info('Cleaning packages:')
602 logging.info('%s', packages)
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100603 cmd = [EMERGE_CMD, '--unmerge']
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700604 if root != '/':
605 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100606 cmd.extend(packages)
607 cros_build_lib.RunCommand(cmd)
608 else:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400609 logging.info('Nothing to clean!')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100610
611
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700612def SelectActiveToolchains(targets, suffixes, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100613 """Runs gcc-config and binutils-config to select the desired.
614
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500615 Args:
616 targets: The targets to select
617 suffixes: Optional target-specific hacks
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700618 root: The root where we want to select toolchain versions.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100619 """
620 for package in ['gcc', 'binutils']:
621 for target in targets:
622 # Pick the first version in the numbered list as the selected one.
623 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700624 desired_num = VersionListToNumeric(target, package, desired, True,
625 root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100626 desired = desired_num[0]
627 # *-config does not play revisions, strip them, keep just PV.
628 desired = portage.versions.pkgsplit('%s-%s' % (package, desired))[1]
629
630 if target == 'host':
631 # *-config is the only tool treating host identically (by tuple).
David James27ac4ae2012-12-03 23:16:15 -0800632 target = toolchain.GetHostTuple()
Zdenek Behan508dcce2011-12-05 15:39:32 +0100633
634 # And finally, attach target to it.
635 desired = '%s-%s' % (target, desired)
636
637 # Target specific hacks
638 if package in suffixes:
639 if target in suffixes[package]:
640 desired += suffixes[package][target]
641
David James7ec5efc2012-11-06 09:39:49 -0800642 extra_env = {'CHOST': target}
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700643 if root != '/':
644 extra_env['ROOT'] = root
David James7ec5efc2012-11-06 09:39:49 -0800645 cmd = ['%s-config' % package, '-c', target]
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500646 result = cros_build_lib.RunCommand(
647 cmd, print_cmd=False, redirect_stdout=True, extra_env=extra_env)
648 current = result.output.splitlines()[0]
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700649
650 # Do not reconfig when the current is live or nothing needs to be done.
651 extra_env = {'ROOT': root} if root != '/' else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100652 if current != desired and current != '9999':
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500653 cmd = [package + '-config', desired]
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700654 cros_build_lib.RunCommand(cmd, print_cmd=False, extra_env=extra_env)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100655
656
Mike Frysinger35247af2012-11-16 18:58:06 -0500657def ExpandTargets(targets_wanted):
658 """Expand any possible toolchain aliases into full targets
659
660 This will expand 'all' and 'sdk' into the respective toolchain tuples.
661
662 Args:
663 targets_wanted: The targets specified by the user.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500664
Mike Frysinger35247af2012-11-16 18:58:06 -0500665 Returns:
Gilad Arnold8195b532015-04-07 10:56:30 +0300666 Dictionary of concrete targets and their toolchain tuples.
Mike Frysinger35247af2012-11-16 18:58:06 -0500667 """
Mike Frysinger35247af2012-11-16 18:58:06 -0500668 targets_wanted = set(targets_wanted)
Don Garrettc0c74002015-10-09 12:58:19 -0700669 if targets_wanted == set(['boards']):
670 # Only pull targets from the included boards.
Gilad Arnold8195b532015-04-07 10:56:30 +0300671 return {}
672
673 all_targets = toolchain.GetAllTargets()
Mike Frysinger35247af2012-11-16 18:58:06 -0500674 if targets_wanted == set(['all']):
Gilad Arnold8195b532015-04-07 10:56:30 +0300675 return all_targets
676 if targets_wanted == set(['sdk']):
Mike Frysinger35247af2012-11-16 18:58:06 -0500677 # Filter out all the non-sdk toolchains as we don't want to mess
678 # with those in all of our builds.
Gilad Arnold8195b532015-04-07 10:56:30 +0300679 return toolchain.FilterToolchains(all_targets, 'sdk', True)
680
681 # Verify user input.
682 nonexistent = targets_wanted.difference(all_targets)
683 if nonexistent:
684 raise ValueError('Invalid targets: %s', ','.join(nonexistent))
685 return {t: all_targets[t] for t in targets_wanted}
Mike Frysinger35247af2012-11-16 18:58:06 -0500686
687
David Jamesf8c672f2012-11-06 13:38:11 -0800688def UpdateToolchains(usepkg, deleteold, hostonly, reconfig,
Don Garrettc0c74002015-10-09 12:58:19 -0700689 targets_wanted, boards_wanted, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100690 """Performs all steps to create a synchronized toolchain enviroment.
691
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500692 Args:
693 usepkg: Use prebuilt packages
694 deleteold: Unmerge deprecated packages
695 hostonly: Only setup the host toolchain
696 reconfig: Reload crossdev config and reselect toolchains
697 targets_wanted: All the targets to update
698 boards_wanted: Load targets from these boards
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700699 root: The root in which to install the toolchains.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100700 """
David Jamesf8c672f2012-11-06 13:38:11 -0800701 targets, crossdev_targets, reconfig_targets = {}, {}, {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100702 if not hostonly:
703 # For hostonly, we can skip most of the below logic, much of which won't
704 # work on bare systems where this is useful.
Mike Frysinger35247af2012-11-16 18:58:06 -0500705 targets = ExpandTargets(targets_wanted)
Mike Frysinger7ccee992012-06-01 21:27:59 -0400706
Don Garrettc0c74002015-10-09 12:58:19 -0700707 # Now re-add any targets that might be from this board. This is to
Gilad Arnold8195b532015-04-07 10:56:30 +0300708 # allow unofficial boards to declare their own toolchains.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400709 for board in boards_wanted:
David James27ac4ae2012-12-03 23:16:15 -0800710 targets.update(toolchain.GetToolchainsForBoard(board))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100711
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100712 # First check and initialize all cross targets that need to be.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400713 for target in targets:
714 if TargetIsInitialized(target):
715 reconfig_targets[target] = targets[target]
716 else:
717 crossdev_targets[target] = targets[target]
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100718 if crossdev_targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400719 logging.info('The following targets need to be re-initialized:')
720 logging.info('%s', crossdev_targets)
David James66a09c42012-11-05 13:31:38 -0800721 Crossdev.UpdateTargets(crossdev_targets, usepkg)
Zdenek Behan8be29ba2012-05-29 23:10:34 +0200722 # Those that were not initialized may need a config update.
David James66a09c42012-11-05 13:31:38 -0800723 Crossdev.UpdateTargets(reconfig_targets, usepkg, config_only=True)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100724
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100725 # We want host updated.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400726 targets['host'] = {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100727
728 # Now update all packages.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700729 if UpdateTargets(targets, usepkg, root=root) or crossdev_targets or reconfig:
730 SelectActiveToolchains(targets, CONFIG_TARGET_SUFFIXES, root=root)
David James7ec5efc2012-11-06 09:39:49 -0800731
732 if deleteold:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700733 CleanTargets(targets, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100734
Mike Frysingerc880a962013-11-08 13:59:06 -0500735 # Now that we've cleared out old versions, see if we need to rebuild
736 # anything. Can't do this earlier as it might not be broken.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700737 RebuildLibtool(root=root)
Mike Frysingerc880a962013-11-08 13:59:06 -0500738
Zdenek Behan508dcce2011-12-05 15:39:32 +0100739
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -0700740def ShowConfig(name):
741 """Show the toolchain tuples used by |name|
Mike Frysinger35247af2012-11-16 18:58:06 -0500742
743 Args:
Don Garrettc0c74002015-10-09 12:58:19 -0700744 name: The board name to query.
Mike Frysinger35247af2012-11-16 18:58:06 -0500745 """
Don Garrettc0c74002015-10-09 12:58:19 -0700746 toolchains = toolchain.GetToolchainsForBoard(name)
Mike Frysinger35247af2012-11-16 18:58:06 -0500747 # Make sure we display the default toolchain first.
Mike Frysinger3bba5032016-09-20 14:15:04 -0400748 # Note: Do not use logging here as this is meant to be used by other tools.
Mike Frysinger383367e2014-09-16 15:06:17 -0400749 print(','.join(
David James27ac4ae2012-12-03 23:16:15 -0800750 toolchain.FilterToolchains(toolchains, 'default', True).keys() +
Mike Frysinger383367e2014-09-16 15:06:17 -0400751 toolchain.FilterToolchains(toolchains, 'default', False).keys()))
Mike Frysinger35247af2012-11-16 18:58:06 -0500752
753
Mike Frysinger35247af2012-11-16 18:58:06 -0500754def GeneratePathWrapper(root, wrappath, path):
755 """Generate a shell script to execute another shell script
756
757 Since we can't symlink a wrapped ELF (see GenerateLdsoWrapper) because the
758 argv[0] won't be pointing to the correct path, generate a shell script that
759 just executes another program with its full path.
760
761 Args:
762 root: The root tree to generate scripts inside of
763 wrappath: The full path (inside |root|) to create the wrapper
764 path: The target program which this wrapper will execute
765 """
766 replacements = {
767 'path': path,
768 'relroot': os.path.relpath('/', os.path.dirname(wrappath)),
769 }
770 wrapper = """#!/bin/sh
771base=$(realpath "$0")
772basedir=${base%%/*}
773exec "${basedir}/%(relroot)s%(path)s" "$@"
774""" % replacements
775 root_wrapper = root + wrappath
776 if os.path.islink(root_wrapper):
777 os.unlink(root_wrapper)
778 else:
779 osutils.SafeMakedirs(os.path.dirname(root_wrapper))
780 osutils.WriteFile(root_wrapper, wrapper)
Mike Frysinger60ec1012013-10-21 00:11:10 -0400781 os.chmod(root_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -0500782
783
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -0700784def FixClangXXWrapper(root, path):
785 """Fix wrapper shell scripts and symlinks for invoking clang++
786
787 In a typical installation, clang++ symlinks to clang, which symlinks to the
788 elf executable. The executable distinguishes between clang and clang++ based
789 on argv[0].
790
791 When invoked through the LdsoWrapper, argv[0] always contains the path to the
792 executable elf file, making clang/clang++ invocations indistinguishable.
793
794 This function detects if the elf executable being wrapped is clang-X.Y, and
795 fixes wrappers/symlinks as necessary so that clang++ will work correctly.
796
797 The calling sequence now becomes:
798 -) clang++ invocation turns into clang++-3.9 (which is a copy of clang-3.9,
799 the Ldsowrapper).
800 -) clang++-3.9 uses the Ldso to invoke clang++-3.9.elf, which is a symlink
801 to the original clang-3.9 elf.
802 -) The difference this time is that inside the elf file execution, $0 is
803 set as .../usr/bin/clang++-3.9.elf, which contains 'clang++' in the name.
804
805 Args:
806 root: The root tree to generate scripts / symlinks inside of
807 path: The target elf for which LdsoWrapper was created
808 """
809 if re.match(r'/usr/bin/clang-\d+\.\d+$', path):
810 logging.info('fixing clang++ invocation for %s', path)
811 clangdir = os.path.dirname(root + path)
812 clang = os.path.basename(path)
813 clangxx = clang.replace('clang', 'clang++')
814
815 # Create a symlink clang++-X.Y.elf to point to clang-X.Y.elf
816 os.symlink(clang + '.elf', os.path.join(clangdir, clangxx + '.elf'))
817
818 # Create a hardlink clang++-X.Y pointing to clang-X.Y
819 os.link(os.path.join(clangdir, clang), os.path.join(clangdir, clangxx))
820
821 # Adjust the clang++ symlink to point to clang++-X.Y
822 os.unlink(os.path.join(clangdir, 'clang++'))
823 os.symlink(clangxx, os.path.join(clangdir, 'clang++'))
824
825
Mike Frysinger35247af2012-11-16 18:58:06 -0500826def FileIsCrosSdkElf(elf):
827 """Determine if |elf| is an ELF that we execute in the cros_sdk
828
829 We don't need this to be perfect, just quick. It makes sure the ELF
830 is a 64bit LSB x86_64 ELF. That is the native type of cros_sdk.
831
832 Args:
833 elf: The file to check
Mike Frysinger1a736a82013-12-12 01:50:59 -0500834
Mike Frysinger35247af2012-11-16 18:58:06 -0500835 Returns:
836 True if we think |elf| is a native ELF
837 """
838 with open(elf) as f:
839 data = f.read(20)
840 # Check the magic number, EI_CLASS, EI_DATA, and e_machine.
841 return (data[0:4] == '\x7fELF' and
842 data[4] == '\x02' and
843 data[5] == '\x01' and
844 data[18] == '\x3e')
845
846
847def IsPathPackagable(ptype, path):
848 """Should the specified file be included in a toolchain package?
849
850 We only need to handle files as we'll create dirs as we need them.
851
852 Further, trim files that won't be useful:
853 - non-english translations (.mo) since it'd require env vars
854 - debug files since these are for the host compiler itself
855 - info/man pages as they're big, and docs are online, and the
856 native docs should work fine for the most part (`man gcc`)
857
858 Args:
859 ptype: A string describing the path type (i.e. 'file' or 'dir' or 'sym')
860 path: The full path to inspect
Mike Frysinger1a736a82013-12-12 01:50:59 -0500861
Mike Frysinger35247af2012-11-16 18:58:06 -0500862 Returns:
863 True if we want to include this path in the package
864 """
865 return not (ptype in ('dir',) or
866 path.startswith('/usr/lib/debug/') or
867 os.path.splitext(path)[1] == '.mo' or
868 ('/man/' in path or '/info/' in path))
869
870
871def ReadlinkRoot(path, root):
872 """Like os.readlink(), but relative to a |root|
873
874 Args:
875 path: The symlink to read
876 root: The path to use for resolving absolute symlinks
Mike Frysinger1a736a82013-12-12 01:50:59 -0500877
Mike Frysinger35247af2012-11-16 18:58:06 -0500878 Returns:
879 A fully resolved symlink path
880 """
881 while os.path.islink(root + path):
882 path = os.path.join(os.path.dirname(path), os.readlink(root + path))
883 return path
884
885
886def _GetFilesForTarget(target, root='/'):
887 """Locate all the files to package for |target|
888
889 This does not cover ELF dependencies.
890
891 Args:
892 target: The toolchain target name
893 root: The root path to pull all packages from
Mike Frysinger1a736a82013-12-12 01:50:59 -0500894
Mike Frysinger35247af2012-11-16 18:58:06 -0500895 Returns:
896 A tuple of a set of all packable paths, and a set of all paths which
897 are also native ELFs
898 """
899 paths = set()
900 elfs = set()
901
902 # Find all the files owned by the packages for this target.
903 for pkg in GetTargetPackages(target):
Mike Frysinger35247af2012-11-16 18:58:06 -0500904
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700905 # Skip Go compiler from redistributable packages.
906 # The "go" executable has GOROOT=/usr/lib/go/${CTARGET} hardcoded
907 # into it. Due to this, the toolchain cannot be unpacked anywhere
908 # else and be readily useful. To enable packaging Go, we need to:
909 # -) Tweak the wrappers/environment to override GOROOT
910 # automatically based on the unpack location.
911 # -) Make sure the ELF dependency checking and wrapping logic
912 # below skips the Go toolchain executables and libraries.
913 # -) Make sure the packaging process maintains the relative
914 # timestamps of precompiled standard library packages.
915 # (see dev-lang/go ebuild for details).
916 if pkg == 'ex_go':
917 continue
918
Mike Frysinger35247af2012-11-16 18:58:06 -0500919 atom = GetPortagePackage(target, pkg)
920 cat, pn = atom.split('/')
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700921 ver = GetInstalledPackageVersions(atom, root=root)[0]
Ralph Nathan03047282015-03-23 11:09:32 -0700922 logging.info('packaging %s-%s', atom, ver)
Mike Frysinger35247af2012-11-16 18:58:06 -0500923
924 # pylint: disable=E1101
925 dblink = portage.dblink(cat, pn + '-' + ver, myroot=root,
926 settings=portage.settings)
927 contents = dblink.getcontents()
928 for obj in contents:
929 ptype = contents[obj][0]
930 if not IsPathPackagable(ptype, obj):
931 continue
932
933 if ptype == 'obj':
934 # For native ELFs, we need to pull in their dependencies too.
935 if FileIsCrosSdkElf(obj):
936 elfs.add(obj)
937 paths.add(obj)
938
939 return paths, elfs
940
941
942def _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500943 path_rewrite_func=lambda x: x, root='/'):
Mike Frysinger35247af2012-11-16 18:58:06 -0500944 """Link in all packable files and their runtime dependencies
945
946 This also wraps up executable ELFs with helper scripts.
947
948 Args:
949 output_dir: The output directory to store files
950 paths: All the files to include
951 elfs: All the files which are ELFs (a subset of |paths|)
952 ldpaths: A dict of static ldpath information
953 path_rewrite_func: User callback to rewrite paths in output_dir
954 root: The root path to pull all packages/files from
955 """
956 # Link in all the files.
957 sym_paths = []
958 for path in paths:
959 new_path = path_rewrite_func(path)
960 dst = output_dir + new_path
961 osutils.SafeMakedirs(os.path.dirname(dst))
962
963 # Is this a symlink which we have to rewrite or wrap?
964 # Delay wrap check until after we have created all paths.
965 src = root + path
966 if os.path.islink(src):
967 tgt = os.readlink(src)
968 if os.path.sep in tgt:
969 sym_paths.append((new_path, lddtree.normpath(ReadlinkRoot(src, root))))
970
971 # Rewrite absolute links to relative and then generate the symlink
972 # ourselves. All other symlinks can be hardlinked below.
973 if tgt[0] == '/':
974 tgt = os.path.relpath(tgt, os.path.dirname(new_path))
975 os.symlink(tgt, dst)
976 continue
977
978 os.link(src, dst)
979
980 # Now see if any of the symlinks need to be wrapped.
981 for sym, tgt in sym_paths:
982 if tgt in elfs:
983 GeneratePathWrapper(output_dir, sym, tgt)
984
985 # Locate all the dependencies for all the ELFs. Stick them all in the
986 # top level "lib" dir to make the wrapper simpler. This exact path does
987 # not matter since we execute ldso directly, and we tell the ldso the
988 # exact path to search for its libraries.
989 libdir = os.path.join(output_dir, 'lib')
990 osutils.SafeMakedirs(libdir)
991 donelibs = set()
992 for elf in elfs:
Mike Frysingerea7688e2014-07-31 22:40:33 -0400993 e = lddtree.ParseELF(elf, root=root, ldpaths=ldpaths)
Mike Frysinger35247af2012-11-16 18:58:06 -0500994 interp = e['interp']
995 if interp:
996 # Generate a wrapper if it is executable.
Mike Frysingerc2ec0902013-03-26 01:28:45 -0400997 interp = os.path.join('/lib', os.path.basename(interp))
998 lddtree.GenerateLdsoWrapper(output_dir, path_rewrite_func(elf), interp,
999 libpaths=e['rpath'] + e['runpath'])
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -07001000 FixClangXXWrapper(output_dir, path_rewrite_func(elf))
Mike Frysinger35247af2012-11-16 18:58:06 -05001001
1002 for lib, lib_data in e['libs'].iteritems():
1003 if lib in donelibs:
1004 continue
1005
1006 src = path = lib_data['path']
1007 if path is None:
Ralph Nathan446aee92015-03-23 14:44:56 -07001008 logging.warning('%s: could not locate %s', elf, lib)
Mike Frysinger35247af2012-11-16 18:58:06 -05001009 continue
1010 donelibs.add(lib)
1011
1012 # Needed libs are the SONAME, but that is usually a symlink, not a
1013 # real file. So link in the target rather than the symlink itself.
1014 # We have to walk all the possible symlinks (SONAME could point to a
1015 # symlink which points to a symlink), and we have to handle absolute
1016 # ourselves (since we have a "root" argument).
1017 dst = os.path.join(libdir, os.path.basename(path))
1018 src = ReadlinkRoot(src, root)
1019
1020 os.link(root + src, dst)
1021
1022
1023def _EnvdGetVar(envd, var):
1024 """Given a Gentoo env.d file, extract a var from it
1025
1026 Args:
1027 envd: The env.d file to load (may be a glob path)
1028 var: The var to extract
Mike Frysinger1a736a82013-12-12 01:50:59 -05001029
Mike Frysinger35247af2012-11-16 18:58:06 -05001030 Returns:
1031 The value of |var|
1032 """
1033 envds = glob.glob(envd)
1034 assert len(envds) == 1, '%s: should have exactly 1 env.d file' % envd
1035 envd = envds[0]
1036 return cros_build_lib.LoadKeyValueFile(envd)[var]
1037
1038
1039def _ProcessBinutilsConfig(target, output_dir):
1040 """Do what binutils-config would have done"""
1041 binpath = os.path.join('/bin', target + '-')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001042
1043 # Locate the bin dir holding the gold linker.
1044 binutils_bin_path = os.path.join(output_dir, 'usr', toolchain.GetHostTuple(),
1045 target, 'binutils-bin')
1046 globpath = os.path.join(binutils_bin_path, '*-gold')
Mike Frysinger35247af2012-11-16 18:58:06 -05001047 srcpath = glob.glob(globpath)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001048 if not srcpath:
1049 # Maybe this target doesn't support gold.
1050 globpath = os.path.join(binutils_bin_path, '*')
1051 srcpath = glob.glob(globpath)
1052 assert len(srcpath) == 1, ('%s: matched more than one path (but not *-gold)'
1053 % globpath)
1054 srcpath = srcpath[0]
1055 ld_path = os.path.join(srcpath, 'ld')
1056 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1057 ld_path = os.path.join(srcpath, 'ld.bfd')
1058 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1059 ld_path = os.path.join(srcpath, 'ld.gold')
1060 assert not os.path.exists(ld_path), ('%s: exists, but gold dir does not!'
1061 % ld_path)
1062
1063 # Nope, no gold support to be found.
1064 gold_supported = False
Ralph Nathan446aee92015-03-23 14:44:56 -07001065 logging.warning('%s: binutils lacks support for the gold linker', target)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001066 else:
1067 assert len(srcpath) == 1, '%s: did not match exactly 1 path' % globpath
Mike Frysinger78b7a812014-11-26 19:45:23 -05001068 srcpath = srcpath[0]
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001069
Rahul Chaudhry4891b4d2017-03-08 10:31:27 -08001070 # Package the binutils-bin directory without the '-gold' suffix
1071 # if gold is not enabled as the default linker for this target.
1072 gold_supported = CONFIG_TARGET_SUFFIXES['binutils'].get(target) == '-gold'
1073 if not gold_supported:
1074 srcpath = srcpath[:-len('-gold')]
1075 ld_path = os.path.join(srcpath, 'ld')
1076 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1077
Mike Frysinger78b7a812014-11-26 19:45:23 -05001078 srcpath = srcpath[len(output_dir):]
Mike Frysinger35247af2012-11-16 18:58:06 -05001079 gccpath = os.path.join('/usr', 'libexec', 'gcc')
1080 for prog in os.listdir(output_dir + srcpath):
1081 # Skip binaries already wrapped.
1082 if not prog.endswith('.real'):
1083 GeneratePathWrapper(output_dir, binpath + prog,
1084 os.path.join(srcpath, prog))
1085 GeneratePathWrapper(output_dir, os.path.join(gccpath, prog),
1086 os.path.join(srcpath, prog))
1087
David James27ac4ae2012-12-03 23:16:15 -08001088 libpath = os.path.join('/usr', toolchain.GetHostTuple(), target, 'lib')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001089 envd = os.path.join(output_dir, 'etc', 'env.d', 'binutils', '*')
1090 if gold_supported:
1091 envd += '-gold'
Rahul Chaudhry4891b4d2017-03-08 10:31:27 -08001092 else:
1093 # If gold is not enabled as the default linker and 2 env.d
1094 # files exist, pick the one without the '-gold' suffix.
1095 envds = sorted(glob.glob(envd))
1096 if len(envds) == 2 and envds[1] == envds[0] + '-gold':
1097 envd = envds[0]
Mike Frysinger35247af2012-11-16 18:58:06 -05001098 srcpath = _EnvdGetVar(envd, 'LIBPATH')
1099 os.symlink(os.path.relpath(srcpath, os.path.dirname(libpath)),
1100 output_dir + libpath)
1101
1102
1103def _ProcessGccConfig(target, output_dir):
1104 """Do what gcc-config would have done"""
1105 binpath = '/bin'
1106 envd = os.path.join(output_dir, 'etc', 'env.d', 'gcc', '*')
1107 srcpath = _EnvdGetVar(envd, 'GCC_PATH')
1108 for prog in os.listdir(output_dir + srcpath):
1109 # Skip binaries already wrapped.
1110 if (not prog.endswith('.real') and
1111 not prog.endswith('.elf') and
1112 prog.startswith(target)):
1113 GeneratePathWrapper(output_dir, os.path.join(binpath, prog),
1114 os.path.join(srcpath, prog))
1115 return srcpath
1116
1117
Frank Henigman179ec7c2015-02-06 03:01:09 -05001118def _ProcessSysrootWrappers(_target, output_dir, srcpath):
1119 """Remove chroot-specific things from our sysroot wrappers"""
Mike Frysinger35247af2012-11-16 18:58:06 -05001120 # Disable ccache since we know it won't work outside of chroot.
Frank Henigman179ec7c2015-02-06 03:01:09 -05001121 for sysroot_wrapper in glob.glob(os.path.join(
1122 output_dir + srcpath, 'sysroot_wrapper*')):
1123 contents = osutils.ReadFile(sysroot_wrapper).splitlines()
1124 for num in xrange(len(contents)):
1125 if '@CCACHE_DEFAULT@' in contents[num]:
Caroline Ticece9e9232017-06-02 09:38:42 -07001126 assert 'True' in contents[num]
1127 contents[num] = contents[num].replace('True', 'False')
Frank Henigman179ec7c2015-02-06 03:01:09 -05001128 break
1129 # Can't update the wrapper in place since it's a hardlink to a file in /.
1130 os.unlink(sysroot_wrapper)
1131 osutils.WriteFile(sysroot_wrapper, '\n'.join(contents))
1132 os.chmod(sysroot_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -05001133
1134
1135def _ProcessDistroCleanups(target, output_dir):
1136 """Clean up the tree and remove all distro-specific requirements
1137
1138 Args:
1139 target: The toolchain target name
1140 output_dir: The output directory to clean up
1141 """
1142 _ProcessBinutilsConfig(target, output_dir)
1143 gcc_path = _ProcessGccConfig(target, output_dir)
Frank Henigman179ec7c2015-02-06 03:01:09 -05001144 _ProcessSysrootWrappers(target, output_dir, gcc_path)
Mike Frysinger35247af2012-11-16 18:58:06 -05001145
1146 osutils.RmDir(os.path.join(output_dir, 'etc'))
1147
1148
1149def CreatePackagableRoot(target, output_dir, ldpaths, root='/'):
1150 """Setup a tree from the packages for the specified target
1151
1152 This populates a path with all the files from toolchain packages so that
1153 a tarball can easily be generated from the result.
1154
1155 Args:
1156 target: The target to create a packagable root from
1157 output_dir: The output directory to place all the files
1158 ldpaths: A dict of static ldpath information
1159 root: The root path to pull all packages/files from
1160 """
1161 # Find all the files owned by the packages for this target.
1162 paths, elfs = _GetFilesForTarget(target, root=root)
1163
1164 # Link in all the package's files, any ELF dependencies, and wrap any
1165 # executable ELFs with helper scripts.
1166 def MoveUsrBinToBin(path):
Han Shen699ea192016-03-02 10:42:47 -08001167 """Move /usr/bin to /bin so people can just use that toplevel dir
1168
1169 Note we do not apply this to clang - there is correlation between clang's
1170 search path for libraries / inclusion and its installation path.
1171 """
1172 if path.startswith('/usr/bin/') and path.find('clang') == -1:
1173 return path[4:]
1174 return path
Mike Frysinger35247af2012-11-16 18:58:06 -05001175 _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
1176 path_rewrite_func=MoveUsrBinToBin, root=root)
1177
1178 # The packages, when part of the normal distro, have helper scripts
1179 # that setup paths and such. Since we are making this standalone, we
1180 # need to preprocess all that ourselves.
1181 _ProcessDistroCleanups(target, output_dir)
1182
1183
1184def CreatePackages(targets_wanted, output_dir, root='/'):
1185 """Create redistributable cross-compiler packages for the specified targets
1186
1187 This creates toolchain packages that should be usable in conjunction with
1188 a downloaded sysroot (created elsewhere).
1189
1190 Tarballs (one per target) will be created in $PWD.
1191
1192 Args:
Don Garrett25f309a2014-03-19 14:02:12 -07001193 targets_wanted: The targets to package up.
1194 output_dir: The directory to put the packages in.
1195 root: The root path to pull all packages/files from.
Mike Frysinger35247af2012-11-16 18:58:06 -05001196 """
Ralph Nathan03047282015-03-23 11:09:32 -07001197 logging.info('Writing tarballs to %s', output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001198 osutils.SafeMakedirs(output_dir)
1199 ldpaths = lddtree.LoadLdpaths(root)
1200 targets = ExpandTargets(targets_wanted)
1201
David James4bc13702013-03-26 08:08:04 -07001202 with osutils.TempDir() as tempdir:
Mike Frysinger35247af2012-11-16 18:58:06 -05001203 # We have to split the root generation from the compression stages. This is
1204 # because we hardlink in all the files (to avoid overhead of reading/writing
1205 # the copies multiple times). But tar gets angry if a file's hardlink count
1206 # changes from when it starts reading a file to when it finishes.
1207 with parallel.BackgroundTaskRunner(CreatePackagableRoot) as queue:
1208 for target in targets:
1209 output_target_dir = os.path.join(tempdir, target)
1210 queue.put([target, output_target_dir, ldpaths, root])
1211
1212 # Build the tarball.
1213 with parallel.BackgroundTaskRunner(cros_build_lib.CreateTarball) as queue:
1214 for target in targets:
1215 tar_file = os.path.join(output_dir, target + '.tar.xz')
1216 queue.put([tar_file, os.path.join(tempdir, target)])
1217
1218
Mike Frysinger07534cf2017-09-12 17:40:21 -04001219def GetParser():
1220 """Return a command line parser."""
Mike Frysinger0c808452014-11-06 17:30:23 -05001221 parser = commandline.ArgumentParser(description=__doc__)
1222 parser.add_argument('-u', '--nousepkg',
1223 action='store_false', dest='usepkg', default=True,
1224 help='Use prebuilt packages if possible')
1225 parser.add_argument('-d', '--deleteold',
1226 action='store_true', dest='deleteold', default=False,
1227 help='Unmerge deprecated packages')
1228 parser.add_argument('-t', '--targets',
1229 dest='targets', default='sdk',
Gilad Arnold8195b532015-04-07 10:56:30 +03001230 help="Comma separated list of tuples. Special keywords "
Don Garrettc0c74002015-10-09 12:58:19 -07001231 "'host', 'sdk', 'boards', and 'all' are "
Gilad Arnold8195b532015-04-07 10:56:30 +03001232 "allowed. Defaults to 'sdk'.")
1233 parser.add_argument('--include-boards', default='', metavar='BOARDS',
1234 help='Comma separated list of boards whose toolchains we '
1235 'will always include. Default: none')
Mike Frysinger0c808452014-11-06 17:30:23 -05001236 parser.add_argument('--hostonly',
1237 dest='hostonly', default=False, action='store_true',
1238 help='Only setup the host toolchain. '
1239 'Useful for bootstrapping chroot')
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001240 parser.add_argument('--show-board-cfg', '--show-cfg',
1241 dest='cfg_name', default=None,
Don Garrettc0c74002015-10-09 12:58:19 -07001242 help='Board to list toolchains tuples for')
Mike Frysinger0c808452014-11-06 17:30:23 -05001243 parser.add_argument('--create-packages',
1244 action='store_true', default=False,
1245 help='Build redistributable packages')
1246 parser.add_argument('--output-dir', default=os.getcwd(), type='path',
1247 help='Output directory')
1248 parser.add_argument('--reconfig', default=False, action='store_true',
1249 help='Reload crossdev config and reselect toolchains')
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001250 parser.add_argument('--sysroot', type='path',
1251 help='The sysroot in which to install the toolchains')
Mike Frysinger07534cf2017-09-12 17:40:21 -04001252 return parser
Zdenek Behan508dcce2011-12-05 15:39:32 +01001253
Mike Frysinger07534cf2017-09-12 17:40:21 -04001254
1255def main(argv):
1256 parser = GetParser()
Mike Frysinger0c808452014-11-06 17:30:23 -05001257 options = parser.parse_args(argv)
1258 options.Freeze()
Zdenek Behan508dcce2011-12-05 15:39:32 +01001259
Mike Frysinger35247af2012-11-16 18:58:06 -05001260 # Figure out what we're supposed to do and reject conflicting options.
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001261 if options.cfg_name and options.create_packages:
Mike Frysinger35247af2012-11-16 18:58:06 -05001262 parser.error('conflicting options: create-packages & show-board-cfg')
Mike Frysinger984d0622012-06-01 16:08:44 -04001263
Gilad Arnold8195b532015-04-07 10:56:30 +03001264 targets_wanted = set(options.targets.split(','))
1265 boards_wanted = (set(options.include_boards.split(','))
1266 if options.include_boards else set())
Mike Frysinger35247af2012-11-16 18:58:06 -05001267
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001268 if options.cfg_name:
1269 ShowConfig(options.cfg_name)
Mike Frysinger35247af2012-11-16 18:58:06 -05001270 elif options.create_packages:
1271 cros_build_lib.AssertInsideChroot()
1272 Crossdev.Load(False)
Gilad Arnold8195b532015-04-07 10:56:30 +03001273 CreatePackages(targets_wanted, options.output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001274 else:
1275 cros_build_lib.AssertInsideChroot()
1276 # This has to be always run as root.
1277 if os.geteuid() != 0:
1278 cros_build_lib.Die('this script must be run as root')
1279
1280 Crossdev.Load(options.reconfig)
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001281 root = options.sysroot or '/'
Mike Frysinger35247af2012-11-16 18:58:06 -05001282 UpdateToolchains(options.usepkg, options.deleteold, options.hostonly,
Gilad Arnold8195b532015-04-07 10:56:30 +03001283 options.reconfig, targets_wanted, boards_wanted,
Don Garrettc0c74002015-10-09 12:58:19 -07001284 root=root)
Mike Frysinger35247af2012-11-16 18:58:06 -05001285 Crossdev.Save()
1286
1287 return 0