blob: 3a80bb262a1cb67a5248a7fe8f8c4c57f92bde93 [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#
Mike Frysinger66bfde52017-09-12 16:42:57 -040058# We don't use crossdev to manage the host toolchain for us, especially since
59# we diverge significantly now (with llvm/clang/etc...), and we don't need or
60# want crossdev managing /etc/portage config files for the sdk
61HOST_PACKAGES = (
62 'dev-lang/go',
63 'sys-devel/binutils',
64 'sys-devel/clang',
65 'sys-devel/gcc',
66 'sys-devel/llvm',
67 'sys-kernel/linux-headers',
68 'sys-libs/glibc',
69 'sys-libs/libcxx',
70 'sys-libs/libcxxabi',
71)
72
Rahul Chaudhry4b803052015-05-13 15:25:56 -070073# Enable the Go compiler for these targets.
74TARGET_GO_ENABLED = (
75 'x86_64-cros-linux-gnu',
Rahul Chaudhry4b803052015-05-13 15:25:56 -070076 'armv7a-cros-linux-gnueabi',
77)
78CROSSDEV_GO_ARGS = ['--ex-pkg', 'dev-lang/go']
79
Manoj Gupta1b5642e2017-03-08 16:44:12 -080080# Enable llvm's compiler-rt for these targets.
81TARGET_COMPILER_RT_ENABLED = (
82 'armv7a-cros-linux-gnueabi',
Manoj Gupta946abb42017-04-12 14:27:19 -070083 'aarch64-cros-linux-gnu',
Manoj Gupta1b5642e2017-03-08 16:44:12 -080084)
85CROSSDEV_COMPILER_RT_ARGS = ['--ex-pkg', 'sys-libs/compiler-rt']
86
Manoj Gupta946abb42017-04-12 14:27:19 -070087TARGET_LLVM_PKGS_ENABLED = (
88 'armv7a-cros-linux-gnueabi',
89 'aarch64-cros-linux-gnu',
90 'x86_64-cros-linux-gnu',
91)
92
93LLVM_PKGS_TABLE = {
Yunlian Jiangbb2a3d32017-04-26 14:44:09 -070094 'ex_libcxxabi' : ['--ex-pkg', 'sys-libs/libcxxabi'],
95 'ex_libcxx' : ['--ex-pkg', 'sys-libs/libcxx'],
Manoj Gupta946abb42017-04-12 14:27:19 -070096}
97
Zdenek Behan508dcce2011-12-05 15:39:32 +010098# Overrides for {gcc,binutils}-config, pick a package with particular suffix.
99CONFIG_TARGET_SUFFIXES = {
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500100 'binutils' : {
Mike Frysinger8a83c622015-05-28 00:35:05 -0400101 'armv6j-cros-linux-gnueabi': '-gold',
Han Shen43b84422015-02-19 11:38:13 -0800102 'armv7a-cros-linux-gnueabi': '-gold',
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500103 'i686-pc-linux-gnu' : '-gold',
104 'x86_64-cros-linux-gnu' : '-gold',
105 },
Zdenek Behan508dcce2011-12-05 15:39:32 +0100106}
Zdenek Behan508dcce2011-12-05 15:39:32 +0100107# Global per-run cache that will be filled ondemand in by GetPackageMap()
108# function as needed.
109target_version_map = {
110}
111
112
David James66a09c42012-11-05 13:31:38 -0800113class Crossdev(object):
114 """Class for interacting with crossdev and caching its output."""
115
116 _CACHE_FILE = os.path.join(CROSSDEV_OVERLAY, '.configured.json')
117 _CACHE = {}
Han Shene23782f2016-02-18 12:20:00 -0800118 # Packages that needs separate handling, in addition to what we have from
119 # crossdev.
120 MANUAL_PKGS = {
Manoj Guptaf0a602e2017-08-02 10:25:45 -0700121 'clang': 'sys-devel',
Han Shene23782f2016-02-18 12:20:00 -0800122 'llvm': 'sys-devel',
Manoj Gupta20cfc6c2017-07-19 15:49:55 -0700123 'libcxxabi': 'sys-libs',
124 'libcxx': 'sys-libs',
Han Shene23782f2016-02-18 12:20:00 -0800125 }
David James66a09c42012-11-05 13:31:38 -0800126
127 @classmethod
128 def Load(cls, reconfig):
Mike Frysinger3ed47722017-08-08 14:59:08 -0400129 """Load crossdev cache from disk.
130
131 We invalidate the cache when crossdev updates or this script changes.
132 """
David James90239b92012-11-05 15:31:34 -0800133 crossdev_version = GetStablePackageVersion('sys-devel/crossdev', True)
Mike Frysinger3ed47722017-08-08 14:59:08 -0400134 # If we run the compiled/cached .pyc file, we'll read/hash that when we
135 # really always want to track the source .py file.
136 script = os.path.abspath(__file__)
137 if script.endswith('.pyc'):
138 script = script[:-1]
139 setup_toolchains_hash = hashlib.md5(osutils.ReadFile(script)).hexdigest()
140
141 cls._CACHE = {
142 'crossdev_version': crossdev_version,
143 'setup_toolchains_hash': setup_toolchains_hash,
144 }
145
146 logging.debug('cache: checking file: %s', cls._CACHE_FILE)
147 if reconfig:
148 logging.debug('cache: forcing regen due to reconfig')
149 return
150
151 try:
152 file_data = osutils.ReadFile(cls._CACHE_FILE)
153 except IOError as e:
154 if e.errno != errno.ENOENT:
155 logging.warning('cache: reading failed: %s', e)
156 osutils.SafeUnlink(cls._CACHE_FILE)
157 return
158
159 try:
160 data = json.loads(file_data)
161 except ValueError as e:
162 logging.warning('cache: ignoring invalid content: %s', e)
163 return
164
165 if crossdev_version != data.get('crossdev_version'):
166 logging.debug('cache: rebuilding after crossdev upgrade')
167 elif setup_toolchains_hash != data.get('setup_toolchains_hash'):
168 logging.debug('cache: rebuilding after cros_setup_toolchains change')
169 else:
170 logging.debug('cache: content is up-to-date!')
171 cls._CACHE = data
David James66a09c42012-11-05 13:31:38 -0800172
173 @classmethod
174 def Save(cls):
175 """Store crossdev cache on disk."""
176 # Save the cache from the successful run.
177 with open(cls._CACHE_FILE, 'w') as f:
178 json.dump(cls._CACHE, f)
179
180 @classmethod
181 def GetConfig(cls, target):
182 """Returns a map of crossdev provided variables about a tuple."""
183 CACHE_ATTR = '_target_tuple_map'
184
185 val = cls._CACHE.setdefault(CACHE_ATTR, {})
186 if not target in val:
David James66a09c42012-11-05 13:31:38 -0800187 if target == 'host':
Mike Frysinger66bfde52017-09-12 16:42:57 -0400188 conf = {
189 'crosspkgs': [],
190 'target': toolchain.GetHostTuple(),
191 }
192 manual_pkgs = dict((pkg, cat) for cat, pkg in
193 [x.split('/') for x in HOST_PACKAGES])
194 else:
195 # Build the crossdev command.
196 cmd = ['crossdev', '--show-target-cfg', '--ex-gdb']
197 if target in TARGET_COMPILER_RT_ENABLED:
198 cmd.extend(CROSSDEV_COMPILER_RT_ARGS)
199 if target in TARGET_GO_ENABLED:
200 cmd.extend(CROSSDEV_GO_ARGS)
201 if target in TARGET_LLVM_PKGS_ENABLED:
202 for pkg in LLVM_PKGS_TABLE:
203 cmd.extend(LLVM_PKGS_TABLE[pkg])
204 cmd.extend(['-t', target])
205 # Catch output of crossdev.
206 out = cros_build_lib.RunCommand(
207 cmd, print_cmd=False, redirect_stdout=True).output.splitlines()
208 # List of tuples split at the first '=', converted into dict.
209 conf = dict((k, cros_build_lib.ShellUnquote(v))
210 for k, v in (x.split('=', 1) for x in out))
211 conf['crosspkgs'] = conf['crosspkgs'].split()
Han Shene23782f2016-02-18 12:20:00 -0800212
Mike Frysinger66bfde52017-09-12 16:42:57 -0400213 manual_pkgs = cls.MANUAL_PKGS
214
215 for pkg, cat in manual_pkgs.items():
Mike Frysinger3bba5032016-09-20 14:15:04 -0400216 conf[pkg + '_pn'] = pkg
217 conf[pkg + '_category'] = cat
218 if pkg not in conf['crosspkgs']:
219 conf['crosspkgs'].append(pkg)
Han Shene23782f2016-02-18 12:20:00 -0800220
221 val[target] = conf
222
David James66a09c42012-11-05 13:31:38 -0800223 return val[target]
224
225 @classmethod
226 def UpdateTargets(cls, targets, usepkg, config_only=False):
227 """Calls crossdev to initialize a cross target.
228
229 Args:
Don Garrett25f309a2014-03-19 14:02:12 -0700230 targets: The list of targets to initialize using crossdev.
231 usepkg: Copies the commandline opts.
232 config_only: Just update.
David James66a09c42012-11-05 13:31:38 -0800233 """
234 configured_targets = cls._CACHE.setdefault('configured_targets', [])
235
236 cmdbase = ['crossdev', '--show-fail-log']
237 cmdbase.extend(['--env', 'FEATURES=splitdebug'])
238 # Pick stable by default, and override as necessary.
239 cmdbase.extend(['-P', '--oneshot'])
240 if usepkg:
241 cmdbase.extend(['-P', '--getbinpkg',
242 '-P', '--usepkgonly',
243 '--without-headers'])
244
Christopher Wileyb22c0712015-06-02 10:37:03 -0700245 overlays = ' '.join((CHROMIUMOS_OVERLAY, ECLASS_OVERLAY, STABLE_OVERLAY))
David James66a09c42012-11-05 13:31:38 -0800246 cmdbase.extend(['--overlays', overlays])
247 cmdbase.extend(['--ov-output', CROSSDEV_OVERLAY])
248
249 for target in targets:
250 if config_only and target in configured_targets:
251 continue
252
253 cmd = cmdbase + ['-t', target]
254
255 for pkg in GetTargetPackages(target):
256 if pkg == 'gdb':
257 # Gdb does not have selectable versions.
258 cmd.append('--ex-gdb')
Manoj Guptab8181562017-05-21 10:18:59 -0700259 elif pkg == 'ex_compiler-rt':
260 cmd.extend(CROSSDEV_COMPILER_RT_ARGS)
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700261 elif pkg == 'ex_go':
262 # Go does not have selectable versions.
263 cmd.extend(CROSSDEV_GO_ARGS)
Manoj Gupta946abb42017-04-12 14:27:19 -0700264 elif pkg in LLVM_PKGS_TABLE:
265 cmd.extend(LLVM_PKGS_TABLE[pkg])
Han Shene23782f2016-02-18 12:20:00 -0800266 elif pkg in cls.MANUAL_PKGS:
267 pass
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700268 else:
269 # The first of the desired versions is the "primary" one.
270 version = GetDesiredPackageVersions(target, pkg)[0]
271 cmd.extend(['--%s' % pkg, version])
David James66a09c42012-11-05 13:31:38 -0800272
273 cmd.extend(targets[target]['crossdev'].split())
274 if config_only:
275 # In this case we want to just quietly reinit
276 cmd.append('--init-target')
277 cros_build_lib.RunCommand(cmd, print_cmd=False, redirect_stdout=True)
278 else:
279 cros_build_lib.RunCommand(cmd)
280
281 configured_targets.append(target)
282
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100283
Zdenek Behan508dcce2011-12-05 15:39:32 +0100284def GetPackageMap(target):
285 """Compiles a package map for the given target from the constants.
286
287 Uses a cache in target_version_map, that is dynamically filled in as needed,
288 since here everything is static data and the structuring is for ease of
289 configurability only.
290
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500291 Args:
292 target: The target for which to return a version map
Zdenek Behan508dcce2011-12-05 15:39:32 +0100293
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500294 Returns:
295 A map between packages and desired versions in internal format
296 (using the PACKAGE_* constants)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100297 """
298 if target in target_version_map:
299 return target_version_map[target]
300
301 # Start from copy of the global defaults.
302 result = copy.copy(DEFAULT_TARGET_VERSION_MAP)
303
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100304 for pkg in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100305 # prefer any specific overrides
306 if pkg in TARGET_VERSION_MAP.get(target, {}):
307 result[pkg] = TARGET_VERSION_MAP[target][pkg]
308 else:
309 # finally, if not already set, set a sane default
310 result.setdefault(pkg, DEFAULT_VERSION)
311 target_version_map[target] = result
312 return result
313
314
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100315def GetTargetPackages(target):
316 """Returns a list of packages for a given target."""
David James66a09c42012-11-05 13:31:38 -0800317 conf = Crossdev.GetConfig(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100318 # Undesired packages are denoted by empty ${pkg}_pn variable.
Han Shene23782f2016-02-18 12:20:00 -0800319 return [x for x in conf['crosspkgs'] if conf.get(x+'_pn')]
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100320
321
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100322# Portage helper functions:
323def GetPortagePackage(target, package):
324 """Returns a package name for the given target."""
David James66a09c42012-11-05 13:31:38 -0800325 conf = Crossdev.GetConfig(target)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100326 # Portage category:
Han Shene23782f2016-02-18 12:20:00 -0800327 if target == 'host' or package in Crossdev.MANUAL_PKGS:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100328 category = conf[package + '_category']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100329 else:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100330 category = conf['category']
331 # Portage package:
332 pn = conf[package + '_pn']
333 # Final package name:
Mike Frysinger422faf42014-11-12 23:16:48 -0500334 assert category
335 assert pn
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100336 return '%s/%s' % (category, pn)
337
338
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700339def PortageTrees(root):
340 """Return the portage trees for a given root."""
341 if root == '/':
342 return portage.db['/']
343 # The portage logic requires the path always end in a slash.
344 root = root.rstrip('/') + '/'
345 return portage.create_trees(target_root=root, config_root=root)[root]
346
347
348def GetInstalledPackageVersions(atom, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100349 """Extracts the list of current versions of a target, package pair.
350
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500351 Args:
352 atom: The atom to operate on (e.g. sys-devel/gcc)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700353 root: The root to check for installed packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100354
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500355 Returns:
356 The list of versions of the package currently installed.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100357 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100358 versions = []
Mike Frysinger506e75f2012-12-17 14:21:13 -0500359 # pylint: disable=E1101
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700360 for pkg in PortageTrees(root)['vartree'].dbapi.match(atom, use_cache=0):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100361 version = portage.versions.cpv_getversion(pkg)
362 versions.append(version)
363 return versions
364
365
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700366def GetStablePackageVersion(atom, installed, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100367 """Extracts the current stable version for a given package.
368
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500369 Args:
370 atom: The target/package to operate on eg. i686-pc-linux-gnu,gcc
371 installed: Whether we want installed packages or ebuilds
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700372 root: The root to use when querying packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100373
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500374 Returns:
375 A string containing the latest version.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100376 """
David James90239b92012-11-05 15:31:34 -0800377 pkgtype = 'vartree' if installed else 'porttree'
Mike Frysinger506e75f2012-12-17 14:21:13 -0500378 # pylint: disable=E1101
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700379 cpv = portage.best(PortageTrees(root)[pkgtype].dbapi.match(atom, use_cache=0))
David James90239b92012-11-05 15:31:34 -0800380 return portage.versions.cpv_getversion(cpv) if cpv else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100381
382
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700383def VersionListToNumeric(target, package, versions, installed, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100384 """Resolves keywords in a given version list for a particular package.
385
386 Resolving means replacing PACKAGE_STABLE with the actual number.
387
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500388 Args:
389 target: The target to operate on (e.g. i686-pc-linux-gnu)
390 package: The target/package to operate on (e.g. gcc)
391 versions: List of versions to resolve
392 installed: Query installed packages
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700393 root: The install root to use; ignored if |installed| is False.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100394
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500395 Returns:
396 List of purely numeric versions equivalent to argument
Zdenek Behan508dcce2011-12-05 15:39:32 +0100397 """
398 resolved = []
David James90239b92012-11-05 15:31:34 -0800399 atom = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700400 if not installed:
401 root = '/'
Zdenek Behan508dcce2011-12-05 15:39:32 +0100402 for version in versions:
403 if version == PACKAGE_STABLE:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700404 resolved.append(GetStablePackageVersion(atom, installed, root=root))
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400405 else:
Zdenek Behan508dcce2011-12-05 15:39:32 +0100406 resolved.append(version)
407 return resolved
408
409
410def GetDesiredPackageVersions(target, package):
411 """Produces the list of desired versions for each target, package pair.
412
413 The first version in the list is implicitly treated as primary, ie.
414 the version that will be initialized by crossdev and selected.
415
416 If the version is PACKAGE_STABLE, it really means the current version which
417 is emerged by using the package atom with no particular version key.
418 Since crossdev unmasks all packages by default, this will actually
419 mean 'unstable' in most cases.
420
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500421 Args:
422 target: The target to operate on (e.g. i686-pc-linux-gnu)
423 package: The target/package to operate on (e.g. gcc)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100424
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500425 Returns:
426 A list composed of either a version string, PACKAGE_STABLE
Zdenek Behan508dcce2011-12-05 15:39:32 +0100427 """
428 packagemap = GetPackageMap(target)
429
430 versions = []
431 if package in packagemap:
432 versions.append(packagemap[package])
433
434 return versions
435
436
437def TargetIsInitialized(target):
438 """Verifies if the given list of targets has been correctly initialized.
439
440 This determines whether we have to call crossdev while emerging
441 toolchain packages or can do it using emerge. Emerge is naturally
442 preferred, because all packages can be updated in a single pass.
443
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500444 Args:
445 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100446
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500447 Returns:
448 True if |target| is completely initialized, else False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100449 """
450 # Check if packages for the given target all have a proper version.
451 try:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100452 for package in GetTargetPackages(target):
David James66a09c42012-11-05 13:31:38 -0800453 atom = GetPortagePackage(target, package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100454 # Do we even want this package && is it initialized?
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400455 if not (GetStablePackageVersion(atom, True) and
456 GetStablePackageVersion(atom, False)):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100457 return False
458 return True
459 except cros_build_lib.RunCommandError:
460 # Fails - The target has likely never been initialized before.
461 return False
462
463
464def RemovePackageMask(target):
465 """Removes a package.mask file for the given platform.
466
467 The pre-existing package.mask files can mess with the keywords.
468
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500469 Args:
470 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100471 """
472 maskfile = os.path.join('/etc/portage/package.mask', 'cross-' + target)
Brian Harringaf019fb2012-05-10 15:06:13 -0700473 osutils.SafeUnlink(maskfile)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100474
475
Zdenek Behan508dcce2011-12-05 15:39:32 +0100476# Main functions performing the actual update steps.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700477def RebuildLibtool(root='/'):
Mike Frysingerc880a962013-11-08 13:59:06 -0500478 """Rebuild libtool as needed
479
480 Libtool hardcodes full paths to internal gcc files, so whenever we upgrade
481 gcc, libtool will break. We can't use binary packages either as those will
482 most likely be compiled against the previous version of gcc.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700483
484 Args:
485 root: The install root where we want libtool rebuilt.
Mike Frysingerc880a962013-11-08 13:59:06 -0500486 """
487 needs_update = False
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700488 with open(os.path.join(root, 'usr/bin/libtool')) as f:
Mike Frysingerc880a962013-11-08 13:59:06 -0500489 for line in f:
490 # Look for a line like:
491 # sys_lib_search_path_spec="..."
492 # It'll be a list of paths and gcc will be one of them.
493 if line.startswith('sys_lib_search_path_spec='):
494 line = line.rstrip()
495 for path in line.split('=', 1)[1].strip('"').split():
Mike Frysinger3bba5032016-09-20 14:15:04 -0400496 root_path = os.path.join(root, path.lstrip(os.path.sep))
497 logging.debug('Libtool: checking %s', root_path)
498 if not os.path.exists(root_path):
499 logging.info('Rebuilding libtool after gcc upgrade')
500 logging.info(' %s', line)
501 logging.info(' missing path: %s', path)
Mike Frysingerc880a962013-11-08 13:59:06 -0500502 needs_update = True
503 break
504
505 if needs_update:
506 break
507
508 if needs_update:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700509 cmd = [EMERGE_CMD, '--oneshot']
510 if root != '/':
511 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
512 cmd.append('sys-devel/libtool')
Mike Frysingerc880a962013-11-08 13:59:06 -0500513 cros_build_lib.RunCommand(cmd)
Mike Frysinger3bba5032016-09-20 14:15:04 -0400514 else:
515 logging.debug('Libtool is up-to-date; no need to rebuild')
Mike Frysingerc880a962013-11-08 13:59:06 -0500516
517
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700518def UpdateTargets(targets, usepkg, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100519 """Determines which packages need update/unmerge and defers to portage.
520
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500521 Args:
522 targets: The list of targets to update
523 usepkg: Copies the commandline option
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700524 root: The install root in which we want packages updated.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100525 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100526 # For each target, we do two things. Figure out the list of updates,
527 # and figure out the appropriate keywords/masks. Crossdev will initialize
528 # these, but they need to be regenerated on every update.
Mike Frysinger3bba5032016-09-20 14:15:04 -0400529 logging.info('Determining required toolchain updates...')
David James90239b92012-11-05 15:31:34 -0800530 mergemap = {}
Zdenek Behan508dcce2011-12-05 15:39:32 +0100531 for target in targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400532 logging.debug('Updating target %s', target)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100533 # Record the highest needed version for each target, for masking purposes.
534 RemovePackageMask(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100535 for package in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100536 # Portage name for the package
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400537 logging.debug(' Checking package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100538 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700539 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100540 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200541 desired_num = VersionListToNumeric(target, package, desired, False)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100542 mergemap[pkg] = set(desired_num).difference(current)
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400543 logging.debug(' %s -> %s', current, desired_num)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100544
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400545 packages = [pkg for pkg, vers in mergemap.items() if vers]
Zdenek Behan508dcce2011-12-05 15:39:32 +0100546 if not packages:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400547 logging.info('Nothing to update!')
David Jamesf8c672f2012-11-06 13:38:11 -0800548 return False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100549
Mike Frysinger3bba5032016-09-20 14:15:04 -0400550 logging.info('Updating packages:')
551 logging.info('%s', packages)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100552
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100553 cmd = [EMERGE_CMD, '--oneshot', '--update']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100554 if usepkg:
555 cmd.extend(['--getbinpkg', '--usepkgonly'])
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700556 if root != '/':
557 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100558
559 cmd.extend(packages)
560 cros_build_lib.RunCommand(cmd)
David Jamesf8c672f2012-11-06 13:38:11 -0800561 return True
Zdenek Behan508dcce2011-12-05 15:39:32 +0100562
563
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700564def CleanTargets(targets, root='/'):
565 """Unmerges old packages that are assumed unnecessary.
566
567 Args:
568 targets: The list of targets to clean up.
569 root: The install root in which we want packages cleaned up.
570 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100571 unmergemap = {}
572 for target in targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400573 logging.debug('Cleaning target %s', target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100574 for package in GetTargetPackages(target):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400575 logging.debug(' Cleaning package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100576 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700577 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100578 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2fcb0aa2015-05-21 14:51:41 -0700579 # NOTE: This refers to installed packages (vartree) rather than the
580 # Portage version (porttree and/or bintree) when determining the current
581 # version. While this isn't the most accurate thing to do, it is probably
582 # a good simple compromise, which should have the desired result of
583 # uninstalling everything but the latest installed version. In
584 # particular, using the bintree (--usebinpkg) requires a non-trivial
585 # binhost sync and is probably more complex than useful.
Zdenek Behan699ddd32012-04-13 07:14:08 +0200586 desired_num = VersionListToNumeric(target, package, desired, True)
587 if not set(desired_num).issubset(current):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400588 logging.warning('Error detecting stable version for %s, '
589 'skipping clean!', pkg)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200590 return
Zdenek Behan508dcce2011-12-05 15:39:32 +0100591 unmergemap[pkg] = set(current).difference(desired_num)
592
593 # Cleaning doesn't care about consistency and rebuilding package.* files.
594 packages = []
595 for pkg, vers in unmergemap.iteritems():
596 packages.extend('=%s-%s' % (pkg, ver) for ver in vers if ver != '9999')
597
598 if packages:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400599 logging.info('Cleaning packages:')
600 logging.info('%s', packages)
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100601 cmd = [EMERGE_CMD, '--unmerge']
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700602 if root != '/':
603 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100604 cmd.extend(packages)
605 cros_build_lib.RunCommand(cmd)
606 else:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400607 logging.info('Nothing to clean!')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100608
609
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700610def SelectActiveToolchains(targets, suffixes, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100611 """Runs gcc-config and binutils-config to select the desired.
612
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500613 Args:
614 targets: The targets to select
615 suffixes: Optional target-specific hacks
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700616 root: The root where we want to select toolchain versions.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100617 """
618 for package in ['gcc', 'binutils']:
619 for target in targets:
620 # Pick the first version in the numbered list as the selected one.
621 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700622 desired_num = VersionListToNumeric(target, package, desired, True,
623 root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100624 desired = desired_num[0]
625 # *-config does not play revisions, strip them, keep just PV.
626 desired = portage.versions.pkgsplit('%s-%s' % (package, desired))[1]
627
628 if target == 'host':
629 # *-config is the only tool treating host identically (by tuple).
David James27ac4ae2012-12-03 23:16:15 -0800630 target = toolchain.GetHostTuple()
Zdenek Behan508dcce2011-12-05 15:39:32 +0100631
632 # And finally, attach target to it.
633 desired = '%s-%s' % (target, desired)
634
635 # Target specific hacks
636 if package in suffixes:
637 if target in suffixes[package]:
638 desired += suffixes[package][target]
639
David James7ec5efc2012-11-06 09:39:49 -0800640 extra_env = {'CHOST': target}
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700641 if root != '/':
642 extra_env['ROOT'] = root
David James7ec5efc2012-11-06 09:39:49 -0800643 cmd = ['%s-config' % package, '-c', target]
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500644 result = cros_build_lib.RunCommand(
645 cmd, print_cmd=False, redirect_stdout=True, extra_env=extra_env)
646 current = result.output.splitlines()[0]
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700647
648 # Do not reconfig when the current is live or nothing needs to be done.
649 extra_env = {'ROOT': root} if root != '/' else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100650 if current != desired and current != '9999':
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500651 cmd = [package + '-config', desired]
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700652 cros_build_lib.RunCommand(cmd, print_cmd=False, extra_env=extra_env)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100653
654
Mike Frysinger35247af2012-11-16 18:58:06 -0500655def ExpandTargets(targets_wanted):
656 """Expand any possible toolchain aliases into full targets
657
658 This will expand 'all' and 'sdk' into the respective toolchain tuples.
659
660 Args:
661 targets_wanted: The targets specified by the user.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500662
Mike Frysinger35247af2012-11-16 18:58:06 -0500663 Returns:
Gilad Arnold8195b532015-04-07 10:56:30 +0300664 Dictionary of concrete targets and their toolchain tuples.
Mike Frysinger35247af2012-11-16 18:58:06 -0500665 """
Mike Frysinger35247af2012-11-16 18:58:06 -0500666 targets_wanted = set(targets_wanted)
Don Garrettc0c74002015-10-09 12:58:19 -0700667 if targets_wanted == set(['boards']):
668 # Only pull targets from the included boards.
Gilad Arnold8195b532015-04-07 10:56:30 +0300669 return {}
670
671 all_targets = toolchain.GetAllTargets()
Mike Frysinger35247af2012-11-16 18:58:06 -0500672 if targets_wanted == set(['all']):
Gilad Arnold8195b532015-04-07 10:56:30 +0300673 return all_targets
674 if targets_wanted == set(['sdk']):
Mike Frysinger35247af2012-11-16 18:58:06 -0500675 # Filter out all the non-sdk toolchains as we don't want to mess
676 # with those in all of our builds.
Gilad Arnold8195b532015-04-07 10:56:30 +0300677 return toolchain.FilterToolchains(all_targets, 'sdk', True)
678
679 # Verify user input.
680 nonexistent = targets_wanted.difference(all_targets)
681 if nonexistent:
682 raise ValueError('Invalid targets: %s', ','.join(nonexistent))
683 return {t: all_targets[t] for t in targets_wanted}
Mike Frysinger35247af2012-11-16 18:58:06 -0500684
685
David Jamesf8c672f2012-11-06 13:38:11 -0800686def UpdateToolchains(usepkg, deleteold, hostonly, reconfig,
Don Garrettc0c74002015-10-09 12:58:19 -0700687 targets_wanted, boards_wanted, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100688 """Performs all steps to create a synchronized toolchain enviroment.
689
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500690 Args:
691 usepkg: Use prebuilt packages
692 deleteold: Unmerge deprecated packages
693 hostonly: Only setup the host toolchain
694 reconfig: Reload crossdev config and reselect toolchains
695 targets_wanted: All the targets to update
696 boards_wanted: Load targets from these boards
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700697 root: The root in which to install the toolchains.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100698 """
David Jamesf8c672f2012-11-06 13:38:11 -0800699 targets, crossdev_targets, reconfig_targets = {}, {}, {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100700 if not hostonly:
701 # For hostonly, we can skip most of the below logic, much of which won't
702 # work on bare systems where this is useful.
Mike Frysinger35247af2012-11-16 18:58:06 -0500703 targets = ExpandTargets(targets_wanted)
Mike Frysinger7ccee992012-06-01 21:27:59 -0400704
Don Garrettc0c74002015-10-09 12:58:19 -0700705 # Now re-add any targets that might be from this board. This is to
Gilad Arnold8195b532015-04-07 10:56:30 +0300706 # allow unofficial boards to declare their own toolchains.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400707 for board in boards_wanted:
David James27ac4ae2012-12-03 23:16:15 -0800708 targets.update(toolchain.GetToolchainsForBoard(board))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100709
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100710 # First check and initialize all cross targets that need to be.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400711 for target in targets:
712 if TargetIsInitialized(target):
713 reconfig_targets[target] = targets[target]
714 else:
715 crossdev_targets[target] = targets[target]
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100716 if crossdev_targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400717 logging.info('The following targets need to be re-initialized:')
718 logging.info('%s', crossdev_targets)
David James66a09c42012-11-05 13:31:38 -0800719 Crossdev.UpdateTargets(crossdev_targets, usepkg)
Zdenek Behan8be29ba2012-05-29 23:10:34 +0200720 # Those that were not initialized may need a config update.
David James66a09c42012-11-05 13:31:38 -0800721 Crossdev.UpdateTargets(reconfig_targets, usepkg, config_only=True)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100722
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100723 # We want host updated.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400724 targets['host'] = {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100725
726 # Now update all packages.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700727 if UpdateTargets(targets, usepkg, root=root) or crossdev_targets or reconfig:
728 SelectActiveToolchains(targets, CONFIG_TARGET_SUFFIXES, root=root)
David James7ec5efc2012-11-06 09:39:49 -0800729
730 if deleteold:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700731 CleanTargets(targets, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100732
Mike Frysingerc880a962013-11-08 13:59:06 -0500733 # Now that we've cleared out old versions, see if we need to rebuild
734 # anything. Can't do this earlier as it might not be broken.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700735 RebuildLibtool(root=root)
Mike Frysingerc880a962013-11-08 13:59:06 -0500736
Zdenek Behan508dcce2011-12-05 15:39:32 +0100737
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -0700738def ShowConfig(name):
739 """Show the toolchain tuples used by |name|
Mike Frysinger35247af2012-11-16 18:58:06 -0500740
741 Args:
Don Garrettc0c74002015-10-09 12:58:19 -0700742 name: The board name to query.
Mike Frysinger35247af2012-11-16 18:58:06 -0500743 """
Don Garrettc0c74002015-10-09 12:58:19 -0700744 toolchains = toolchain.GetToolchainsForBoard(name)
Mike Frysinger35247af2012-11-16 18:58:06 -0500745 # Make sure we display the default toolchain first.
Mike Frysinger3bba5032016-09-20 14:15:04 -0400746 # Note: Do not use logging here as this is meant to be used by other tools.
Mike Frysinger383367e2014-09-16 15:06:17 -0400747 print(','.join(
David James27ac4ae2012-12-03 23:16:15 -0800748 toolchain.FilterToolchains(toolchains, 'default', True).keys() +
Mike Frysinger383367e2014-09-16 15:06:17 -0400749 toolchain.FilterToolchains(toolchains, 'default', False).keys()))
Mike Frysinger35247af2012-11-16 18:58:06 -0500750
751
Mike Frysinger35247af2012-11-16 18:58:06 -0500752def GeneratePathWrapper(root, wrappath, path):
753 """Generate a shell script to execute another shell script
754
755 Since we can't symlink a wrapped ELF (see GenerateLdsoWrapper) because the
756 argv[0] won't be pointing to the correct path, generate a shell script that
757 just executes another program with its full path.
758
759 Args:
760 root: The root tree to generate scripts inside of
761 wrappath: The full path (inside |root|) to create the wrapper
762 path: The target program which this wrapper will execute
763 """
764 replacements = {
765 'path': path,
766 'relroot': os.path.relpath('/', os.path.dirname(wrappath)),
767 }
768 wrapper = """#!/bin/sh
769base=$(realpath "$0")
770basedir=${base%%/*}
771exec "${basedir}/%(relroot)s%(path)s" "$@"
772""" % replacements
773 root_wrapper = root + wrappath
774 if os.path.islink(root_wrapper):
775 os.unlink(root_wrapper)
776 else:
777 osutils.SafeMakedirs(os.path.dirname(root_wrapper))
778 osutils.WriteFile(root_wrapper, wrapper)
Mike Frysinger60ec1012013-10-21 00:11:10 -0400779 os.chmod(root_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -0500780
781
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -0700782def FixClangXXWrapper(root, path):
783 """Fix wrapper shell scripts and symlinks for invoking clang++
784
785 In a typical installation, clang++ symlinks to clang, which symlinks to the
786 elf executable. The executable distinguishes between clang and clang++ based
787 on argv[0].
788
789 When invoked through the LdsoWrapper, argv[0] always contains the path to the
790 executable elf file, making clang/clang++ invocations indistinguishable.
791
792 This function detects if the elf executable being wrapped is clang-X.Y, and
793 fixes wrappers/symlinks as necessary so that clang++ will work correctly.
794
795 The calling sequence now becomes:
796 -) clang++ invocation turns into clang++-3.9 (which is a copy of clang-3.9,
797 the Ldsowrapper).
798 -) clang++-3.9 uses the Ldso to invoke clang++-3.9.elf, which is a symlink
799 to the original clang-3.9 elf.
800 -) The difference this time is that inside the elf file execution, $0 is
801 set as .../usr/bin/clang++-3.9.elf, which contains 'clang++' in the name.
802
803 Args:
804 root: The root tree to generate scripts / symlinks inside of
805 path: The target elf for which LdsoWrapper was created
806 """
807 if re.match(r'/usr/bin/clang-\d+\.\d+$', path):
808 logging.info('fixing clang++ invocation for %s', path)
809 clangdir = os.path.dirname(root + path)
810 clang = os.path.basename(path)
811 clangxx = clang.replace('clang', 'clang++')
812
813 # Create a symlink clang++-X.Y.elf to point to clang-X.Y.elf
814 os.symlink(clang + '.elf', os.path.join(clangdir, clangxx + '.elf'))
815
816 # Create a hardlink clang++-X.Y pointing to clang-X.Y
817 os.link(os.path.join(clangdir, clang), os.path.join(clangdir, clangxx))
818
819 # Adjust the clang++ symlink to point to clang++-X.Y
820 os.unlink(os.path.join(clangdir, 'clang++'))
821 os.symlink(clangxx, os.path.join(clangdir, 'clang++'))
822
823
Mike Frysinger35247af2012-11-16 18:58:06 -0500824def FileIsCrosSdkElf(elf):
825 """Determine if |elf| is an ELF that we execute in the cros_sdk
826
827 We don't need this to be perfect, just quick. It makes sure the ELF
828 is a 64bit LSB x86_64 ELF. That is the native type of cros_sdk.
829
830 Args:
831 elf: The file to check
Mike Frysinger1a736a82013-12-12 01:50:59 -0500832
Mike Frysinger35247af2012-11-16 18:58:06 -0500833 Returns:
834 True if we think |elf| is a native ELF
835 """
836 with open(elf) as f:
837 data = f.read(20)
838 # Check the magic number, EI_CLASS, EI_DATA, and e_machine.
839 return (data[0:4] == '\x7fELF' and
840 data[4] == '\x02' and
841 data[5] == '\x01' and
842 data[18] == '\x3e')
843
844
845def IsPathPackagable(ptype, path):
846 """Should the specified file be included in a toolchain package?
847
848 We only need to handle files as we'll create dirs as we need them.
849
850 Further, trim files that won't be useful:
851 - non-english translations (.mo) since it'd require env vars
852 - debug files since these are for the host compiler itself
853 - info/man pages as they're big, and docs are online, and the
854 native docs should work fine for the most part (`man gcc`)
855
856 Args:
857 ptype: A string describing the path type (i.e. 'file' or 'dir' or 'sym')
858 path: The full path to inspect
Mike Frysinger1a736a82013-12-12 01:50:59 -0500859
Mike Frysinger35247af2012-11-16 18:58:06 -0500860 Returns:
861 True if we want to include this path in the package
862 """
863 return not (ptype in ('dir',) or
864 path.startswith('/usr/lib/debug/') or
865 os.path.splitext(path)[1] == '.mo' or
866 ('/man/' in path or '/info/' in path))
867
868
869def ReadlinkRoot(path, root):
870 """Like os.readlink(), but relative to a |root|
871
872 Args:
873 path: The symlink to read
874 root: The path to use for resolving absolute symlinks
Mike Frysinger1a736a82013-12-12 01:50:59 -0500875
Mike Frysinger35247af2012-11-16 18:58:06 -0500876 Returns:
877 A fully resolved symlink path
878 """
879 while os.path.islink(root + path):
880 path = os.path.join(os.path.dirname(path), os.readlink(root + path))
881 return path
882
883
884def _GetFilesForTarget(target, root='/'):
885 """Locate all the files to package for |target|
886
887 This does not cover ELF dependencies.
888
889 Args:
890 target: The toolchain target name
891 root: The root path to pull all packages from
Mike Frysinger1a736a82013-12-12 01:50:59 -0500892
Mike Frysinger35247af2012-11-16 18:58:06 -0500893 Returns:
894 A tuple of a set of all packable paths, and a set of all paths which
895 are also native ELFs
896 """
897 paths = set()
898 elfs = set()
899
900 # Find all the files owned by the packages for this target.
901 for pkg in GetTargetPackages(target):
Mike Frysinger35247af2012-11-16 18:58:06 -0500902
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700903 # Skip Go compiler from redistributable packages.
904 # The "go" executable has GOROOT=/usr/lib/go/${CTARGET} hardcoded
905 # into it. Due to this, the toolchain cannot be unpacked anywhere
906 # else and be readily useful. To enable packaging Go, we need to:
907 # -) Tweak the wrappers/environment to override GOROOT
908 # automatically based on the unpack location.
909 # -) Make sure the ELF dependency checking and wrapping logic
910 # below skips the Go toolchain executables and libraries.
911 # -) Make sure the packaging process maintains the relative
912 # timestamps of precompiled standard library packages.
913 # (see dev-lang/go ebuild for details).
914 if pkg == 'ex_go':
915 continue
916
Mike Frysinger35247af2012-11-16 18:58:06 -0500917 atom = GetPortagePackage(target, pkg)
918 cat, pn = atom.split('/')
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700919 ver = GetInstalledPackageVersions(atom, root=root)[0]
Ralph Nathan03047282015-03-23 11:09:32 -0700920 logging.info('packaging %s-%s', atom, ver)
Mike Frysinger35247af2012-11-16 18:58:06 -0500921
922 # pylint: disable=E1101
923 dblink = portage.dblink(cat, pn + '-' + ver, myroot=root,
924 settings=portage.settings)
925 contents = dblink.getcontents()
926 for obj in contents:
927 ptype = contents[obj][0]
928 if not IsPathPackagable(ptype, obj):
929 continue
930
931 if ptype == 'obj':
932 # For native ELFs, we need to pull in their dependencies too.
933 if FileIsCrosSdkElf(obj):
934 elfs.add(obj)
935 paths.add(obj)
936
937 return paths, elfs
938
939
940def _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500941 path_rewrite_func=lambda x: x, root='/'):
Mike Frysinger35247af2012-11-16 18:58:06 -0500942 """Link in all packable files and their runtime dependencies
943
944 This also wraps up executable ELFs with helper scripts.
945
946 Args:
947 output_dir: The output directory to store files
948 paths: All the files to include
949 elfs: All the files which are ELFs (a subset of |paths|)
950 ldpaths: A dict of static ldpath information
951 path_rewrite_func: User callback to rewrite paths in output_dir
952 root: The root path to pull all packages/files from
953 """
954 # Link in all the files.
955 sym_paths = []
956 for path in paths:
957 new_path = path_rewrite_func(path)
958 dst = output_dir + new_path
959 osutils.SafeMakedirs(os.path.dirname(dst))
960
961 # Is this a symlink which we have to rewrite or wrap?
962 # Delay wrap check until after we have created all paths.
963 src = root + path
964 if os.path.islink(src):
965 tgt = os.readlink(src)
966 if os.path.sep in tgt:
967 sym_paths.append((new_path, lddtree.normpath(ReadlinkRoot(src, root))))
968
969 # Rewrite absolute links to relative and then generate the symlink
970 # ourselves. All other symlinks can be hardlinked below.
971 if tgt[0] == '/':
972 tgt = os.path.relpath(tgt, os.path.dirname(new_path))
973 os.symlink(tgt, dst)
974 continue
975
976 os.link(src, dst)
977
978 # Now see if any of the symlinks need to be wrapped.
979 for sym, tgt in sym_paths:
980 if tgt in elfs:
981 GeneratePathWrapper(output_dir, sym, tgt)
982
983 # Locate all the dependencies for all the ELFs. Stick them all in the
984 # top level "lib" dir to make the wrapper simpler. This exact path does
985 # not matter since we execute ldso directly, and we tell the ldso the
986 # exact path to search for its libraries.
987 libdir = os.path.join(output_dir, 'lib')
988 osutils.SafeMakedirs(libdir)
989 donelibs = set()
990 for elf in elfs:
Mike Frysingerea7688e2014-07-31 22:40:33 -0400991 e = lddtree.ParseELF(elf, root=root, ldpaths=ldpaths)
Mike Frysinger35247af2012-11-16 18:58:06 -0500992 interp = e['interp']
993 if interp:
994 # Generate a wrapper if it is executable.
Mike Frysingerc2ec0902013-03-26 01:28:45 -0400995 interp = os.path.join('/lib', os.path.basename(interp))
996 lddtree.GenerateLdsoWrapper(output_dir, path_rewrite_func(elf), interp,
997 libpaths=e['rpath'] + e['runpath'])
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -0700998 FixClangXXWrapper(output_dir, path_rewrite_func(elf))
Mike Frysinger35247af2012-11-16 18:58:06 -0500999
1000 for lib, lib_data in e['libs'].iteritems():
1001 if lib in donelibs:
1002 continue
1003
1004 src = path = lib_data['path']
1005 if path is None:
Ralph Nathan446aee92015-03-23 14:44:56 -07001006 logging.warning('%s: could not locate %s', elf, lib)
Mike Frysinger35247af2012-11-16 18:58:06 -05001007 continue
1008 donelibs.add(lib)
1009
1010 # Needed libs are the SONAME, but that is usually a symlink, not a
1011 # real file. So link in the target rather than the symlink itself.
1012 # We have to walk all the possible symlinks (SONAME could point to a
1013 # symlink which points to a symlink), and we have to handle absolute
1014 # ourselves (since we have a "root" argument).
1015 dst = os.path.join(libdir, os.path.basename(path))
1016 src = ReadlinkRoot(src, root)
1017
1018 os.link(root + src, dst)
1019
1020
1021def _EnvdGetVar(envd, var):
1022 """Given a Gentoo env.d file, extract a var from it
1023
1024 Args:
1025 envd: The env.d file to load (may be a glob path)
1026 var: The var to extract
Mike Frysinger1a736a82013-12-12 01:50:59 -05001027
Mike Frysinger35247af2012-11-16 18:58:06 -05001028 Returns:
1029 The value of |var|
1030 """
1031 envds = glob.glob(envd)
1032 assert len(envds) == 1, '%s: should have exactly 1 env.d file' % envd
1033 envd = envds[0]
1034 return cros_build_lib.LoadKeyValueFile(envd)[var]
1035
1036
1037def _ProcessBinutilsConfig(target, output_dir):
1038 """Do what binutils-config would have done"""
1039 binpath = os.path.join('/bin', target + '-')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001040
1041 # Locate the bin dir holding the gold linker.
1042 binutils_bin_path = os.path.join(output_dir, 'usr', toolchain.GetHostTuple(),
1043 target, 'binutils-bin')
1044 globpath = os.path.join(binutils_bin_path, '*-gold')
Mike Frysinger35247af2012-11-16 18:58:06 -05001045 srcpath = glob.glob(globpath)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001046 if not srcpath:
1047 # Maybe this target doesn't support gold.
1048 globpath = os.path.join(binutils_bin_path, '*')
1049 srcpath = glob.glob(globpath)
1050 assert len(srcpath) == 1, ('%s: matched more than one path (but not *-gold)'
1051 % globpath)
1052 srcpath = srcpath[0]
1053 ld_path = os.path.join(srcpath, 'ld')
1054 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1055 ld_path = os.path.join(srcpath, 'ld.bfd')
1056 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1057 ld_path = os.path.join(srcpath, 'ld.gold')
1058 assert not os.path.exists(ld_path), ('%s: exists, but gold dir does not!'
1059 % ld_path)
1060
1061 # Nope, no gold support to be found.
1062 gold_supported = False
Ralph Nathan446aee92015-03-23 14:44:56 -07001063 logging.warning('%s: binutils lacks support for the gold linker', target)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001064 else:
1065 assert len(srcpath) == 1, '%s: did not match exactly 1 path' % globpath
Mike Frysinger78b7a812014-11-26 19:45:23 -05001066 srcpath = srcpath[0]
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001067
Rahul Chaudhry4891b4d2017-03-08 10:31:27 -08001068 # Package the binutils-bin directory without the '-gold' suffix
1069 # if gold is not enabled as the default linker for this target.
1070 gold_supported = CONFIG_TARGET_SUFFIXES['binutils'].get(target) == '-gold'
1071 if not gold_supported:
1072 srcpath = srcpath[:-len('-gold')]
1073 ld_path = os.path.join(srcpath, 'ld')
1074 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1075
Mike Frysinger78b7a812014-11-26 19:45:23 -05001076 srcpath = srcpath[len(output_dir):]
Mike Frysinger35247af2012-11-16 18:58:06 -05001077 gccpath = os.path.join('/usr', 'libexec', 'gcc')
1078 for prog in os.listdir(output_dir + srcpath):
1079 # Skip binaries already wrapped.
1080 if not prog.endswith('.real'):
1081 GeneratePathWrapper(output_dir, binpath + prog,
1082 os.path.join(srcpath, prog))
1083 GeneratePathWrapper(output_dir, os.path.join(gccpath, prog),
1084 os.path.join(srcpath, prog))
1085
David James27ac4ae2012-12-03 23:16:15 -08001086 libpath = os.path.join('/usr', toolchain.GetHostTuple(), target, 'lib')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001087 envd = os.path.join(output_dir, 'etc', 'env.d', 'binutils', '*')
1088 if gold_supported:
1089 envd += '-gold'
Rahul Chaudhry4891b4d2017-03-08 10:31:27 -08001090 else:
1091 # If gold is not enabled as the default linker and 2 env.d
1092 # files exist, pick the one without the '-gold' suffix.
1093 envds = sorted(glob.glob(envd))
1094 if len(envds) == 2 and envds[1] == envds[0] + '-gold':
1095 envd = envds[0]
Mike Frysinger35247af2012-11-16 18:58:06 -05001096 srcpath = _EnvdGetVar(envd, 'LIBPATH')
1097 os.symlink(os.path.relpath(srcpath, os.path.dirname(libpath)),
1098 output_dir + libpath)
1099
1100
1101def _ProcessGccConfig(target, output_dir):
1102 """Do what gcc-config would have done"""
1103 binpath = '/bin'
1104 envd = os.path.join(output_dir, 'etc', 'env.d', 'gcc', '*')
1105 srcpath = _EnvdGetVar(envd, 'GCC_PATH')
1106 for prog in os.listdir(output_dir + srcpath):
1107 # Skip binaries already wrapped.
1108 if (not prog.endswith('.real') and
1109 not prog.endswith('.elf') and
1110 prog.startswith(target)):
1111 GeneratePathWrapper(output_dir, os.path.join(binpath, prog),
1112 os.path.join(srcpath, prog))
1113 return srcpath
1114
1115
Frank Henigman179ec7c2015-02-06 03:01:09 -05001116def _ProcessSysrootWrappers(_target, output_dir, srcpath):
1117 """Remove chroot-specific things from our sysroot wrappers"""
Mike Frysinger35247af2012-11-16 18:58:06 -05001118 # Disable ccache since we know it won't work outside of chroot.
Frank Henigman179ec7c2015-02-06 03:01:09 -05001119 for sysroot_wrapper in glob.glob(os.path.join(
1120 output_dir + srcpath, 'sysroot_wrapper*')):
1121 contents = osutils.ReadFile(sysroot_wrapper).splitlines()
1122 for num in xrange(len(contents)):
1123 if '@CCACHE_DEFAULT@' in contents[num]:
Caroline Ticece9e9232017-06-02 09:38:42 -07001124 assert 'True' in contents[num]
1125 contents[num] = contents[num].replace('True', 'False')
Frank Henigman179ec7c2015-02-06 03:01:09 -05001126 break
1127 # Can't update the wrapper in place since it's a hardlink to a file in /.
1128 os.unlink(sysroot_wrapper)
1129 osutils.WriteFile(sysroot_wrapper, '\n'.join(contents))
1130 os.chmod(sysroot_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -05001131
1132
1133def _ProcessDistroCleanups(target, output_dir):
1134 """Clean up the tree and remove all distro-specific requirements
1135
1136 Args:
1137 target: The toolchain target name
1138 output_dir: The output directory to clean up
1139 """
1140 _ProcessBinutilsConfig(target, output_dir)
1141 gcc_path = _ProcessGccConfig(target, output_dir)
Frank Henigman179ec7c2015-02-06 03:01:09 -05001142 _ProcessSysrootWrappers(target, output_dir, gcc_path)
Mike Frysinger35247af2012-11-16 18:58:06 -05001143
1144 osutils.RmDir(os.path.join(output_dir, 'etc'))
1145
1146
1147def CreatePackagableRoot(target, output_dir, ldpaths, root='/'):
1148 """Setup a tree from the packages for the specified target
1149
1150 This populates a path with all the files from toolchain packages so that
1151 a tarball can easily be generated from the result.
1152
1153 Args:
1154 target: The target to create a packagable root from
1155 output_dir: The output directory to place all the files
1156 ldpaths: A dict of static ldpath information
1157 root: The root path to pull all packages/files from
1158 """
1159 # Find all the files owned by the packages for this target.
1160 paths, elfs = _GetFilesForTarget(target, root=root)
1161
1162 # Link in all the package's files, any ELF dependencies, and wrap any
1163 # executable ELFs with helper scripts.
1164 def MoveUsrBinToBin(path):
Han Shen699ea192016-03-02 10:42:47 -08001165 """Move /usr/bin to /bin so people can just use that toplevel dir
1166
1167 Note we do not apply this to clang - there is correlation between clang's
1168 search path for libraries / inclusion and its installation path.
1169 """
1170 if path.startswith('/usr/bin/') and path.find('clang') == -1:
1171 return path[4:]
1172 return path
Mike Frysinger35247af2012-11-16 18:58:06 -05001173 _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
1174 path_rewrite_func=MoveUsrBinToBin, root=root)
1175
1176 # The packages, when part of the normal distro, have helper scripts
1177 # that setup paths and such. Since we are making this standalone, we
1178 # need to preprocess all that ourselves.
1179 _ProcessDistroCleanups(target, output_dir)
1180
1181
1182def CreatePackages(targets_wanted, output_dir, root='/'):
1183 """Create redistributable cross-compiler packages for the specified targets
1184
1185 This creates toolchain packages that should be usable in conjunction with
1186 a downloaded sysroot (created elsewhere).
1187
1188 Tarballs (one per target) will be created in $PWD.
1189
1190 Args:
Don Garrett25f309a2014-03-19 14:02:12 -07001191 targets_wanted: The targets to package up.
1192 output_dir: The directory to put the packages in.
1193 root: The root path to pull all packages/files from.
Mike Frysinger35247af2012-11-16 18:58:06 -05001194 """
Ralph Nathan03047282015-03-23 11:09:32 -07001195 logging.info('Writing tarballs to %s', output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001196 osutils.SafeMakedirs(output_dir)
1197 ldpaths = lddtree.LoadLdpaths(root)
1198 targets = ExpandTargets(targets_wanted)
1199
David James4bc13702013-03-26 08:08:04 -07001200 with osutils.TempDir() as tempdir:
Mike Frysinger35247af2012-11-16 18:58:06 -05001201 # We have to split the root generation from the compression stages. This is
1202 # because we hardlink in all the files (to avoid overhead of reading/writing
1203 # the copies multiple times). But tar gets angry if a file's hardlink count
1204 # changes from when it starts reading a file to when it finishes.
1205 with parallel.BackgroundTaskRunner(CreatePackagableRoot) as queue:
1206 for target in targets:
1207 output_target_dir = os.path.join(tempdir, target)
1208 queue.put([target, output_target_dir, ldpaths, root])
1209
1210 # Build the tarball.
1211 with parallel.BackgroundTaskRunner(cros_build_lib.CreateTarball) as queue:
1212 for target in targets:
1213 tar_file = os.path.join(output_dir, target + '.tar.xz')
1214 queue.put([tar_file, os.path.join(tempdir, target)])
1215
1216
Mike Frysinger07534cf2017-09-12 17:40:21 -04001217def GetParser():
1218 """Return a command line parser."""
Mike Frysinger0c808452014-11-06 17:30:23 -05001219 parser = commandline.ArgumentParser(description=__doc__)
1220 parser.add_argument('-u', '--nousepkg',
1221 action='store_false', dest='usepkg', default=True,
1222 help='Use prebuilt packages if possible')
1223 parser.add_argument('-d', '--deleteold',
1224 action='store_true', dest='deleteold', default=False,
1225 help='Unmerge deprecated packages')
1226 parser.add_argument('-t', '--targets',
1227 dest='targets', default='sdk',
Gilad Arnold8195b532015-04-07 10:56:30 +03001228 help="Comma separated list of tuples. Special keywords "
Don Garrettc0c74002015-10-09 12:58:19 -07001229 "'host', 'sdk', 'boards', and 'all' are "
Gilad Arnold8195b532015-04-07 10:56:30 +03001230 "allowed. Defaults to 'sdk'.")
1231 parser.add_argument('--include-boards', default='', metavar='BOARDS',
1232 help='Comma separated list of boards whose toolchains we '
1233 'will always include. Default: none')
Mike Frysinger0c808452014-11-06 17:30:23 -05001234 parser.add_argument('--hostonly',
1235 dest='hostonly', default=False, action='store_true',
1236 help='Only setup the host toolchain. '
1237 'Useful for bootstrapping chroot')
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001238 parser.add_argument('--show-board-cfg', '--show-cfg',
1239 dest='cfg_name', default=None,
Don Garrettc0c74002015-10-09 12:58:19 -07001240 help='Board to list toolchains tuples for')
Mike Frysinger91f52882017-09-13 00:16:58 -04001241 parser.add_argument('--show-packages', default=None,
1242 help='List all packages the specified target uses')
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.
Mike Frysinger91f52882017-09-13 00:16:58 -04001261 conflicting_options = (
1262 options.cfg_name,
1263 options.show_packages,
1264 options.create_packages,
1265 )
1266 if sum(bool(x) for x in conflicting_options) > 1:
1267 parser.error('conflicting options: create-packages & show-packages & '
1268 'show-board-cfg')
Mike Frysinger984d0622012-06-01 16:08:44 -04001269
Gilad Arnold8195b532015-04-07 10:56:30 +03001270 targets_wanted = set(options.targets.split(','))
1271 boards_wanted = (set(options.include_boards.split(','))
1272 if options.include_boards else set())
Mike Frysinger35247af2012-11-16 18:58:06 -05001273
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001274 if options.cfg_name:
1275 ShowConfig(options.cfg_name)
Mike Frysinger91f52882017-09-13 00:16:58 -04001276 elif options.show_packages is not None:
1277 cros_build_lib.AssertInsideChroot()
1278 target = options.show_packages
1279 Crossdev.Load(False)
1280 for package in GetTargetPackages(target):
1281 print(GetPortagePackage(target, package))
Mike Frysinger35247af2012-11-16 18:58:06 -05001282 elif options.create_packages:
1283 cros_build_lib.AssertInsideChroot()
1284 Crossdev.Load(False)
Gilad Arnold8195b532015-04-07 10:56:30 +03001285 CreatePackages(targets_wanted, options.output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001286 else:
1287 cros_build_lib.AssertInsideChroot()
1288 # This has to be always run as root.
1289 if os.geteuid() != 0:
1290 cros_build_lib.Die('this script must be run as root')
1291
1292 Crossdev.Load(options.reconfig)
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001293 root = options.sysroot or '/'
Mike Frysinger35247af2012-11-16 18:58:06 -05001294 UpdateToolchains(options.usepkg, options.deleteold, options.hostonly,
Gilad Arnold8195b532015-04-07 10:56:30 +03001295 options.reconfig, targets_wanted, boards_wanted,
Don Garrettc0c74002015-10-09 12:58:19 -07001296 root=root)
Mike Frysinger35247af2012-11-16 18:58:06 -05001297 Crossdev.Save()
1298
1299 return 0