blob: 54e79067834ede2b0bf56c645fd5c257a5e66174 [file] [log] [blame]
Mike Frysingere58c0e22017-10-04 15:43:30 -04001# -*- coding: utf-8 -*-
Zdenek Behan508dcce2011-12-05 15:39:32 +01002# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
Mike Frysinger750c5f52014-09-16 16:16:57 -04006"""This script manages the installed toolchains in the chroot."""
Zdenek Behan508dcce2011-12-05 15:39:32 +01007
Mike Frysinger383367e2014-09-16 15:06:17 -04008from __future__ import print_function
9
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
Mike Frysinger66bfde52017-09-12 16:42:57 -040045# The exact list of host toolchain packages we care about. These are the
46# packages that bots/devs install only from binpkgs and rely on the SDK bot
47# (chromiumos-sdk) to validate+uprev.
48#
Mike Frysinger66bfde52017-09-12 16:42:57 -040049# We don't use crossdev to manage the host toolchain for us, especially since
50# we diverge significantly now (with llvm/clang/etc...), and we don't need or
51# want crossdev managing /etc/portage config files for the sdk
52HOST_PACKAGES = (
53 'dev-lang/go',
54 'sys-devel/binutils',
55 'sys-devel/clang',
56 'sys-devel/gcc',
57 'sys-devel/llvm',
58 'sys-kernel/linux-headers',
59 'sys-libs/glibc',
60 'sys-libs/libcxx',
61 'sys-libs/libcxxabi',
62)
63
Rahul Chaudhry4b803052015-05-13 15:25:56 -070064# Enable the Go compiler for these targets.
65TARGET_GO_ENABLED = (
66 'x86_64-cros-linux-gnu',
Rahul Chaudhry4b803052015-05-13 15:25:56 -070067 'armv7a-cros-linux-gnueabi',
68)
69CROSSDEV_GO_ARGS = ['--ex-pkg', 'dev-lang/go']
70
Manoj Gupta1b5642e2017-03-08 16:44:12 -080071# Enable llvm's compiler-rt for these targets.
72TARGET_COMPILER_RT_ENABLED = (
73 'armv7a-cros-linux-gnueabi',
Manoj Gupta946abb42017-04-12 14:27:19 -070074 'aarch64-cros-linux-gnu',
Manoj Gupta1b5642e2017-03-08 16:44:12 -080075)
76CROSSDEV_COMPILER_RT_ARGS = ['--ex-pkg', 'sys-libs/compiler-rt']
77
Manoj Gupta946abb42017-04-12 14:27:19 -070078TARGET_LLVM_PKGS_ENABLED = (
79 'armv7a-cros-linux-gnueabi',
80 'aarch64-cros-linux-gnu',
81 'x86_64-cros-linux-gnu',
82)
83
84LLVM_PKGS_TABLE = {
Yunlian Jiangbb2a3d32017-04-26 14:44:09 -070085 'ex_libcxxabi' : ['--ex-pkg', 'sys-libs/libcxxabi'],
86 'ex_libcxx' : ['--ex-pkg', 'sys-libs/libcxx'],
Manoj Gupta946abb42017-04-12 14:27:19 -070087}
88
Zdenek Behan508dcce2011-12-05 15:39:32 +010089# Overrides for {gcc,binutils}-config, pick a package with particular suffix.
90CONFIG_TARGET_SUFFIXES = {
Mike Frysingerd6e2df02014-11-26 02:55:04 -050091 'binutils' : {
Mike Frysinger8a83c622015-05-28 00:35:05 -040092 'armv6j-cros-linux-gnueabi': '-gold',
Han Shen43b84422015-02-19 11:38:13 -080093 'armv7a-cros-linux-gnueabi': '-gold',
Mike Frysingerd6e2df02014-11-26 02:55:04 -050094 'i686-pc-linux-gnu' : '-gold',
95 'x86_64-cros-linux-gnu' : '-gold',
96 },
Zdenek Behan508dcce2011-12-05 15:39:32 +010097}
Zdenek Behan508dcce2011-12-05 15:39:32 +010098
99
David James66a09c42012-11-05 13:31:38 -0800100class Crossdev(object):
101 """Class for interacting with crossdev and caching its output."""
102
103 _CACHE_FILE = os.path.join(CROSSDEV_OVERLAY, '.configured.json')
104 _CACHE = {}
Han Shene23782f2016-02-18 12:20:00 -0800105 # Packages that needs separate handling, in addition to what we have from
106 # crossdev.
107 MANUAL_PKGS = {
Manoj Guptaf0a602e2017-08-02 10:25:45 -0700108 'clang': 'sys-devel',
Han Shene23782f2016-02-18 12:20:00 -0800109 'llvm': 'sys-devel',
Manoj Gupta20cfc6c2017-07-19 15:49:55 -0700110 'libcxxabi': 'sys-libs',
111 'libcxx': 'sys-libs',
Han Shene23782f2016-02-18 12:20:00 -0800112 }
David James66a09c42012-11-05 13:31:38 -0800113
114 @classmethod
115 def Load(cls, reconfig):
Mike Frysinger3ed47722017-08-08 14:59:08 -0400116 """Load crossdev cache from disk.
117
118 We invalidate the cache when crossdev updates or this script changes.
119 """
David James90239b92012-11-05 15:31:34 -0800120 crossdev_version = GetStablePackageVersion('sys-devel/crossdev', True)
Mike Frysinger3ed47722017-08-08 14:59:08 -0400121 # If we run the compiled/cached .pyc file, we'll read/hash that when we
122 # really always want to track the source .py file.
123 script = os.path.abspath(__file__)
124 if script.endswith('.pyc'):
125 script = script[:-1]
126 setup_toolchains_hash = hashlib.md5(osutils.ReadFile(script)).hexdigest()
127
128 cls._CACHE = {
129 'crossdev_version': crossdev_version,
130 'setup_toolchains_hash': setup_toolchains_hash,
131 }
132
133 logging.debug('cache: checking file: %s', cls._CACHE_FILE)
134 if reconfig:
135 logging.debug('cache: forcing regen due to reconfig')
136 return
137
138 try:
139 file_data = osutils.ReadFile(cls._CACHE_FILE)
140 except IOError as e:
141 if e.errno != errno.ENOENT:
142 logging.warning('cache: reading failed: %s', e)
143 osutils.SafeUnlink(cls._CACHE_FILE)
144 return
145
146 try:
147 data = json.loads(file_data)
148 except ValueError as e:
149 logging.warning('cache: ignoring invalid content: %s', e)
150 return
151
152 if crossdev_version != data.get('crossdev_version'):
153 logging.debug('cache: rebuilding after crossdev upgrade')
154 elif setup_toolchains_hash != data.get('setup_toolchains_hash'):
155 logging.debug('cache: rebuilding after cros_setup_toolchains change')
156 else:
157 logging.debug('cache: content is up-to-date!')
158 cls._CACHE = data
David James66a09c42012-11-05 13:31:38 -0800159
160 @classmethod
161 def Save(cls):
162 """Store crossdev cache on disk."""
163 # Save the cache from the successful run.
164 with open(cls._CACHE_FILE, 'w') as f:
165 json.dump(cls._CACHE, f)
166
167 @classmethod
168 def GetConfig(cls, target):
169 """Returns a map of crossdev provided variables about a tuple."""
170 CACHE_ATTR = '_target_tuple_map'
171
172 val = cls._CACHE.setdefault(CACHE_ATTR, {})
173 if not target in val:
David James66a09c42012-11-05 13:31:38 -0800174 if target == 'host':
Mike Frysinger66bfde52017-09-12 16:42:57 -0400175 conf = {
176 'crosspkgs': [],
177 'target': toolchain.GetHostTuple(),
178 }
179 manual_pkgs = dict((pkg, cat) for cat, pkg in
180 [x.split('/') for x in HOST_PACKAGES])
181 else:
182 # Build the crossdev command.
183 cmd = ['crossdev', '--show-target-cfg', '--ex-gdb']
184 if target in TARGET_COMPILER_RT_ENABLED:
185 cmd.extend(CROSSDEV_COMPILER_RT_ARGS)
186 if target in TARGET_GO_ENABLED:
187 cmd.extend(CROSSDEV_GO_ARGS)
188 if target in TARGET_LLVM_PKGS_ENABLED:
189 for pkg in LLVM_PKGS_TABLE:
190 cmd.extend(LLVM_PKGS_TABLE[pkg])
191 cmd.extend(['-t', target])
192 # Catch output of crossdev.
193 out = cros_build_lib.RunCommand(
194 cmd, print_cmd=False, redirect_stdout=True).output.splitlines()
195 # List of tuples split at the first '=', converted into dict.
196 conf = dict((k, cros_build_lib.ShellUnquote(v))
197 for k, v in (x.split('=', 1) for x in out))
198 conf['crosspkgs'] = conf['crosspkgs'].split()
Han Shene23782f2016-02-18 12:20:00 -0800199
Mike Frysinger66bfde52017-09-12 16:42:57 -0400200 manual_pkgs = cls.MANUAL_PKGS
201
202 for pkg, cat in manual_pkgs.items():
Mike Frysinger3bba5032016-09-20 14:15:04 -0400203 conf[pkg + '_pn'] = pkg
204 conf[pkg + '_category'] = cat
205 if pkg not in conf['crosspkgs']:
206 conf['crosspkgs'].append(pkg)
Han Shene23782f2016-02-18 12:20:00 -0800207
208 val[target] = conf
209
David James66a09c42012-11-05 13:31:38 -0800210 return val[target]
211
212 @classmethod
213 def UpdateTargets(cls, targets, usepkg, config_only=False):
214 """Calls crossdev to initialize a cross target.
215
216 Args:
Don Garrett25f309a2014-03-19 14:02:12 -0700217 targets: The list of targets to initialize using crossdev.
218 usepkg: Copies the commandline opts.
219 config_only: Just update.
David James66a09c42012-11-05 13:31:38 -0800220 """
221 configured_targets = cls._CACHE.setdefault('configured_targets', [])
222
223 cmdbase = ['crossdev', '--show-fail-log']
224 cmdbase.extend(['--env', 'FEATURES=splitdebug'])
225 # Pick stable by default, and override as necessary.
226 cmdbase.extend(['-P', '--oneshot'])
227 if usepkg:
228 cmdbase.extend(['-P', '--getbinpkg',
229 '-P', '--usepkgonly',
230 '--without-headers'])
231
Christopher Wileyb22c0712015-06-02 10:37:03 -0700232 overlays = ' '.join((CHROMIUMOS_OVERLAY, ECLASS_OVERLAY, STABLE_OVERLAY))
David James66a09c42012-11-05 13:31:38 -0800233 cmdbase.extend(['--overlays', overlays])
234 cmdbase.extend(['--ov-output', CROSSDEV_OVERLAY])
235
236 for target in targets:
237 if config_only and target in configured_targets:
238 continue
239
240 cmd = cmdbase + ['-t', target]
241
242 for pkg in GetTargetPackages(target):
243 if pkg == 'gdb':
244 # Gdb does not have selectable versions.
245 cmd.append('--ex-gdb')
Manoj Guptab8181562017-05-21 10:18:59 -0700246 elif pkg == 'ex_compiler-rt':
247 cmd.extend(CROSSDEV_COMPILER_RT_ARGS)
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700248 elif pkg == 'ex_go':
249 # Go does not have selectable versions.
250 cmd.extend(CROSSDEV_GO_ARGS)
Manoj Gupta946abb42017-04-12 14:27:19 -0700251 elif pkg in LLVM_PKGS_TABLE:
252 cmd.extend(LLVM_PKGS_TABLE[pkg])
Han Shene23782f2016-02-18 12:20:00 -0800253 elif pkg in cls.MANUAL_PKGS:
254 pass
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700255 else:
256 # The first of the desired versions is the "primary" one.
257 version = GetDesiredPackageVersions(target, pkg)[0]
258 cmd.extend(['--%s' % pkg, version])
David James66a09c42012-11-05 13:31:38 -0800259
260 cmd.extend(targets[target]['crossdev'].split())
261 if config_only:
262 # In this case we want to just quietly reinit
263 cmd.append('--init-target')
264 cros_build_lib.RunCommand(cmd, print_cmd=False, redirect_stdout=True)
265 else:
266 cros_build_lib.RunCommand(cmd)
267
268 configured_targets.append(target)
269
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100270
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100271def GetTargetPackages(target):
272 """Returns a list of packages for a given target."""
David James66a09c42012-11-05 13:31:38 -0800273 conf = Crossdev.GetConfig(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100274 # Undesired packages are denoted by empty ${pkg}_pn variable.
Han Shene23782f2016-02-18 12:20:00 -0800275 return [x for x in conf['crosspkgs'] if conf.get(x+'_pn')]
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100276
277
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100278# Portage helper functions:
279def GetPortagePackage(target, package):
280 """Returns a package name for the given target."""
David James66a09c42012-11-05 13:31:38 -0800281 conf = Crossdev.GetConfig(target)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100282 # Portage category:
Han Shene23782f2016-02-18 12:20:00 -0800283 if target == 'host' or package in Crossdev.MANUAL_PKGS:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100284 category = conf[package + '_category']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100285 else:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100286 category = conf['category']
287 # Portage package:
288 pn = conf[package + '_pn']
289 # Final package name:
Mike Frysinger422faf42014-11-12 23:16:48 -0500290 assert category
291 assert pn
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100292 return '%s/%s' % (category, pn)
293
294
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700295def PortageTrees(root):
296 """Return the portage trees for a given root."""
297 if root == '/':
298 return portage.db['/']
299 # The portage logic requires the path always end in a slash.
300 root = root.rstrip('/') + '/'
301 return portage.create_trees(target_root=root, config_root=root)[root]
302
303
304def GetInstalledPackageVersions(atom, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100305 """Extracts the list of current versions of a target, package pair.
306
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500307 Args:
308 atom: The atom to operate on (e.g. sys-devel/gcc)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700309 root: The root to check for installed packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100310
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500311 Returns:
312 The list of versions of the package currently installed.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100313 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100314 versions = []
Mike Frysinger506e75f2012-12-17 14:21:13 -0500315 # pylint: disable=E1101
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700316 for pkg in PortageTrees(root)['vartree'].dbapi.match(atom, use_cache=0):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100317 version = portage.versions.cpv_getversion(pkg)
318 versions.append(version)
319 return versions
320
321
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700322def GetStablePackageVersion(atom, installed, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100323 """Extracts the current stable version for a given package.
324
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500325 Args:
326 atom: The target/package to operate on eg. i686-pc-linux-gnu,gcc
327 installed: Whether we want installed packages or ebuilds
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700328 root: The root to use when querying packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100329
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500330 Returns:
331 A string containing the latest version.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100332 """
David James90239b92012-11-05 15:31:34 -0800333 pkgtype = 'vartree' if installed else 'porttree'
Mike Frysinger506e75f2012-12-17 14:21:13 -0500334 # pylint: disable=E1101
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700335 cpv = portage.best(PortageTrees(root)[pkgtype].dbapi.match(atom, use_cache=0))
David James90239b92012-11-05 15:31:34 -0800336 return portage.versions.cpv_getversion(cpv) if cpv else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100337
338
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700339def VersionListToNumeric(target, package, versions, installed, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100340 """Resolves keywords in a given version list for a particular package.
341
342 Resolving means replacing PACKAGE_STABLE with the actual number.
343
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500344 Args:
345 target: The target to operate on (e.g. i686-pc-linux-gnu)
346 package: The target/package to operate on (e.g. gcc)
347 versions: List of versions to resolve
348 installed: Query installed packages
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700349 root: The install root to use; ignored if |installed| is False.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100350
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500351 Returns:
352 List of purely numeric versions equivalent to argument
Zdenek Behan508dcce2011-12-05 15:39:32 +0100353 """
354 resolved = []
David James90239b92012-11-05 15:31:34 -0800355 atom = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700356 if not installed:
357 root = '/'
Zdenek Behan508dcce2011-12-05 15:39:32 +0100358 for version in versions:
359 if version == PACKAGE_STABLE:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700360 resolved.append(GetStablePackageVersion(atom, installed, root=root))
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400361 else:
Zdenek Behan508dcce2011-12-05 15:39:32 +0100362 resolved.append(version)
363 return resolved
364
365
366def GetDesiredPackageVersions(target, package):
367 """Produces the list of desired versions for each target, package pair.
368
369 The first version in the list is implicitly treated as primary, ie.
370 the version that will be initialized by crossdev and selected.
371
372 If the version is PACKAGE_STABLE, it really means the current version which
373 is emerged by using the package atom with no particular version key.
374 Since crossdev unmasks all packages by default, this will actually
375 mean 'unstable' in most cases.
376
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500377 Args:
378 target: The target to operate on (e.g. i686-pc-linux-gnu)
379 package: The target/package to operate on (e.g. gcc)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100380
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500381 Returns:
382 A list composed of either a version string, PACKAGE_STABLE
Zdenek Behan508dcce2011-12-05 15:39:32 +0100383 """
Mike Frysingerd23be272017-09-12 17:18:44 -0400384 if package in GetTargetPackages(target):
385 return [PACKAGE_STABLE]
386 else:
387 return []
Zdenek Behan508dcce2011-12-05 15:39:32 +0100388
389
390def TargetIsInitialized(target):
391 """Verifies if the given list of targets has been correctly initialized.
392
393 This determines whether we have to call crossdev while emerging
394 toolchain packages or can do it using emerge. Emerge is naturally
395 preferred, because all packages can be updated in a single pass.
396
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500397 Args:
398 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100399
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500400 Returns:
401 True if |target| is completely initialized, else False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100402 """
403 # Check if packages for the given target all have a proper version.
404 try:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100405 for package in GetTargetPackages(target):
David James66a09c42012-11-05 13:31:38 -0800406 atom = GetPortagePackage(target, package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100407 # Do we even want this package && is it initialized?
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400408 if not (GetStablePackageVersion(atom, True) and
409 GetStablePackageVersion(atom, False)):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100410 return False
411 return True
412 except cros_build_lib.RunCommandError:
413 # Fails - The target has likely never been initialized before.
414 return False
415
416
417def RemovePackageMask(target):
418 """Removes a package.mask file for the given platform.
419
420 The pre-existing package.mask files can mess with the keywords.
421
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500422 Args:
423 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100424 """
425 maskfile = os.path.join('/etc/portage/package.mask', 'cross-' + target)
Brian Harringaf019fb2012-05-10 15:06:13 -0700426 osutils.SafeUnlink(maskfile)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100427
428
Zdenek Behan508dcce2011-12-05 15:39:32 +0100429# Main functions performing the actual update steps.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700430def RebuildLibtool(root='/'):
Mike Frysingerc880a962013-11-08 13:59:06 -0500431 """Rebuild libtool as needed
432
433 Libtool hardcodes full paths to internal gcc files, so whenever we upgrade
434 gcc, libtool will break. We can't use binary packages either as those will
435 most likely be compiled against the previous version of gcc.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700436
437 Args:
438 root: The install root where we want libtool rebuilt.
Mike Frysingerc880a962013-11-08 13:59:06 -0500439 """
440 needs_update = False
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700441 with open(os.path.join(root, 'usr/bin/libtool')) as f:
Mike Frysingerc880a962013-11-08 13:59:06 -0500442 for line in f:
443 # Look for a line like:
444 # sys_lib_search_path_spec="..."
445 # It'll be a list of paths and gcc will be one of them.
446 if line.startswith('sys_lib_search_path_spec='):
447 line = line.rstrip()
448 for path in line.split('=', 1)[1].strip('"').split():
Mike Frysinger3bba5032016-09-20 14:15:04 -0400449 root_path = os.path.join(root, path.lstrip(os.path.sep))
450 logging.debug('Libtool: checking %s', root_path)
451 if not os.path.exists(root_path):
452 logging.info('Rebuilding libtool after gcc upgrade')
453 logging.info(' %s', line)
454 logging.info(' missing path: %s', path)
Mike Frysingerc880a962013-11-08 13:59:06 -0500455 needs_update = True
456 break
457
458 if needs_update:
459 break
460
461 if needs_update:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700462 cmd = [EMERGE_CMD, '--oneshot']
463 if root != '/':
464 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
465 cmd.append('sys-devel/libtool')
Mike Frysingerc880a962013-11-08 13:59:06 -0500466 cros_build_lib.RunCommand(cmd)
Mike Frysinger3bba5032016-09-20 14:15:04 -0400467 else:
468 logging.debug('Libtool is up-to-date; no need to rebuild')
Mike Frysingerc880a962013-11-08 13:59:06 -0500469
470
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700471def UpdateTargets(targets, usepkg, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100472 """Determines which packages need update/unmerge and defers to portage.
473
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500474 Args:
475 targets: The list of targets to update
476 usepkg: Copies the commandline option
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700477 root: The install root in which we want packages updated.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100478 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100479 # For each target, we do two things. Figure out the list of updates,
480 # and figure out the appropriate keywords/masks. Crossdev will initialize
481 # these, but they need to be regenerated on every update.
Mike Frysinger3bba5032016-09-20 14:15:04 -0400482 logging.info('Determining required toolchain updates...')
David James90239b92012-11-05 15:31:34 -0800483 mergemap = {}
Zdenek Behan508dcce2011-12-05 15:39:32 +0100484 for target in targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400485 logging.debug('Updating target %s', target)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100486 # Record the highest needed version for each target, for masking purposes.
487 RemovePackageMask(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100488 for package in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100489 # Portage name for the package
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400490 logging.debug(' Checking package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100491 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700492 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100493 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200494 desired_num = VersionListToNumeric(target, package, desired, False)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100495 mergemap[pkg] = set(desired_num).difference(current)
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400496 logging.debug(' %s -> %s', current, desired_num)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100497
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400498 packages = [pkg for pkg, vers in mergemap.items() if vers]
Zdenek Behan508dcce2011-12-05 15:39:32 +0100499 if not packages:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400500 logging.info('Nothing to update!')
David Jamesf8c672f2012-11-06 13:38:11 -0800501 return False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100502
Mike Frysinger3bba5032016-09-20 14:15:04 -0400503 logging.info('Updating packages:')
504 logging.info('%s', packages)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100505
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100506 cmd = [EMERGE_CMD, '--oneshot', '--update']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100507 if usepkg:
508 cmd.extend(['--getbinpkg', '--usepkgonly'])
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700509 if root != '/':
510 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100511
512 cmd.extend(packages)
513 cros_build_lib.RunCommand(cmd)
David Jamesf8c672f2012-11-06 13:38:11 -0800514 return True
Zdenek Behan508dcce2011-12-05 15:39:32 +0100515
516
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700517def CleanTargets(targets, root='/'):
518 """Unmerges old packages that are assumed unnecessary.
519
520 Args:
521 targets: The list of targets to clean up.
522 root: The install root in which we want packages cleaned up.
523 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100524 unmergemap = {}
525 for target in targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400526 logging.debug('Cleaning target %s', target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100527 for package in GetTargetPackages(target):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400528 logging.debug(' Cleaning package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100529 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700530 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100531 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2fcb0aa2015-05-21 14:51:41 -0700532 # NOTE: This refers to installed packages (vartree) rather than the
533 # Portage version (porttree and/or bintree) when determining the current
534 # version. While this isn't the most accurate thing to do, it is probably
535 # a good simple compromise, which should have the desired result of
536 # uninstalling everything but the latest installed version. In
537 # particular, using the bintree (--usebinpkg) requires a non-trivial
538 # binhost sync and is probably more complex than useful.
Zdenek Behan699ddd32012-04-13 07:14:08 +0200539 desired_num = VersionListToNumeric(target, package, desired, True)
540 if not set(desired_num).issubset(current):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400541 logging.warning('Error detecting stable version for %s, '
542 'skipping clean!', pkg)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200543 return
Zdenek Behan508dcce2011-12-05 15:39:32 +0100544 unmergemap[pkg] = set(current).difference(desired_num)
545
546 # Cleaning doesn't care about consistency and rebuilding package.* files.
547 packages = []
548 for pkg, vers in unmergemap.iteritems():
549 packages.extend('=%s-%s' % (pkg, ver) for ver in vers if ver != '9999')
550
551 if packages:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400552 logging.info('Cleaning packages:')
553 logging.info('%s', packages)
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100554 cmd = [EMERGE_CMD, '--unmerge']
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700555 if root != '/':
556 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100557 cmd.extend(packages)
558 cros_build_lib.RunCommand(cmd)
559 else:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400560 logging.info('Nothing to clean!')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100561
562
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700563def SelectActiveToolchains(targets, suffixes, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100564 """Runs gcc-config and binutils-config to select the desired.
565
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500566 Args:
567 targets: The targets to select
568 suffixes: Optional target-specific hacks
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700569 root: The root where we want to select toolchain versions.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100570 """
571 for package in ['gcc', 'binutils']:
572 for target in targets:
573 # Pick the first version in the numbered list as the selected one.
574 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700575 desired_num = VersionListToNumeric(target, package, desired, True,
576 root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100577 desired = desired_num[0]
578 # *-config does not play revisions, strip them, keep just PV.
579 desired = portage.versions.pkgsplit('%s-%s' % (package, desired))[1]
580
581 if target == 'host':
582 # *-config is the only tool treating host identically (by tuple).
David James27ac4ae2012-12-03 23:16:15 -0800583 target = toolchain.GetHostTuple()
Zdenek Behan508dcce2011-12-05 15:39:32 +0100584
585 # And finally, attach target to it.
586 desired = '%s-%s' % (target, desired)
587
588 # Target specific hacks
589 if package in suffixes:
590 if target in suffixes[package]:
591 desired += suffixes[package][target]
592
David James7ec5efc2012-11-06 09:39:49 -0800593 extra_env = {'CHOST': target}
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700594 if root != '/':
595 extra_env['ROOT'] = root
David James7ec5efc2012-11-06 09:39:49 -0800596 cmd = ['%s-config' % package, '-c', target]
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500597 result = cros_build_lib.RunCommand(
598 cmd, print_cmd=False, redirect_stdout=True, extra_env=extra_env)
599 current = result.output.splitlines()[0]
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700600
601 # Do not reconfig when the current is live or nothing needs to be done.
602 extra_env = {'ROOT': root} if root != '/' else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100603 if current != desired and current != '9999':
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500604 cmd = [package + '-config', desired]
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700605 cros_build_lib.RunCommand(cmd, print_cmd=False, extra_env=extra_env)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100606
607
Mike Frysinger35247af2012-11-16 18:58:06 -0500608def ExpandTargets(targets_wanted):
609 """Expand any possible toolchain aliases into full targets
610
611 This will expand 'all' and 'sdk' into the respective toolchain tuples.
612
613 Args:
614 targets_wanted: The targets specified by the user.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500615
Mike Frysinger35247af2012-11-16 18:58:06 -0500616 Returns:
Gilad Arnold8195b532015-04-07 10:56:30 +0300617 Dictionary of concrete targets and their toolchain tuples.
Mike Frysinger35247af2012-11-16 18:58:06 -0500618 """
Mike Frysinger35247af2012-11-16 18:58:06 -0500619 targets_wanted = set(targets_wanted)
Don Garrettc0c74002015-10-09 12:58:19 -0700620 if targets_wanted == set(['boards']):
621 # Only pull targets from the included boards.
Gilad Arnold8195b532015-04-07 10:56:30 +0300622 return {}
623
624 all_targets = toolchain.GetAllTargets()
Mike Frysinger35247af2012-11-16 18:58:06 -0500625 if targets_wanted == set(['all']):
Gilad Arnold8195b532015-04-07 10:56:30 +0300626 return all_targets
627 if targets_wanted == set(['sdk']):
Mike Frysinger35247af2012-11-16 18:58:06 -0500628 # Filter out all the non-sdk toolchains as we don't want to mess
629 # with those in all of our builds.
Gilad Arnold8195b532015-04-07 10:56:30 +0300630 return toolchain.FilterToolchains(all_targets, 'sdk', True)
631
632 # Verify user input.
633 nonexistent = targets_wanted.difference(all_targets)
634 if nonexistent:
635 raise ValueError('Invalid targets: %s', ','.join(nonexistent))
636 return {t: all_targets[t] for t in targets_wanted}
Mike Frysinger35247af2012-11-16 18:58:06 -0500637
638
David Jamesf8c672f2012-11-06 13:38:11 -0800639def UpdateToolchains(usepkg, deleteold, hostonly, reconfig,
Don Garrettc0c74002015-10-09 12:58:19 -0700640 targets_wanted, boards_wanted, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100641 """Performs all steps to create a synchronized toolchain enviroment.
642
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500643 Args:
644 usepkg: Use prebuilt packages
645 deleteold: Unmerge deprecated packages
646 hostonly: Only setup the host toolchain
647 reconfig: Reload crossdev config and reselect toolchains
648 targets_wanted: All the targets to update
649 boards_wanted: Load targets from these boards
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700650 root: The root in which to install the toolchains.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100651 """
David Jamesf8c672f2012-11-06 13:38:11 -0800652 targets, crossdev_targets, reconfig_targets = {}, {}, {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100653 if not hostonly:
654 # For hostonly, we can skip most of the below logic, much of which won't
655 # work on bare systems where this is useful.
Mike Frysinger35247af2012-11-16 18:58:06 -0500656 targets = ExpandTargets(targets_wanted)
Mike Frysinger7ccee992012-06-01 21:27:59 -0400657
Don Garrettc0c74002015-10-09 12:58:19 -0700658 # Now re-add any targets that might be from this board. This is to
Gilad Arnold8195b532015-04-07 10:56:30 +0300659 # allow unofficial boards to declare their own toolchains.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400660 for board in boards_wanted:
David James27ac4ae2012-12-03 23:16:15 -0800661 targets.update(toolchain.GetToolchainsForBoard(board))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100662
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100663 # First check and initialize all cross targets that need to be.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400664 for target in targets:
665 if TargetIsInitialized(target):
666 reconfig_targets[target] = targets[target]
667 else:
668 crossdev_targets[target] = targets[target]
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100669 if crossdev_targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400670 logging.info('The following targets need to be re-initialized:')
671 logging.info('%s', crossdev_targets)
David James66a09c42012-11-05 13:31:38 -0800672 Crossdev.UpdateTargets(crossdev_targets, usepkg)
Zdenek Behan8be29ba2012-05-29 23:10:34 +0200673 # Those that were not initialized may need a config update.
David James66a09c42012-11-05 13:31:38 -0800674 Crossdev.UpdateTargets(reconfig_targets, usepkg, config_only=True)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100675
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100676 # We want host updated.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400677 targets['host'] = {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100678
679 # Now update all packages.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700680 if UpdateTargets(targets, usepkg, root=root) or crossdev_targets or reconfig:
681 SelectActiveToolchains(targets, CONFIG_TARGET_SUFFIXES, root=root)
David James7ec5efc2012-11-06 09:39:49 -0800682
683 if deleteold:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700684 CleanTargets(targets, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100685
Mike Frysingerc880a962013-11-08 13:59:06 -0500686 # Now that we've cleared out old versions, see if we need to rebuild
687 # anything. Can't do this earlier as it might not be broken.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700688 RebuildLibtool(root=root)
Mike Frysingerc880a962013-11-08 13:59:06 -0500689
Zdenek Behan508dcce2011-12-05 15:39:32 +0100690
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -0700691def ShowConfig(name):
692 """Show the toolchain tuples used by |name|
Mike Frysinger35247af2012-11-16 18:58:06 -0500693
694 Args:
Don Garrettc0c74002015-10-09 12:58:19 -0700695 name: The board name to query.
Mike Frysinger35247af2012-11-16 18:58:06 -0500696 """
Don Garrettc0c74002015-10-09 12:58:19 -0700697 toolchains = toolchain.GetToolchainsForBoard(name)
Mike Frysinger35247af2012-11-16 18:58:06 -0500698 # Make sure we display the default toolchain first.
Mike Frysinger3bba5032016-09-20 14:15:04 -0400699 # Note: Do not use logging here as this is meant to be used by other tools.
Mike Frysinger383367e2014-09-16 15:06:17 -0400700 print(','.join(
David James27ac4ae2012-12-03 23:16:15 -0800701 toolchain.FilterToolchains(toolchains, 'default', True).keys() +
Mike Frysinger383367e2014-09-16 15:06:17 -0400702 toolchain.FilterToolchains(toolchains, 'default', False).keys()))
Mike Frysinger35247af2012-11-16 18:58:06 -0500703
704
Mike Frysinger35247af2012-11-16 18:58:06 -0500705def GeneratePathWrapper(root, wrappath, path):
706 """Generate a shell script to execute another shell script
707
708 Since we can't symlink a wrapped ELF (see GenerateLdsoWrapper) because the
709 argv[0] won't be pointing to the correct path, generate a shell script that
710 just executes another program with its full path.
711
712 Args:
713 root: The root tree to generate scripts inside of
714 wrappath: The full path (inside |root|) to create the wrapper
715 path: The target program which this wrapper will execute
716 """
717 replacements = {
718 'path': path,
719 'relroot': os.path.relpath('/', os.path.dirname(wrappath)),
720 }
721 wrapper = """#!/bin/sh
722base=$(realpath "$0")
723basedir=${base%%/*}
724exec "${basedir}/%(relroot)s%(path)s" "$@"
725""" % replacements
726 root_wrapper = root + wrappath
727 if os.path.islink(root_wrapper):
728 os.unlink(root_wrapper)
729 else:
730 osutils.SafeMakedirs(os.path.dirname(root_wrapper))
731 osutils.WriteFile(root_wrapper, wrapper)
Mike Frysinger60ec1012013-10-21 00:11:10 -0400732 os.chmod(root_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -0500733
734
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -0700735def FixClangXXWrapper(root, path):
736 """Fix wrapper shell scripts and symlinks for invoking clang++
737
738 In a typical installation, clang++ symlinks to clang, which symlinks to the
739 elf executable. The executable distinguishes between clang and clang++ based
740 on argv[0].
741
742 When invoked through the LdsoWrapper, argv[0] always contains the path to the
743 executable elf file, making clang/clang++ invocations indistinguishable.
744
745 This function detects if the elf executable being wrapped is clang-X.Y, and
746 fixes wrappers/symlinks as necessary so that clang++ will work correctly.
747
748 The calling sequence now becomes:
749 -) clang++ invocation turns into clang++-3.9 (which is a copy of clang-3.9,
750 the Ldsowrapper).
751 -) clang++-3.9 uses the Ldso to invoke clang++-3.9.elf, which is a symlink
752 to the original clang-3.9 elf.
753 -) The difference this time is that inside the elf file execution, $0 is
754 set as .../usr/bin/clang++-3.9.elf, which contains 'clang++' in the name.
755
756 Args:
757 root: The root tree to generate scripts / symlinks inside of
758 path: The target elf for which LdsoWrapper was created
759 """
760 if re.match(r'/usr/bin/clang-\d+\.\d+$', path):
761 logging.info('fixing clang++ invocation for %s', path)
762 clangdir = os.path.dirname(root + path)
763 clang = os.path.basename(path)
764 clangxx = clang.replace('clang', 'clang++')
765
766 # Create a symlink clang++-X.Y.elf to point to clang-X.Y.elf
767 os.symlink(clang + '.elf', os.path.join(clangdir, clangxx + '.elf'))
768
769 # Create a hardlink clang++-X.Y pointing to clang-X.Y
770 os.link(os.path.join(clangdir, clang), os.path.join(clangdir, clangxx))
771
772 # Adjust the clang++ symlink to point to clang++-X.Y
773 os.unlink(os.path.join(clangdir, 'clang++'))
774 os.symlink(clangxx, os.path.join(clangdir, 'clang++'))
775
776
Mike Frysinger35247af2012-11-16 18:58:06 -0500777def FileIsCrosSdkElf(elf):
778 """Determine if |elf| is an ELF that we execute in the cros_sdk
779
780 We don't need this to be perfect, just quick. It makes sure the ELF
781 is a 64bit LSB x86_64 ELF. That is the native type of cros_sdk.
782
783 Args:
784 elf: The file to check
Mike Frysinger1a736a82013-12-12 01:50:59 -0500785
Mike Frysinger35247af2012-11-16 18:58:06 -0500786 Returns:
787 True if we think |elf| is a native ELF
788 """
789 with open(elf) as f:
790 data = f.read(20)
791 # Check the magic number, EI_CLASS, EI_DATA, and e_machine.
792 return (data[0:4] == '\x7fELF' and
793 data[4] == '\x02' and
794 data[5] == '\x01' and
795 data[18] == '\x3e')
796
797
798def IsPathPackagable(ptype, path):
799 """Should the specified file be included in a toolchain package?
800
801 We only need to handle files as we'll create dirs as we need them.
802
803 Further, trim files that won't be useful:
804 - non-english translations (.mo) since it'd require env vars
805 - debug files since these are for the host compiler itself
806 - info/man pages as they're big, and docs are online, and the
807 native docs should work fine for the most part (`man gcc`)
808
809 Args:
810 ptype: A string describing the path type (i.e. 'file' or 'dir' or 'sym')
811 path: The full path to inspect
Mike Frysinger1a736a82013-12-12 01:50:59 -0500812
Mike Frysinger35247af2012-11-16 18:58:06 -0500813 Returns:
814 True if we want to include this path in the package
815 """
816 return not (ptype in ('dir',) or
817 path.startswith('/usr/lib/debug/') or
818 os.path.splitext(path)[1] == '.mo' or
819 ('/man/' in path or '/info/' in path))
820
821
822def ReadlinkRoot(path, root):
823 """Like os.readlink(), but relative to a |root|
824
825 Args:
826 path: The symlink to read
827 root: The path to use for resolving absolute symlinks
Mike Frysinger1a736a82013-12-12 01:50:59 -0500828
Mike Frysinger35247af2012-11-16 18:58:06 -0500829 Returns:
830 A fully resolved symlink path
831 """
832 while os.path.islink(root + path):
833 path = os.path.join(os.path.dirname(path), os.readlink(root + path))
834 return path
835
836
837def _GetFilesForTarget(target, root='/'):
838 """Locate all the files to package for |target|
839
840 This does not cover ELF dependencies.
841
842 Args:
843 target: The toolchain target name
844 root: The root path to pull all packages from
Mike Frysinger1a736a82013-12-12 01:50:59 -0500845
Mike Frysinger35247af2012-11-16 18:58:06 -0500846 Returns:
847 A tuple of a set of all packable paths, and a set of all paths which
848 are also native ELFs
849 """
850 paths = set()
851 elfs = set()
852
853 # Find all the files owned by the packages for this target.
854 for pkg in GetTargetPackages(target):
Mike Frysinger35247af2012-11-16 18:58:06 -0500855
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700856 # Skip Go compiler from redistributable packages.
857 # The "go" executable has GOROOT=/usr/lib/go/${CTARGET} hardcoded
858 # into it. Due to this, the toolchain cannot be unpacked anywhere
859 # else and be readily useful. To enable packaging Go, we need to:
860 # -) Tweak the wrappers/environment to override GOROOT
861 # automatically based on the unpack location.
862 # -) Make sure the ELF dependency checking and wrapping logic
863 # below skips the Go toolchain executables and libraries.
864 # -) Make sure the packaging process maintains the relative
865 # timestamps of precompiled standard library packages.
866 # (see dev-lang/go ebuild for details).
867 if pkg == 'ex_go':
868 continue
869
Mike Frysinger35247af2012-11-16 18:58:06 -0500870 atom = GetPortagePackage(target, pkg)
871 cat, pn = atom.split('/')
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700872 ver = GetInstalledPackageVersions(atom, root=root)[0]
Ralph Nathan03047282015-03-23 11:09:32 -0700873 logging.info('packaging %s-%s', atom, ver)
Mike Frysinger35247af2012-11-16 18:58:06 -0500874
875 # pylint: disable=E1101
876 dblink = portage.dblink(cat, pn + '-' + ver, myroot=root,
877 settings=portage.settings)
878 contents = dblink.getcontents()
879 for obj in contents:
880 ptype = contents[obj][0]
881 if not IsPathPackagable(ptype, obj):
882 continue
883
884 if ptype == 'obj':
885 # For native ELFs, we need to pull in their dependencies too.
886 if FileIsCrosSdkElf(obj):
887 elfs.add(obj)
888 paths.add(obj)
889
890 return paths, elfs
891
892
893def _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500894 path_rewrite_func=lambda x: x, root='/'):
Mike Frysinger35247af2012-11-16 18:58:06 -0500895 """Link in all packable files and their runtime dependencies
896
897 This also wraps up executable ELFs with helper scripts.
898
899 Args:
900 output_dir: The output directory to store files
901 paths: All the files to include
902 elfs: All the files which are ELFs (a subset of |paths|)
903 ldpaths: A dict of static ldpath information
904 path_rewrite_func: User callback to rewrite paths in output_dir
905 root: The root path to pull all packages/files from
906 """
907 # Link in all the files.
Mike Frysinger221bd822017-09-29 02:51:47 -0400908 sym_paths = {}
Mike Frysinger35247af2012-11-16 18:58:06 -0500909 for path in paths:
910 new_path = path_rewrite_func(path)
911 dst = output_dir + new_path
912 osutils.SafeMakedirs(os.path.dirname(dst))
913
914 # Is this a symlink which we have to rewrite or wrap?
915 # Delay wrap check until after we have created all paths.
916 src = root + path
917 if os.path.islink(src):
918 tgt = os.readlink(src)
919 if os.path.sep in tgt:
Mike Frysinger221bd822017-09-29 02:51:47 -0400920 sym_paths[lddtree.normpath(ReadlinkRoot(src, root))] = new_path
Mike Frysinger35247af2012-11-16 18:58:06 -0500921
922 # Rewrite absolute links to relative and then generate the symlink
923 # ourselves. All other symlinks can be hardlinked below.
924 if tgt[0] == '/':
925 tgt = os.path.relpath(tgt, os.path.dirname(new_path))
926 os.symlink(tgt, dst)
927 continue
928
929 os.link(src, dst)
930
Mike Frysinger35247af2012-11-16 18:58:06 -0500931 # Locate all the dependencies for all the ELFs. Stick them all in the
932 # top level "lib" dir to make the wrapper simpler. This exact path does
933 # not matter since we execute ldso directly, and we tell the ldso the
934 # exact path to search for its libraries.
935 libdir = os.path.join(output_dir, 'lib')
936 osutils.SafeMakedirs(libdir)
937 donelibs = set()
Mike Frysinger4331fc62017-09-28 14:03:25 -0400938 glibc_re = re.compile(r'/lib(c|pthread)-[0-9.]+\.so$')
Mike Frysinger35247af2012-11-16 18:58:06 -0500939 for elf in elfs:
Mike Frysingerea7688e2014-07-31 22:40:33 -0400940 e = lddtree.ParseELF(elf, root=root, ldpaths=ldpaths)
Mike Frysinger35247af2012-11-16 18:58:06 -0500941 interp = e['interp']
Yunlian Jiang196e8f42017-09-20 12:29:47 -0700942 # Do not create wrapper for libc. crbug.com/766827
943 if interp and not glibc_re.search(elf):
Mike Frysinger35247af2012-11-16 18:58:06 -0500944 # Generate a wrapper if it is executable.
Mike Frysingerc2ec0902013-03-26 01:28:45 -0400945 interp = os.path.join('/lib', os.path.basename(interp))
946 lddtree.GenerateLdsoWrapper(output_dir, path_rewrite_func(elf), interp,
947 libpaths=e['rpath'] + e['runpath'])
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -0700948 FixClangXXWrapper(output_dir, path_rewrite_func(elf))
Mike Frysinger35247af2012-11-16 18:58:06 -0500949
Mike Frysinger221bd822017-09-29 02:51:47 -0400950 # Wrap any symlinks to the wrapper.
951 if elf in sym_paths:
952 link = sym_paths[elf]
953 GeneratePathWrapper(output_dir, link, elf)
954
Mike Frysinger35247af2012-11-16 18:58:06 -0500955 for lib, lib_data in e['libs'].iteritems():
956 if lib in donelibs:
957 continue
958
959 src = path = lib_data['path']
960 if path is None:
Ralph Nathan446aee92015-03-23 14:44:56 -0700961 logging.warning('%s: could not locate %s', elf, lib)
Mike Frysinger35247af2012-11-16 18:58:06 -0500962 continue
963 donelibs.add(lib)
964
965 # Needed libs are the SONAME, but that is usually a symlink, not a
966 # real file. So link in the target rather than the symlink itself.
967 # We have to walk all the possible symlinks (SONAME could point to a
968 # symlink which points to a symlink), and we have to handle absolute
969 # ourselves (since we have a "root" argument).
970 dst = os.path.join(libdir, os.path.basename(path))
971 src = ReadlinkRoot(src, root)
972
973 os.link(root + src, dst)
974
975
976def _EnvdGetVar(envd, var):
977 """Given a Gentoo env.d file, extract a var from it
978
979 Args:
980 envd: The env.d file to load (may be a glob path)
981 var: The var to extract
Mike Frysinger1a736a82013-12-12 01:50:59 -0500982
Mike Frysinger35247af2012-11-16 18:58:06 -0500983 Returns:
984 The value of |var|
985 """
986 envds = glob.glob(envd)
987 assert len(envds) == 1, '%s: should have exactly 1 env.d file' % envd
988 envd = envds[0]
989 return cros_build_lib.LoadKeyValueFile(envd)[var]
990
991
992def _ProcessBinutilsConfig(target, output_dir):
993 """Do what binutils-config would have done"""
994 binpath = os.path.join('/bin', target + '-')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -0500995
996 # Locate the bin dir holding the gold linker.
997 binutils_bin_path = os.path.join(output_dir, 'usr', toolchain.GetHostTuple(),
998 target, 'binutils-bin')
999 globpath = os.path.join(binutils_bin_path, '*-gold')
Mike Frysinger35247af2012-11-16 18:58:06 -05001000 srcpath = glob.glob(globpath)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001001 if not srcpath:
1002 # Maybe this target doesn't support gold.
1003 globpath = os.path.join(binutils_bin_path, '*')
1004 srcpath = glob.glob(globpath)
1005 assert len(srcpath) == 1, ('%s: matched more than one path (but not *-gold)'
1006 % globpath)
1007 srcpath = srcpath[0]
1008 ld_path = os.path.join(srcpath, 'ld')
1009 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1010 ld_path = os.path.join(srcpath, 'ld.bfd')
1011 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1012 ld_path = os.path.join(srcpath, 'ld.gold')
1013 assert not os.path.exists(ld_path), ('%s: exists, but gold dir does not!'
1014 % ld_path)
1015
1016 # Nope, no gold support to be found.
1017 gold_supported = False
Ralph Nathan446aee92015-03-23 14:44:56 -07001018 logging.warning('%s: binutils lacks support for the gold linker', target)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001019 else:
1020 assert len(srcpath) == 1, '%s: did not match exactly 1 path' % globpath
Mike Frysinger78b7a812014-11-26 19:45:23 -05001021 srcpath = srcpath[0]
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001022
Rahul Chaudhry4891b4d2017-03-08 10:31:27 -08001023 # Package the binutils-bin directory without the '-gold' suffix
1024 # if gold is not enabled as the default linker for this target.
1025 gold_supported = CONFIG_TARGET_SUFFIXES['binutils'].get(target) == '-gold'
1026 if not gold_supported:
1027 srcpath = srcpath[:-len('-gold')]
1028 ld_path = os.path.join(srcpath, 'ld')
1029 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1030
Mike Frysinger78b7a812014-11-26 19:45:23 -05001031 srcpath = srcpath[len(output_dir):]
Mike Frysinger35247af2012-11-16 18:58:06 -05001032 gccpath = os.path.join('/usr', 'libexec', 'gcc')
1033 for prog in os.listdir(output_dir + srcpath):
1034 # Skip binaries already wrapped.
1035 if not prog.endswith('.real'):
1036 GeneratePathWrapper(output_dir, binpath + prog,
1037 os.path.join(srcpath, prog))
1038 GeneratePathWrapper(output_dir, os.path.join(gccpath, prog),
1039 os.path.join(srcpath, prog))
1040
David James27ac4ae2012-12-03 23:16:15 -08001041 libpath = os.path.join('/usr', toolchain.GetHostTuple(), target, 'lib')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001042 envd = os.path.join(output_dir, 'etc', 'env.d', 'binutils', '*')
1043 if gold_supported:
1044 envd += '-gold'
Rahul Chaudhry4891b4d2017-03-08 10:31:27 -08001045 else:
1046 # If gold is not enabled as the default linker and 2 env.d
1047 # files exist, pick the one without the '-gold' suffix.
1048 envds = sorted(glob.glob(envd))
1049 if len(envds) == 2 and envds[1] == envds[0] + '-gold':
1050 envd = envds[0]
Mike Frysinger35247af2012-11-16 18:58:06 -05001051 srcpath = _EnvdGetVar(envd, 'LIBPATH')
1052 os.symlink(os.path.relpath(srcpath, os.path.dirname(libpath)),
1053 output_dir + libpath)
1054
1055
1056def _ProcessGccConfig(target, output_dir):
1057 """Do what gcc-config would have done"""
1058 binpath = '/bin'
1059 envd = os.path.join(output_dir, 'etc', 'env.d', 'gcc', '*')
1060 srcpath = _EnvdGetVar(envd, 'GCC_PATH')
1061 for prog in os.listdir(output_dir + srcpath):
1062 # Skip binaries already wrapped.
1063 if (not prog.endswith('.real') and
1064 not prog.endswith('.elf') and
1065 prog.startswith(target)):
1066 GeneratePathWrapper(output_dir, os.path.join(binpath, prog),
1067 os.path.join(srcpath, prog))
1068 return srcpath
1069
1070
Frank Henigman179ec7c2015-02-06 03:01:09 -05001071def _ProcessSysrootWrappers(_target, output_dir, srcpath):
1072 """Remove chroot-specific things from our sysroot wrappers"""
Mike Frysinger35247af2012-11-16 18:58:06 -05001073 # Disable ccache since we know it won't work outside of chroot.
Frank Henigman179ec7c2015-02-06 03:01:09 -05001074 for sysroot_wrapper in glob.glob(os.path.join(
1075 output_dir + srcpath, 'sysroot_wrapper*')):
1076 contents = osutils.ReadFile(sysroot_wrapper).splitlines()
1077 for num in xrange(len(contents)):
1078 if '@CCACHE_DEFAULT@' in contents[num]:
Caroline Ticece9e9232017-06-02 09:38:42 -07001079 assert 'True' in contents[num]
1080 contents[num] = contents[num].replace('True', 'False')
Frank Henigman179ec7c2015-02-06 03:01:09 -05001081 break
1082 # Can't update the wrapper in place since it's a hardlink to a file in /.
1083 os.unlink(sysroot_wrapper)
1084 osutils.WriteFile(sysroot_wrapper, '\n'.join(contents))
1085 os.chmod(sysroot_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -05001086
1087
Yunlian Jiang5ad6b512017-09-20 09:27:45 -07001088def _CreateMainLibDir(target, output_dir):
1089 """Create some lib dirs so that compiler can get the right Gcc paths"""
1090 osutils.SafeMakedirs(os.path.join(output_dir, 'usr', target, 'lib'))
1091 osutils.SafeMakedirs(os.path.join(output_dir, 'usr', target, 'usr/lib'))
1092
1093
Mike Frysinger35247af2012-11-16 18:58:06 -05001094def _ProcessDistroCleanups(target, output_dir):
1095 """Clean up the tree and remove all distro-specific requirements
1096
1097 Args:
1098 target: The toolchain target name
1099 output_dir: The output directory to clean up
1100 """
1101 _ProcessBinutilsConfig(target, output_dir)
1102 gcc_path = _ProcessGccConfig(target, output_dir)
Frank Henigman179ec7c2015-02-06 03:01:09 -05001103 _ProcessSysrootWrappers(target, output_dir, gcc_path)
Yunlian Jiang5ad6b512017-09-20 09:27:45 -07001104 _CreateMainLibDir(target, output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001105
1106 osutils.RmDir(os.path.join(output_dir, 'etc'))
1107
1108
1109def CreatePackagableRoot(target, output_dir, ldpaths, root='/'):
1110 """Setup a tree from the packages for the specified target
1111
1112 This populates a path with all the files from toolchain packages so that
1113 a tarball can easily be generated from the result.
1114
1115 Args:
1116 target: The target to create a packagable root from
1117 output_dir: The output directory to place all the files
1118 ldpaths: A dict of static ldpath information
1119 root: The root path to pull all packages/files from
1120 """
1121 # Find all the files owned by the packages for this target.
1122 paths, elfs = _GetFilesForTarget(target, root=root)
1123
1124 # Link in all the package's files, any ELF dependencies, and wrap any
1125 # executable ELFs with helper scripts.
1126 def MoveUsrBinToBin(path):
Han Shen699ea192016-03-02 10:42:47 -08001127 """Move /usr/bin to /bin so people can just use that toplevel dir
1128
1129 Note we do not apply this to clang - there is correlation between clang's
1130 search path for libraries / inclusion and its installation path.
1131 """
1132 if path.startswith('/usr/bin/') and path.find('clang') == -1:
1133 return path[4:]
1134 return path
Mike Frysinger35247af2012-11-16 18:58:06 -05001135 _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
1136 path_rewrite_func=MoveUsrBinToBin, root=root)
1137
1138 # The packages, when part of the normal distro, have helper scripts
1139 # that setup paths and such. Since we are making this standalone, we
1140 # need to preprocess all that ourselves.
1141 _ProcessDistroCleanups(target, output_dir)
1142
1143
1144def CreatePackages(targets_wanted, output_dir, root='/'):
1145 """Create redistributable cross-compiler packages for the specified targets
1146
1147 This creates toolchain packages that should be usable in conjunction with
1148 a downloaded sysroot (created elsewhere).
1149
1150 Tarballs (one per target) will be created in $PWD.
1151
1152 Args:
Don Garrett25f309a2014-03-19 14:02:12 -07001153 targets_wanted: The targets to package up.
1154 output_dir: The directory to put the packages in.
1155 root: The root path to pull all packages/files from.
Mike Frysinger35247af2012-11-16 18:58:06 -05001156 """
Ralph Nathan03047282015-03-23 11:09:32 -07001157 logging.info('Writing tarballs to %s', output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001158 osutils.SafeMakedirs(output_dir)
1159 ldpaths = lddtree.LoadLdpaths(root)
1160 targets = ExpandTargets(targets_wanted)
1161
Mike Frysinger221bd822017-09-29 02:51:47 -04001162 with osutils.TempDir(prefix='create-packages') as tempdir:
1163 logging.debug('Using tempdir: %s', tempdir)
1164
Mike Frysinger35247af2012-11-16 18:58:06 -05001165 # We have to split the root generation from the compression stages. This is
1166 # because we hardlink in all the files (to avoid overhead of reading/writing
1167 # the copies multiple times). But tar gets angry if a file's hardlink count
1168 # changes from when it starts reading a file to when it finishes.
1169 with parallel.BackgroundTaskRunner(CreatePackagableRoot) as queue:
1170 for target in targets:
1171 output_target_dir = os.path.join(tempdir, target)
1172 queue.put([target, output_target_dir, ldpaths, root])
1173
1174 # Build the tarball.
1175 with parallel.BackgroundTaskRunner(cros_build_lib.CreateTarball) as queue:
1176 for target in targets:
1177 tar_file = os.path.join(output_dir, target + '.tar.xz')
1178 queue.put([tar_file, os.path.join(tempdir, target)])
1179
1180
Mike Frysinger07534cf2017-09-12 17:40:21 -04001181def GetParser():
1182 """Return a command line parser."""
Mike Frysinger0c808452014-11-06 17:30:23 -05001183 parser = commandline.ArgumentParser(description=__doc__)
1184 parser.add_argument('-u', '--nousepkg',
1185 action='store_false', dest='usepkg', default=True,
1186 help='Use prebuilt packages if possible')
1187 parser.add_argument('-d', '--deleteold',
1188 action='store_true', dest='deleteold', default=False,
1189 help='Unmerge deprecated packages')
1190 parser.add_argument('-t', '--targets',
1191 dest='targets', default='sdk',
Gilad Arnold8195b532015-04-07 10:56:30 +03001192 help="Comma separated list of tuples. Special keywords "
Don Garrettc0c74002015-10-09 12:58:19 -07001193 "'host', 'sdk', 'boards', and 'all' are "
Gilad Arnold8195b532015-04-07 10:56:30 +03001194 "allowed. Defaults to 'sdk'.")
1195 parser.add_argument('--include-boards', default='', metavar='BOARDS',
1196 help='Comma separated list of boards whose toolchains we '
1197 'will always include. Default: none')
Mike Frysinger0c808452014-11-06 17:30:23 -05001198 parser.add_argument('--hostonly',
1199 dest='hostonly', default=False, action='store_true',
1200 help='Only setup the host toolchain. '
1201 'Useful for bootstrapping chroot')
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001202 parser.add_argument('--show-board-cfg', '--show-cfg',
1203 dest='cfg_name', default=None,
Don Garrettc0c74002015-10-09 12:58:19 -07001204 help='Board to list toolchains tuples for')
Mike Frysinger91f52882017-09-13 00:16:58 -04001205 parser.add_argument('--show-packages', default=None,
1206 help='List all packages the specified target uses')
Mike Frysinger0c808452014-11-06 17:30:23 -05001207 parser.add_argument('--create-packages',
1208 action='store_true', default=False,
1209 help='Build redistributable packages')
1210 parser.add_argument('--output-dir', default=os.getcwd(), type='path',
1211 help='Output directory')
1212 parser.add_argument('--reconfig', default=False, action='store_true',
1213 help='Reload crossdev config and reselect toolchains')
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001214 parser.add_argument('--sysroot', type='path',
1215 help='The sysroot in which to install the toolchains')
Mike Frysinger07534cf2017-09-12 17:40:21 -04001216 return parser
Zdenek Behan508dcce2011-12-05 15:39:32 +01001217
Mike Frysinger07534cf2017-09-12 17:40:21 -04001218
1219def main(argv):
1220 parser = GetParser()
Mike Frysinger0c808452014-11-06 17:30:23 -05001221 options = parser.parse_args(argv)
1222 options.Freeze()
Zdenek Behan508dcce2011-12-05 15:39:32 +01001223
Mike Frysinger35247af2012-11-16 18:58:06 -05001224 # Figure out what we're supposed to do and reject conflicting options.
Mike Frysinger91f52882017-09-13 00:16:58 -04001225 conflicting_options = (
1226 options.cfg_name,
1227 options.show_packages,
1228 options.create_packages,
1229 )
1230 if sum(bool(x) for x in conflicting_options) > 1:
1231 parser.error('conflicting options: create-packages & show-packages & '
1232 'show-board-cfg')
Mike Frysinger984d0622012-06-01 16:08:44 -04001233
Gilad Arnold8195b532015-04-07 10:56:30 +03001234 targets_wanted = set(options.targets.split(','))
1235 boards_wanted = (set(options.include_boards.split(','))
1236 if options.include_boards else set())
Mike Frysinger35247af2012-11-16 18:58:06 -05001237
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001238 if options.cfg_name:
1239 ShowConfig(options.cfg_name)
Mike Frysinger91f52882017-09-13 00:16:58 -04001240 elif options.show_packages is not None:
1241 cros_build_lib.AssertInsideChroot()
1242 target = options.show_packages
1243 Crossdev.Load(False)
1244 for package in GetTargetPackages(target):
1245 print(GetPortagePackage(target, package))
Mike Frysinger35247af2012-11-16 18:58:06 -05001246 elif options.create_packages:
1247 cros_build_lib.AssertInsideChroot()
1248 Crossdev.Load(False)
Gilad Arnold8195b532015-04-07 10:56:30 +03001249 CreatePackages(targets_wanted, options.output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001250 else:
1251 cros_build_lib.AssertInsideChroot()
1252 # This has to be always run as root.
1253 if os.geteuid() != 0:
1254 cros_build_lib.Die('this script must be run as root')
1255
1256 Crossdev.Load(options.reconfig)
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001257 root = options.sysroot or '/'
Mike Frysinger35247af2012-11-16 18:58:06 -05001258 UpdateToolchains(options.usepkg, options.deleteold, options.hostonly,
Gilad Arnold8195b532015-04-07 10:56:30 +03001259 options.reconfig, targets_wanted, boards_wanted,
Don Garrettc0c74002015-10-09 12:58:19 -07001260 root=root)
Mike Frysinger35247af2012-11-16 18:58:06 -05001261 Crossdev.Save()
1262
1263 return 0