blob: 71bfc7889b38160836c2feb77bcae074abba1315 [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',
Yunlian Jiang16c1a422017-10-04 10:33:22 -070068 'armv7a-cros-linux-gnueabihf',
Rahul Chaudhry4b803052015-05-13 15:25:56 -070069)
70CROSSDEV_GO_ARGS = ['--ex-pkg', 'dev-lang/go']
71
Manoj Gupta1b5642e2017-03-08 16:44:12 -080072# Enable llvm's compiler-rt for these targets.
73TARGET_COMPILER_RT_ENABLED = (
74 'armv7a-cros-linux-gnueabi',
Yunlian Jiang16c1a422017-10-04 10:33:22 -070075 #'armv7a-cros-linux-gnueabihf',
Manoj Gupta946abb42017-04-12 14:27:19 -070076 'aarch64-cros-linux-gnu',
Manoj Gupta1b5642e2017-03-08 16:44:12 -080077)
78CROSSDEV_COMPILER_RT_ARGS = ['--ex-pkg', 'sys-libs/compiler-rt']
79
Manoj Gupta946abb42017-04-12 14:27:19 -070080TARGET_LLVM_PKGS_ENABLED = (
81 'armv7a-cros-linux-gnueabi',
Yunlian Jiang16c1a422017-10-04 10:33:22 -070082 'armv7a-cros-linux-gnueabihf',
Manoj Gupta946abb42017-04-12 14:27:19 -070083 'aarch64-cros-linux-gnu',
84 'x86_64-cros-linux-gnu',
85)
86
87LLVM_PKGS_TABLE = {
Yunlian Jiangbb2a3d32017-04-26 14:44:09 -070088 'ex_libcxxabi' : ['--ex-pkg', 'sys-libs/libcxxabi'],
89 'ex_libcxx' : ['--ex-pkg', 'sys-libs/libcxx'],
Manoj Gupta946abb42017-04-12 14:27:19 -070090}
91
Zdenek Behan508dcce2011-12-05 15:39:32 +010092# Overrides for {gcc,binutils}-config, pick a package with particular suffix.
93CONFIG_TARGET_SUFFIXES = {
Mike Frysingerd6e2df02014-11-26 02:55:04 -050094 'binutils' : {
Mike Frysinger8a83c622015-05-28 00:35:05 -040095 'armv6j-cros-linux-gnueabi': '-gold',
Han Shen43b84422015-02-19 11:38:13 -080096 'armv7a-cros-linux-gnueabi': '-gold',
Yunlian Jiang16c1a422017-10-04 10:33:22 -070097 'armv7a-cros-linux-gnueabihf': '-gold',
Mike Frysingerd6e2df02014-11-26 02:55:04 -050098 'i686-pc-linux-gnu' : '-gold',
99 'x86_64-cros-linux-gnu' : '-gold',
100 },
Zdenek Behan508dcce2011-12-05 15:39:32 +0100101}
Zdenek Behan508dcce2011-12-05 15:39:32 +0100102
103
David James66a09c42012-11-05 13:31:38 -0800104class Crossdev(object):
105 """Class for interacting with crossdev and caching its output."""
106
107 _CACHE_FILE = os.path.join(CROSSDEV_OVERLAY, '.configured.json')
108 _CACHE = {}
Han Shene23782f2016-02-18 12:20:00 -0800109 # Packages that needs separate handling, in addition to what we have from
110 # crossdev.
111 MANUAL_PKGS = {
Manoj Guptaf0a602e2017-08-02 10:25:45 -0700112 'clang': 'sys-devel',
Han Shene23782f2016-02-18 12:20:00 -0800113 'llvm': 'sys-devel',
Manoj Gupta20cfc6c2017-07-19 15:49:55 -0700114 'libcxxabi': 'sys-libs',
115 'libcxx': 'sys-libs',
Han Shene23782f2016-02-18 12:20:00 -0800116 }
David James66a09c42012-11-05 13:31:38 -0800117
118 @classmethod
119 def Load(cls, reconfig):
Mike Frysinger3ed47722017-08-08 14:59:08 -0400120 """Load crossdev cache from disk.
121
122 We invalidate the cache when crossdev updates or this script changes.
123 """
David James90239b92012-11-05 15:31:34 -0800124 crossdev_version = GetStablePackageVersion('sys-devel/crossdev', True)
Mike Frysinger3ed47722017-08-08 14:59:08 -0400125 # If we run the compiled/cached .pyc file, we'll read/hash that when we
126 # really always want to track the source .py file.
127 script = os.path.abspath(__file__)
128 if script.endswith('.pyc'):
129 script = script[:-1]
130 setup_toolchains_hash = hashlib.md5(osutils.ReadFile(script)).hexdigest()
131
132 cls._CACHE = {
133 'crossdev_version': crossdev_version,
134 'setup_toolchains_hash': setup_toolchains_hash,
135 }
136
137 logging.debug('cache: checking file: %s', cls._CACHE_FILE)
138 if reconfig:
139 logging.debug('cache: forcing regen due to reconfig')
140 return
141
142 try:
143 file_data = osutils.ReadFile(cls._CACHE_FILE)
144 except IOError as e:
145 if e.errno != errno.ENOENT:
146 logging.warning('cache: reading failed: %s', e)
147 osutils.SafeUnlink(cls._CACHE_FILE)
148 return
149
150 try:
151 data = json.loads(file_data)
152 except ValueError as e:
153 logging.warning('cache: ignoring invalid content: %s', e)
154 return
155
156 if crossdev_version != data.get('crossdev_version'):
157 logging.debug('cache: rebuilding after crossdev upgrade')
158 elif setup_toolchains_hash != data.get('setup_toolchains_hash'):
159 logging.debug('cache: rebuilding after cros_setup_toolchains change')
160 else:
161 logging.debug('cache: content is up-to-date!')
162 cls._CACHE = data
David James66a09c42012-11-05 13:31:38 -0800163
164 @classmethod
165 def Save(cls):
166 """Store crossdev cache on disk."""
167 # Save the cache from the successful run.
168 with open(cls._CACHE_FILE, 'w') as f:
169 json.dump(cls._CACHE, f)
170
171 @classmethod
172 def GetConfig(cls, target):
173 """Returns a map of crossdev provided variables about a tuple."""
174 CACHE_ATTR = '_target_tuple_map'
175
176 val = cls._CACHE.setdefault(CACHE_ATTR, {})
177 if not target in val:
David James66a09c42012-11-05 13:31:38 -0800178 if target == 'host':
Mike Frysinger66bfde52017-09-12 16:42:57 -0400179 conf = {
180 'crosspkgs': [],
181 'target': toolchain.GetHostTuple(),
182 }
183 manual_pkgs = dict((pkg, cat) for cat, pkg in
184 [x.split('/') for x in HOST_PACKAGES])
185 else:
186 # Build the crossdev command.
187 cmd = ['crossdev', '--show-target-cfg', '--ex-gdb']
188 if target in TARGET_COMPILER_RT_ENABLED:
189 cmd.extend(CROSSDEV_COMPILER_RT_ARGS)
190 if target in TARGET_GO_ENABLED:
191 cmd.extend(CROSSDEV_GO_ARGS)
192 if target in TARGET_LLVM_PKGS_ENABLED:
193 for pkg in LLVM_PKGS_TABLE:
194 cmd.extend(LLVM_PKGS_TABLE[pkg])
195 cmd.extend(['-t', target])
196 # Catch output of crossdev.
197 out = cros_build_lib.RunCommand(
198 cmd, print_cmd=False, redirect_stdout=True).output.splitlines()
199 # List of tuples split at the first '=', converted into dict.
200 conf = dict((k, cros_build_lib.ShellUnquote(v))
201 for k, v in (x.split('=', 1) for x in out))
202 conf['crosspkgs'] = conf['crosspkgs'].split()
Han Shene23782f2016-02-18 12:20:00 -0800203
Mike Frysinger66bfde52017-09-12 16:42:57 -0400204 manual_pkgs = cls.MANUAL_PKGS
205
206 for pkg, cat in manual_pkgs.items():
Mike Frysinger3bba5032016-09-20 14:15:04 -0400207 conf[pkg + '_pn'] = pkg
208 conf[pkg + '_category'] = cat
209 if pkg not in conf['crosspkgs']:
210 conf['crosspkgs'].append(pkg)
Han Shene23782f2016-02-18 12:20:00 -0800211
212 val[target] = conf
213
David James66a09c42012-11-05 13:31:38 -0800214 return val[target]
215
216 @classmethod
217 def UpdateTargets(cls, targets, usepkg, config_only=False):
218 """Calls crossdev to initialize a cross target.
219
220 Args:
Don Garrett25f309a2014-03-19 14:02:12 -0700221 targets: The list of targets to initialize using crossdev.
222 usepkg: Copies the commandline opts.
223 config_only: Just update.
David James66a09c42012-11-05 13:31:38 -0800224 """
225 configured_targets = cls._CACHE.setdefault('configured_targets', [])
226
227 cmdbase = ['crossdev', '--show-fail-log']
228 cmdbase.extend(['--env', 'FEATURES=splitdebug'])
229 # Pick stable by default, and override as necessary.
230 cmdbase.extend(['-P', '--oneshot'])
231 if usepkg:
232 cmdbase.extend(['-P', '--getbinpkg',
233 '-P', '--usepkgonly',
234 '--without-headers'])
235
Christopher Wileyb22c0712015-06-02 10:37:03 -0700236 overlays = ' '.join((CHROMIUMOS_OVERLAY, ECLASS_OVERLAY, STABLE_OVERLAY))
David James66a09c42012-11-05 13:31:38 -0800237 cmdbase.extend(['--overlays', overlays])
238 cmdbase.extend(['--ov-output', CROSSDEV_OVERLAY])
239
240 for target in targets:
241 if config_only and target in configured_targets:
242 continue
243
244 cmd = cmdbase + ['-t', target]
245
246 for pkg in GetTargetPackages(target):
247 if pkg == 'gdb':
248 # Gdb does not have selectable versions.
249 cmd.append('--ex-gdb')
Manoj Guptab8181562017-05-21 10:18:59 -0700250 elif pkg == 'ex_compiler-rt':
251 cmd.extend(CROSSDEV_COMPILER_RT_ARGS)
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700252 elif pkg == 'ex_go':
253 # Go does not have selectable versions.
254 cmd.extend(CROSSDEV_GO_ARGS)
Manoj Gupta946abb42017-04-12 14:27:19 -0700255 elif pkg in LLVM_PKGS_TABLE:
256 cmd.extend(LLVM_PKGS_TABLE[pkg])
Han Shene23782f2016-02-18 12:20:00 -0800257 elif pkg in cls.MANUAL_PKGS:
258 pass
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700259 else:
260 # The first of the desired versions is the "primary" one.
261 version = GetDesiredPackageVersions(target, pkg)[0]
262 cmd.extend(['--%s' % pkg, version])
David James66a09c42012-11-05 13:31:38 -0800263
264 cmd.extend(targets[target]['crossdev'].split())
265 if config_only:
266 # In this case we want to just quietly reinit
267 cmd.append('--init-target')
268 cros_build_lib.RunCommand(cmd, print_cmd=False, redirect_stdout=True)
269 else:
270 cros_build_lib.RunCommand(cmd)
271
272 configured_targets.append(target)
273
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100274
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100275def GetTargetPackages(target):
276 """Returns a list of packages for a given target."""
David James66a09c42012-11-05 13:31:38 -0800277 conf = Crossdev.GetConfig(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100278 # Undesired packages are denoted by empty ${pkg}_pn variable.
Han Shene23782f2016-02-18 12:20:00 -0800279 return [x for x in conf['crosspkgs'] if conf.get(x+'_pn')]
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100280
281
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100282# Portage helper functions:
283def GetPortagePackage(target, package):
284 """Returns a package name for the given target."""
David James66a09c42012-11-05 13:31:38 -0800285 conf = Crossdev.GetConfig(target)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100286 # Portage category:
Han Shene23782f2016-02-18 12:20:00 -0800287 if target == 'host' or package in Crossdev.MANUAL_PKGS:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100288 category = conf[package + '_category']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100289 else:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100290 category = conf['category']
291 # Portage package:
292 pn = conf[package + '_pn']
293 # Final package name:
Mike Frysinger422faf42014-11-12 23:16:48 -0500294 assert category
295 assert pn
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100296 return '%s/%s' % (category, pn)
297
298
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700299def PortageTrees(root):
300 """Return the portage trees for a given root."""
301 if root == '/':
302 return portage.db['/']
303 # The portage logic requires the path always end in a slash.
304 root = root.rstrip('/') + '/'
305 return portage.create_trees(target_root=root, config_root=root)[root]
306
307
308def GetInstalledPackageVersions(atom, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100309 """Extracts the list of current versions of a target, package pair.
310
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500311 Args:
312 atom: The atom to operate on (e.g. sys-devel/gcc)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700313 root: The root to check for installed packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100314
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500315 Returns:
316 The list of versions of the package currently installed.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100317 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100318 versions = []
Mike Frysinger506e75f2012-12-17 14:21:13 -0500319 # pylint: disable=E1101
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700320 for pkg in PortageTrees(root)['vartree'].dbapi.match(atom, use_cache=0):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100321 version = portage.versions.cpv_getversion(pkg)
322 versions.append(version)
323 return versions
324
325
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700326def GetStablePackageVersion(atom, installed, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100327 """Extracts the current stable version for a given package.
328
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500329 Args:
330 atom: The target/package to operate on eg. i686-pc-linux-gnu,gcc
331 installed: Whether we want installed packages or ebuilds
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700332 root: The root to use when querying packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100333
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500334 Returns:
335 A string containing the latest version.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100336 """
David James90239b92012-11-05 15:31:34 -0800337 pkgtype = 'vartree' if installed else 'porttree'
Mike Frysinger506e75f2012-12-17 14:21:13 -0500338 # pylint: disable=E1101
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700339 cpv = portage.best(PortageTrees(root)[pkgtype].dbapi.match(atom, use_cache=0))
David James90239b92012-11-05 15:31:34 -0800340 return portage.versions.cpv_getversion(cpv) if cpv else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100341
342
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700343def VersionListToNumeric(target, package, versions, installed, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100344 """Resolves keywords in a given version list for a particular package.
345
346 Resolving means replacing PACKAGE_STABLE with the actual number.
347
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500348 Args:
349 target: The target to operate on (e.g. i686-pc-linux-gnu)
350 package: The target/package to operate on (e.g. gcc)
351 versions: List of versions to resolve
352 installed: Query installed packages
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700353 root: The install root to use; ignored if |installed| is False.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100354
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500355 Returns:
356 List of purely numeric versions equivalent to argument
Zdenek Behan508dcce2011-12-05 15:39:32 +0100357 """
358 resolved = []
David James90239b92012-11-05 15:31:34 -0800359 atom = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700360 if not installed:
361 root = '/'
Zdenek Behan508dcce2011-12-05 15:39:32 +0100362 for version in versions:
363 if version == PACKAGE_STABLE:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700364 resolved.append(GetStablePackageVersion(atom, installed, root=root))
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400365 else:
Zdenek Behan508dcce2011-12-05 15:39:32 +0100366 resolved.append(version)
367 return resolved
368
369
370def GetDesiredPackageVersions(target, package):
371 """Produces the list of desired versions for each target, package pair.
372
373 The first version in the list is implicitly treated as primary, ie.
374 the version that will be initialized by crossdev and selected.
375
376 If the version is PACKAGE_STABLE, it really means the current version which
377 is emerged by using the package atom with no particular version key.
378 Since crossdev unmasks all packages by default, this will actually
379 mean 'unstable' in most cases.
380
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500381 Args:
382 target: The target to operate on (e.g. i686-pc-linux-gnu)
383 package: The target/package to operate on (e.g. gcc)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100384
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500385 Returns:
386 A list composed of either a version string, PACKAGE_STABLE
Zdenek Behan508dcce2011-12-05 15:39:32 +0100387 """
Mike Frysingerd23be272017-09-12 17:18:44 -0400388 if package in GetTargetPackages(target):
389 return [PACKAGE_STABLE]
390 else:
391 return []
Zdenek Behan508dcce2011-12-05 15:39:32 +0100392
393
394def TargetIsInitialized(target):
395 """Verifies if the given list of targets has been correctly initialized.
396
397 This determines whether we have to call crossdev while emerging
398 toolchain packages or can do it using emerge. Emerge is naturally
399 preferred, because all packages can be updated in a single pass.
400
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500401 Args:
402 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100403
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500404 Returns:
405 True if |target| is completely initialized, else False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100406 """
407 # Check if packages for the given target all have a proper version.
408 try:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100409 for package in GetTargetPackages(target):
David James66a09c42012-11-05 13:31:38 -0800410 atom = GetPortagePackage(target, package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100411 # Do we even want this package && is it initialized?
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400412 if not (GetStablePackageVersion(atom, True) and
413 GetStablePackageVersion(atom, False)):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100414 return False
415 return True
416 except cros_build_lib.RunCommandError:
417 # Fails - The target has likely never been initialized before.
418 return False
419
420
421def RemovePackageMask(target):
422 """Removes a package.mask file for the given platform.
423
424 The pre-existing package.mask files can mess with the keywords.
425
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500426 Args:
427 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100428 """
429 maskfile = os.path.join('/etc/portage/package.mask', 'cross-' + target)
Brian Harringaf019fb2012-05-10 15:06:13 -0700430 osutils.SafeUnlink(maskfile)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100431
432
Zdenek Behan508dcce2011-12-05 15:39:32 +0100433# Main functions performing the actual update steps.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700434def RebuildLibtool(root='/'):
Mike Frysingerc880a962013-11-08 13:59:06 -0500435 """Rebuild libtool as needed
436
437 Libtool hardcodes full paths to internal gcc files, so whenever we upgrade
438 gcc, libtool will break. We can't use binary packages either as those will
439 most likely be compiled against the previous version of gcc.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700440
441 Args:
442 root: The install root where we want libtool rebuilt.
Mike Frysingerc880a962013-11-08 13:59:06 -0500443 """
444 needs_update = False
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700445 with open(os.path.join(root, 'usr/bin/libtool')) as f:
Mike Frysingerc880a962013-11-08 13:59:06 -0500446 for line in f:
447 # Look for a line like:
448 # sys_lib_search_path_spec="..."
449 # It'll be a list of paths and gcc will be one of them.
450 if line.startswith('sys_lib_search_path_spec='):
451 line = line.rstrip()
452 for path in line.split('=', 1)[1].strip('"').split():
Mike Frysinger3bba5032016-09-20 14:15:04 -0400453 root_path = os.path.join(root, path.lstrip(os.path.sep))
454 logging.debug('Libtool: checking %s', root_path)
455 if not os.path.exists(root_path):
456 logging.info('Rebuilding libtool after gcc upgrade')
457 logging.info(' %s', line)
458 logging.info(' missing path: %s', path)
Mike Frysingerc880a962013-11-08 13:59:06 -0500459 needs_update = True
460 break
461
462 if needs_update:
463 break
464
465 if needs_update:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700466 cmd = [EMERGE_CMD, '--oneshot']
467 if root != '/':
468 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
469 cmd.append('sys-devel/libtool')
Mike Frysingerc880a962013-11-08 13:59:06 -0500470 cros_build_lib.RunCommand(cmd)
Mike Frysinger3bba5032016-09-20 14:15:04 -0400471 else:
472 logging.debug('Libtool is up-to-date; no need to rebuild')
Mike Frysingerc880a962013-11-08 13:59:06 -0500473
474
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700475def UpdateTargets(targets, usepkg, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100476 """Determines which packages need update/unmerge and defers to portage.
477
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500478 Args:
479 targets: The list of targets to update
480 usepkg: Copies the commandline option
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700481 root: The install root in which we want packages updated.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100482 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100483 # For each target, we do two things. Figure out the list of updates,
484 # and figure out the appropriate keywords/masks. Crossdev will initialize
485 # these, but they need to be regenerated on every update.
Mike Frysinger3bba5032016-09-20 14:15:04 -0400486 logging.info('Determining required toolchain updates...')
David James90239b92012-11-05 15:31:34 -0800487 mergemap = {}
Zdenek Behan508dcce2011-12-05 15:39:32 +0100488 for target in targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400489 logging.debug('Updating target %s', target)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100490 # Record the highest needed version for each target, for masking purposes.
491 RemovePackageMask(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100492 for package in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100493 # Portage name for the package
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400494 logging.debug(' Checking package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100495 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700496 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100497 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200498 desired_num = VersionListToNumeric(target, package, desired, False)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100499 mergemap[pkg] = set(desired_num).difference(current)
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400500 logging.debug(' %s -> %s', current, desired_num)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100501
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400502 packages = [pkg for pkg, vers in mergemap.items() if vers]
Zdenek Behan508dcce2011-12-05 15:39:32 +0100503 if not packages:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400504 logging.info('Nothing to update!')
David Jamesf8c672f2012-11-06 13:38:11 -0800505 return False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100506
Mike Frysinger3bba5032016-09-20 14:15:04 -0400507 logging.info('Updating packages:')
508 logging.info('%s', packages)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100509
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100510 cmd = [EMERGE_CMD, '--oneshot', '--update']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100511 if usepkg:
512 cmd.extend(['--getbinpkg', '--usepkgonly'])
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700513 if root != '/':
514 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100515
516 cmd.extend(packages)
517 cros_build_lib.RunCommand(cmd)
David Jamesf8c672f2012-11-06 13:38:11 -0800518 return True
Zdenek Behan508dcce2011-12-05 15:39:32 +0100519
520
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700521def CleanTargets(targets, root='/'):
522 """Unmerges old packages that are assumed unnecessary.
523
524 Args:
525 targets: The list of targets to clean up.
526 root: The install root in which we want packages cleaned up.
527 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100528 unmergemap = {}
529 for target in targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400530 logging.debug('Cleaning target %s', target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100531 for package in GetTargetPackages(target):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400532 logging.debug(' Cleaning package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100533 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700534 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100535 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2fcb0aa2015-05-21 14:51:41 -0700536 # NOTE: This refers to installed packages (vartree) rather than the
537 # Portage version (porttree and/or bintree) when determining the current
538 # version. While this isn't the most accurate thing to do, it is probably
539 # a good simple compromise, which should have the desired result of
540 # uninstalling everything but the latest installed version. In
541 # particular, using the bintree (--usebinpkg) requires a non-trivial
542 # binhost sync and is probably more complex than useful.
Zdenek Behan699ddd32012-04-13 07:14:08 +0200543 desired_num = VersionListToNumeric(target, package, desired, True)
544 if not set(desired_num).issubset(current):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400545 logging.warning('Error detecting stable version for %s, '
546 'skipping clean!', pkg)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200547 return
Zdenek Behan508dcce2011-12-05 15:39:32 +0100548 unmergemap[pkg] = set(current).difference(desired_num)
549
550 # Cleaning doesn't care about consistency and rebuilding package.* files.
551 packages = []
552 for pkg, vers in unmergemap.iteritems():
553 packages.extend('=%s-%s' % (pkg, ver) for ver in vers if ver != '9999')
554
555 if packages:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400556 logging.info('Cleaning packages:')
557 logging.info('%s', packages)
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100558 cmd = [EMERGE_CMD, '--unmerge']
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700559 if root != '/':
560 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100561 cmd.extend(packages)
562 cros_build_lib.RunCommand(cmd)
563 else:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400564 logging.info('Nothing to clean!')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100565
566
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700567def SelectActiveToolchains(targets, suffixes, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100568 """Runs gcc-config and binutils-config to select the desired.
569
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500570 Args:
571 targets: The targets to select
572 suffixes: Optional target-specific hacks
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700573 root: The root where we want to select toolchain versions.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100574 """
575 for package in ['gcc', 'binutils']:
576 for target in targets:
577 # Pick the first version in the numbered list as the selected one.
578 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700579 desired_num = VersionListToNumeric(target, package, desired, True,
580 root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100581 desired = desired_num[0]
582 # *-config does not play revisions, strip them, keep just PV.
583 desired = portage.versions.pkgsplit('%s-%s' % (package, desired))[1]
584
585 if target == 'host':
586 # *-config is the only tool treating host identically (by tuple).
David James27ac4ae2012-12-03 23:16:15 -0800587 target = toolchain.GetHostTuple()
Zdenek Behan508dcce2011-12-05 15:39:32 +0100588
589 # And finally, attach target to it.
590 desired = '%s-%s' % (target, desired)
591
592 # Target specific hacks
593 if package in suffixes:
594 if target in suffixes[package]:
595 desired += suffixes[package][target]
596
David James7ec5efc2012-11-06 09:39:49 -0800597 extra_env = {'CHOST': target}
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700598 if root != '/':
599 extra_env['ROOT'] = root
David James7ec5efc2012-11-06 09:39:49 -0800600 cmd = ['%s-config' % package, '-c', target]
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500601 result = cros_build_lib.RunCommand(
602 cmd, print_cmd=False, redirect_stdout=True, extra_env=extra_env)
603 current = result.output.splitlines()[0]
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700604
605 # Do not reconfig when the current is live or nothing needs to be done.
606 extra_env = {'ROOT': root} if root != '/' else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100607 if current != desired and current != '9999':
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500608 cmd = [package + '-config', desired]
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700609 cros_build_lib.RunCommand(cmd, print_cmd=False, extra_env=extra_env)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100610
611
Mike Frysinger35247af2012-11-16 18:58:06 -0500612def ExpandTargets(targets_wanted):
613 """Expand any possible toolchain aliases into full targets
614
615 This will expand 'all' and 'sdk' into the respective toolchain tuples.
616
617 Args:
618 targets_wanted: The targets specified by the user.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500619
Mike Frysinger35247af2012-11-16 18:58:06 -0500620 Returns:
Gilad Arnold8195b532015-04-07 10:56:30 +0300621 Dictionary of concrete targets and their toolchain tuples.
Mike Frysinger35247af2012-11-16 18:58:06 -0500622 """
Mike Frysinger35247af2012-11-16 18:58:06 -0500623 targets_wanted = set(targets_wanted)
Don Garrettc0c74002015-10-09 12:58:19 -0700624 if targets_wanted == set(['boards']):
625 # Only pull targets from the included boards.
Gilad Arnold8195b532015-04-07 10:56:30 +0300626 return {}
627
628 all_targets = toolchain.GetAllTargets()
Mike Frysinger35247af2012-11-16 18:58:06 -0500629 if targets_wanted == set(['all']):
Gilad Arnold8195b532015-04-07 10:56:30 +0300630 return all_targets
631 if targets_wanted == set(['sdk']):
Mike Frysinger35247af2012-11-16 18:58:06 -0500632 # Filter out all the non-sdk toolchains as we don't want to mess
633 # with those in all of our builds.
Gilad Arnold8195b532015-04-07 10:56:30 +0300634 return toolchain.FilterToolchains(all_targets, 'sdk', True)
635
636 # Verify user input.
637 nonexistent = targets_wanted.difference(all_targets)
638 if nonexistent:
639 raise ValueError('Invalid targets: %s', ','.join(nonexistent))
640 return {t: all_targets[t] for t in targets_wanted}
Mike Frysinger35247af2012-11-16 18:58:06 -0500641
642
David Jamesf8c672f2012-11-06 13:38:11 -0800643def UpdateToolchains(usepkg, deleteold, hostonly, reconfig,
Don Garrettc0c74002015-10-09 12:58:19 -0700644 targets_wanted, boards_wanted, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100645 """Performs all steps to create a synchronized toolchain enviroment.
646
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500647 Args:
648 usepkg: Use prebuilt packages
649 deleteold: Unmerge deprecated packages
650 hostonly: Only setup the host toolchain
651 reconfig: Reload crossdev config and reselect toolchains
652 targets_wanted: All the targets to update
653 boards_wanted: Load targets from these boards
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700654 root: The root in which to install the toolchains.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100655 """
David Jamesf8c672f2012-11-06 13:38:11 -0800656 targets, crossdev_targets, reconfig_targets = {}, {}, {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100657 if not hostonly:
658 # For hostonly, we can skip most of the below logic, much of which won't
659 # work on bare systems where this is useful.
Mike Frysinger35247af2012-11-16 18:58:06 -0500660 targets = ExpandTargets(targets_wanted)
Mike Frysinger7ccee992012-06-01 21:27:59 -0400661
Don Garrettc0c74002015-10-09 12:58:19 -0700662 # Now re-add any targets that might be from this board. This is to
Gilad Arnold8195b532015-04-07 10:56:30 +0300663 # allow unofficial boards to declare their own toolchains.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400664 for board in boards_wanted:
David James27ac4ae2012-12-03 23:16:15 -0800665 targets.update(toolchain.GetToolchainsForBoard(board))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100666
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100667 # First check and initialize all cross targets that need to be.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400668 for target in targets:
669 if TargetIsInitialized(target):
670 reconfig_targets[target] = targets[target]
671 else:
672 crossdev_targets[target] = targets[target]
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100673 if crossdev_targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400674 logging.info('The following targets need to be re-initialized:')
675 logging.info('%s', crossdev_targets)
David James66a09c42012-11-05 13:31:38 -0800676 Crossdev.UpdateTargets(crossdev_targets, usepkg)
Zdenek Behan8be29ba2012-05-29 23:10:34 +0200677 # Those that were not initialized may need a config update.
David James66a09c42012-11-05 13:31:38 -0800678 Crossdev.UpdateTargets(reconfig_targets, usepkg, config_only=True)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100679
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100680 # We want host updated.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400681 targets['host'] = {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100682
683 # Now update all packages.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700684 if UpdateTargets(targets, usepkg, root=root) or crossdev_targets or reconfig:
685 SelectActiveToolchains(targets, CONFIG_TARGET_SUFFIXES, root=root)
David James7ec5efc2012-11-06 09:39:49 -0800686
687 if deleteold:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700688 CleanTargets(targets, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100689
Mike Frysingerc880a962013-11-08 13:59:06 -0500690 # Now that we've cleared out old versions, see if we need to rebuild
691 # anything. Can't do this earlier as it might not be broken.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700692 RebuildLibtool(root=root)
Mike Frysingerc880a962013-11-08 13:59:06 -0500693
Zdenek Behan508dcce2011-12-05 15:39:32 +0100694
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -0700695def ShowConfig(name):
696 """Show the toolchain tuples used by |name|
Mike Frysinger35247af2012-11-16 18:58:06 -0500697
698 Args:
Don Garrettc0c74002015-10-09 12:58:19 -0700699 name: The board name to query.
Mike Frysinger35247af2012-11-16 18:58:06 -0500700 """
Don Garrettc0c74002015-10-09 12:58:19 -0700701 toolchains = toolchain.GetToolchainsForBoard(name)
Mike Frysinger35247af2012-11-16 18:58:06 -0500702 # Make sure we display the default toolchain first.
Mike Frysinger3bba5032016-09-20 14:15:04 -0400703 # Note: Do not use logging here as this is meant to be used by other tools.
Mike Frysinger383367e2014-09-16 15:06:17 -0400704 print(','.join(
David James27ac4ae2012-12-03 23:16:15 -0800705 toolchain.FilterToolchains(toolchains, 'default', True).keys() +
Mike Frysinger383367e2014-09-16 15:06:17 -0400706 toolchain.FilterToolchains(toolchains, 'default', False).keys()))
Mike Frysinger35247af2012-11-16 18:58:06 -0500707
708
Mike Frysinger35247af2012-11-16 18:58:06 -0500709def GeneratePathWrapper(root, wrappath, path):
710 """Generate a shell script to execute another shell script
711
712 Since we can't symlink a wrapped ELF (see GenerateLdsoWrapper) because the
713 argv[0] won't be pointing to the correct path, generate a shell script that
714 just executes another program with its full path.
715
716 Args:
717 root: The root tree to generate scripts inside of
718 wrappath: The full path (inside |root|) to create the wrapper
719 path: The target program which this wrapper will execute
720 """
721 replacements = {
722 'path': path,
723 'relroot': os.path.relpath('/', os.path.dirname(wrappath)),
724 }
725 wrapper = """#!/bin/sh
726base=$(realpath "$0")
727basedir=${base%%/*}
728exec "${basedir}/%(relroot)s%(path)s" "$@"
729""" % replacements
730 root_wrapper = root + wrappath
731 if os.path.islink(root_wrapper):
732 os.unlink(root_wrapper)
733 else:
734 osutils.SafeMakedirs(os.path.dirname(root_wrapper))
735 osutils.WriteFile(root_wrapper, wrapper)
Mike Frysinger60ec1012013-10-21 00:11:10 -0400736 os.chmod(root_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -0500737
738
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -0700739def FixClangXXWrapper(root, path):
740 """Fix wrapper shell scripts and symlinks for invoking clang++
741
742 In a typical installation, clang++ symlinks to clang, which symlinks to the
743 elf executable. The executable distinguishes between clang and clang++ based
744 on argv[0].
745
746 When invoked through the LdsoWrapper, argv[0] always contains the path to the
747 executable elf file, making clang/clang++ invocations indistinguishable.
748
749 This function detects if the elf executable being wrapped is clang-X.Y, and
750 fixes wrappers/symlinks as necessary so that clang++ will work correctly.
751
752 The calling sequence now becomes:
753 -) clang++ invocation turns into clang++-3.9 (which is a copy of clang-3.9,
754 the Ldsowrapper).
755 -) clang++-3.9 uses the Ldso to invoke clang++-3.9.elf, which is a symlink
756 to the original clang-3.9 elf.
757 -) The difference this time is that inside the elf file execution, $0 is
758 set as .../usr/bin/clang++-3.9.elf, which contains 'clang++' in the name.
759
760 Args:
761 root: The root tree to generate scripts / symlinks inside of
762 path: The target elf for which LdsoWrapper was created
763 """
764 if re.match(r'/usr/bin/clang-\d+\.\d+$', path):
765 logging.info('fixing clang++ invocation for %s', path)
766 clangdir = os.path.dirname(root + path)
767 clang = os.path.basename(path)
768 clangxx = clang.replace('clang', 'clang++')
769
770 # Create a symlink clang++-X.Y.elf to point to clang-X.Y.elf
771 os.symlink(clang + '.elf', os.path.join(clangdir, clangxx + '.elf'))
772
773 # Create a hardlink clang++-X.Y pointing to clang-X.Y
774 os.link(os.path.join(clangdir, clang), os.path.join(clangdir, clangxx))
775
776 # Adjust the clang++ symlink to point to clang++-X.Y
777 os.unlink(os.path.join(clangdir, 'clang++'))
778 os.symlink(clangxx, os.path.join(clangdir, 'clang++'))
779
780
Mike Frysinger35247af2012-11-16 18:58:06 -0500781def FileIsCrosSdkElf(elf):
782 """Determine if |elf| is an ELF that we execute in the cros_sdk
783
784 We don't need this to be perfect, just quick. It makes sure the ELF
785 is a 64bit LSB x86_64 ELF. That is the native type of cros_sdk.
786
787 Args:
788 elf: The file to check
Mike Frysinger1a736a82013-12-12 01:50:59 -0500789
Mike Frysinger35247af2012-11-16 18:58:06 -0500790 Returns:
791 True if we think |elf| is a native ELF
792 """
793 with open(elf) as f:
794 data = f.read(20)
795 # Check the magic number, EI_CLASS, EI_DATA, and e_machine.
796 return (data[0:4] == '\x7fELF' and
797 data[4] == '\x02' and
798 data[5] == '\x01' and
799 data[18] == '\x3e')
800
801
802def IsPathPackagable(ptype, path):
803 """Should the specified file be included in a toolchain package?
804
805 We only need to handle files as we'll create dirs as we need them.
806
807 Further, trim files that won't be useful:
808 - non-english translations (.mo) since it'd require env vars
809 - debug files since these are for the host compiler itself
810 - info/man pages as they're big, and docs are online, and the
811 native docs should work fine for the most part (`man gcc`)
812
813 Args:
814 ptype: A string describing the path type (i.e. 'file' or 'dir' or 'sym')
815 path: The full path to inspect
Mike Frysinger1a736a82013-12-12 01:50:59 -0500816
Mike Frysinger35247af2012-11-16 18:58:06 -0500817 Returns:
818 True if we want to include this path in the package
819 """
820 return not (ptype in ('dir',) or
821 path.startswith('/usr/lib/debug/') or
822 os.path.splitext(path)[1] == '.mo' or
823 ('/man/' in path or '/info/' in path))
824
825
826def ReadlinkRoot(path, root):
827 """Like os.readlink(), but relative to a |root|
828
829 Args:
830 path: The symlink to read
831 root: The path to use for resolving absolute symlinks
Mike Frysinger1a736a82013-12-12 01:50:59 -0500832
Mike Frysinger35247af2012-11-16 18:58:06 -0500833 Returns:
834 A fully resolved symlink path
835 """
836 while os.path.islink(root + path):
837 path = os.path.join(os.path.dirname(path), os.readlink(root + path))
838 return path
839
840
841def _GetFilesForTarget(target, root='/'):
842 """Locate all the files to package for |target|
843
844 This does not cover ELF dependencies.
845
846 Args:
847 target: The toolchain target name
848 root: The root path to pull all packages from
Mike Frysinger1a736a82013-12-12 01:50:59 -0500849
Mike Frysinger35247af2012-11-16 18:58:06 -0500850 Returns:
851 A tuple of a set of all packable paths, and a set of all paths which
852 are also native ELFs
853 """
854 paths = set()
855 elfs = set()
856
857 # Find all the files owned by the packages for this target.
858 for pkg in GetTargetPackages(target):
Mike Frysinger35247af2012-11-16 18:58:06 -0500859
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700860 # Skip Go compiler from redistributable packages.
861 # The "go" executable has GOROOT=/usr/lib/go/${CTARGET} hardcoded
862 # into it. Due to this, the toolchain cannot be unpacked anywhere
863 # else and be readily useful. To enable packaging Go, we need to:
864 # -) Tweak the wrappers/environment to override GOROOT
865 # automatically based on the unpack location.
866 # -) Make sure the ELF dependency checking and wrapping logic
867 # below skips the Go toolchain executables and libraries.
868 # -) Make sure the packaging process maintains the relative
869 # timestamps of precompiled standard library packages.
870 # (see dev-lang/go ebuild for details).
871 if pkg == 'ex_go':
872 continue
873
Mike Frysinger35247af2012-11-16 18:58:06 -0500874 atom = GetPortagePackage(target, pkg)
875 cat, pn = atom.split('/')
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700876 ver = GetInstalledPackageVersions(atom, root=root)[0]
Ralph Nathan03047282015-03-23 11:09:32 -0700877 logging.info('packaging %s-%s', atom, ver)
Mike Frysinger35247af2012-11-16 18:58:06 -0500878
879 # pylint: disable=E1101
880 dblink = portage.dblink(cat, pn + '-' + ver, myroot=root,
881 settings=portage.settings)
882 contents = dblink.getcontents()
883 for obj in contents:
884 ptype = contents[obj][0]
885 if not IsPathPackagable(ptype, obj):
886 continue
887
888 if ptype == 'obj':
889 # For native ELFs, we need to pull in their dependencies too.
890 if FileIsCrosSdkElf(obj):
891 elfs.add(obj)
892 paths.add(obj)
893
894 return paths, elfs
895
896
897def _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500898 path_rewrite_func=lambda x: x, root='/'):
Mike Frysinger35247af2012-11-16 18:58:06 -0500899 """Link in all packable files and their runtime dependencies
900
901 This also wraps up executable ELFs with helper scripts.
902
903 Args:
904 output_dir: The output directory to store files
905 paths: All the files to include
906 elfs: All the files which are ELFs (a subset of |paths|)
907 ldpaths: A dict of static ldpath information
908 path_rewrite_func: User callback to rewrite paths in output_dir
909 root: The root path to pull all packages/files from
910 """
911 # Link in all the files.
Mike Frysinger221bd822017-09-29 02:51:47 -0400912 sym_paths = {}
Mike Frysinger35247af2012-11-16 18:58:06 -0500913 for path in paths:
914 new_path = path_rewrite_func(path)
915 dst = output_dir + new_path
916 osutils.SafeMakedirs(os.path.dirname(dst))
917
918 # Is this a symlink which we have to rewrite or wrap?
919 # Delay wrap check until after we have created all paths.
920 src = root + path
921 if os.path.islink(src):
922 tgt = os.readlink(src)
923 if os.path.sep in tgt:
Mike Frysinger221bd822017-09-29 02:51:47 -0400924 sym_paths[lddtree.normpath(ReadlinkRoot(src, root))] = new_path
Mike Frysinger35247af2012-11-16 18:58:06 -0500925
926 # Rewrite absolute links to relative and then generate the symlink
927 # ourselves. All other symlinks can be hardlinked below.
928 if tgt[0] == '/':
929 tgt = os.path.relpath(tgt, os.path.dirname(new_path))
930 os.symlink(tgt, dst)
931 continue
932
933 os.link(src, dst)
934
Mike Frysinger35247af2012-11-16 18:58:06 -0500935 # Locate all the dependencies for all the ELFs. Stick them all in the
936 # top level "lib" dir to make the wrapper simpler. This exact path does
937 # not matter since we execute ldso directly, and we tell the ldso the
938 # exact path to search for its libraries.
939 libdir = os.path.join(output_dir, 'lib')
940 osutils.SafeMakedirs(libdir)
941 donelibs = set()
Mike Frysinger4331fc62017-09-28 14:03:25 -0400942 glibc_re = re.compile(r'/lib(c|pthread)-[0-9.]+\.so$')
Mike Frysinger35247af2012-11-16 18:58:06 -0500943 for elf in elfs:
Mike Frysingerea7688e2014-07-31 22:40:33 -0400944 e = lddtree.ParseELF(elf, root=root, ldpaths=ldpaths)
Mike Frysinger35247af2012-11-16 18:58:06 -0500945 interp = e['interp']
Yunlian Jiang196e8f42017-09-20 12:29:47 -0700946 # Do not create wrapper for libc. crbug.com/766827
947 if interp and not glibc_re.search(elf):
Mike Frysinger35247af2012-11-16 18:58:06 -0500948 # Generate a wrapper if it is executable.
Mike Frysingerc2ec0902013-03-26 01:28:45 -0400949 interp = os.path.join('/lib', os.path.basename(interp))
950 lddtree.GenerateLdsoWrapper(output_dir, path_rewrite_func(elf), interp,
951 libpaths=e['rpath'] + e['runpath'])
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -0700952 FixClangXXWrapper(output_dir, path_rewrite_func(elf))
Mike Frysinger35247af2012-11-16 18:58:06 -0500953
Mike Frysinger221bd822017-09-29 02:51:47 -0400954 # Wrap any symlinks to the wrapper.
955 if elf in sym_paths:
956 link = sym_paths[elf]
957 GeneratePathWrapper(output_dir, link, elf)
958
Mike Frysinger35247af2012-11-16 18:58:06 -0500959 for lib, lib_data in e['libs'].iteritems():
960 if lib in donelibs:
961 continue
962
963 src = path = lib_data['path']
964 if path is None:
Ralph Nathan446aee92015-03-23 14:44:56 -0700965 logging.warning('%s: could not locate %s', elf, lib)
Mike Frysinger35247af2012-11-16 18:58:06 -0500966 continue
967 donelibs.add(lib)
968
969 # Needed libs are the SONAME, but that is usually a symlink, not a
970 # real file. So link in the target rather than the symlink itself.
971 # We have to walk all the possible symlinks (SONAME could point to a
972 # symlink which points to a symlink), and we have to handle absolute
973 # ourselves (since we have a "root" argument).
974 dst = os.path.join(libdir, os.path.basename(path))
975 src = ReadlinkRoot(src, root)
976
977 os.link(root + src, dst)
978
979
980def _EnvdGetVar(envd, var):
981 """Given a Gentoo env.d file, extract a var from it
982
983 Args:
984 envd: The env.d file to load (may be a glob path)
985 var: The var to extract
Mike Frysinger1a736a82013-12-12 01:50:59 -0500986
Mike Frysinger35247af2012-11-16 18:58:06 -0500987 Returns:
988 The value of |var|
989 """
990 envds = glob.glob(envd)
991 assert len(envds) == 1, '%s: should have exactly 1 env.d file' % envd
992 envd = envds[0]
993 return cros_build_lib.LoadKeyValueFile(envd)[var]
994
995
996def _ProcessBinutilsConfig(target, output_dir):
997 """Do what binutils-config would have done"""
998 binpath = os.path.join('/bin', target + '-')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -0500999
1000 # Locate the bin dir holding the gold linker.
1001 binutils_bin_path = os.path.join(output_dir, 'usr', toolchain.GetHostTuple(),
1002 target, 'binutils-bin')
1003 globpath = os.path.join(binutils_bin_path, '*-gold')
Mike Frysinger35247af2012-11-16 18:58:06 -05001004 srcpath = glob.glob(globpath)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001005 if not srcpath:
1006 # Maybe this target doesn't support gold.
1007 globpath = os.path.join(binutils_bin_path, '*')
1008 srcpath = glob.glob(globpath)
1009 assert len(srcpath) == 1, ('%s: matched more than one path (but not *-gold)'
1010 % globpath)
1011 srcpath = srcpath[0]
1012 ld_path = os.path.join(srcpath, 'ld')
1013 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1014 ld_path = os.path.join(srcpath, 'ld.bfd')
1015 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1016 ld_path = os.path.join(srcpath, 'ld.gold')
1017 assert not os.path.exists(ld_path), ('%s: exists, but gold dir does not!'
1018 % ld_path)
1019
1020 # Nope, no gold support to be found.
1021 gold_supported = False
Ralph Nathan446aee92015-03-23 14:44:56 -07001022 logging.warning('%s: binutils lacks support for the gold linker', target)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001023 else:
1024 assert len(srcpath) == 1, '%s: did not match exactly 1 path' % globpath
Mike Frysinger78b7a812014-11-26 19:45:23 -05001025 srcpath = srcpath[0]
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001026
Rahul Chaudhry4891b4d2017-03-08 10:31:27 -08001027 # Package the binutils-bin directory without the '-gold' suffix
1028 # if gold is not enabled as the default linker for this target.
1029 gold_supported = CONFIG_TARGET_SUFFIXES['binutils'].get(target) == '-gold'
1030 if not gold_supported:
1031 srcpath = srcpath[:-len('-gold')]
1032 ld_path = os.path.join(srcpath, 'ld')
1033 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1034
Mike Frysinger78b7a812014-11-26 19:45:23 -05001035 srcpath = srcpath[len(output_dir):]
Mike Frysinger35247af2012-11-16 18:58:06 -05001036 gccpath = os.path.join('/usr', 'libexec', 'gcc')
1037 for prog in os.listdir(output_dir + srcpath):
1038 # Skip binaries already wrapped.
1039 if not prog.endswith('.real'):
1040 GeneratePathWrapper(output_dir, binpath + prog,
1041 os.path.join(srcpath, prog))
1042 GeneratePathWrapper(output_dir, os.path.join(gccpath, prog),
1043 os.path.join(srcpath, prog))
1044
David James27ac4ae2012-12-03 23:16:15 -08001045 libpath = os.path.join('/usr', toolchain.GetHostTuple(), target, 'lib')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001046 envd = os.path.join(output_dir, 'etc', 'env.d', 'binutils', '*')
1047 if gold_supported:
1048 envd += '-gold'
Rahul Chaudhry4891b4d2017-03-08 10:31:27 -08001049 else:
1050 # If gold is not enabled as the default linker and 2 env.d
1051 # files exist, pick the one without the '-gold' suffix.
1052 envds = sorted(glob.glob(envd))
1053 if len(envds) == 2 and envds[1] == envds[0] + '-gold':
1054 envd = envds[0]
Mike Frysinger35247af2012-11-16 18:58:06 -05001055 srcpath = _EnvdGetVar(envd, 'LIBPATH')
1056 os.symlink(os.path.relpath(srcpath, os.path.dirname(libpath)),
1057 output_dir + libpath)
1058
1059
1060def _ProcessGccConfig(target, output_dir):
1061 """Do what gcc-config would have done"""
1062 binpath = '/bin'
1063 envd = os.path.join(output_dir, 'etc', 'env.d', 'gcc', '*')
1064 srcpath = _EnvdGetVar(envd, 'GCC_PATH')
1065 for prog in os.listdir(output_dir + srcpath):
1066 # Skip binaries already wrapped.
1067 if (not prog.endswith('.real') and
1068 not prog.endswith('.elf') and
1069 prog.startswith(target)):
1070 GeneratePathWrapper(output_dir, os.path.join(binpath, prog),
1071 os.path.join(srcpath, prog))
1072 return srcpath
1073
1074
Frank Henigman179ec7c2015-02-06 03:01:09 -05001075def _ProcessSysrootWrappers(_target, output_dir, srcpath):
1076 """Remove chroot-specific things from our sysroot wrappers"""
Mike Frysinger35247af2012-11-16 18:58:06 -05001077 # Disable ccache since we know it won't work outside of chroot.
Frank Henigman179ec7c2015-02-06 03:01:09 -05001078 for sysroot_wrapper in glob.glob(os.path.join(
1079 output_dir + srcpath, 'sysroot_wrapper*')):
1080 contents = osutils.ReadFile(sysroot_wrapper).splitlines()
1081 for num in xrange(len(contents)):
1082 if '@CCACHE_DEFAULT@' in contents[num]:
Caroline Ticece9e9232017-06-02 09:38:42 -07001083 assert 'True' in contents[num]
1084 contents[num] = contents[num].replace('True', 'False')
Frank Henigman179ec7c2015-02-06 03:01:09 -05001085 break
1086 # Can't update the wrapper in place since it's a hardlink to a file in /.
1087 os.unlink(sysroot_wrapper)
1088 osutils.WriteFile(sysroot_wrapper, '\n'.join(contents))
1089 os.chmod(sysroot_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -05001090
1091
Yunlian Jiang5ad6b512017-09-20 09:27:45 -07001092def _CreateMainLibDir(target, output_dir):
1093 """Create some lib dirs so that compiler can get the right Gcc paths"""
1094 osutils.SafeMakedirs(os.path.join(output_dir, 'usr', target, 'lib'))
1095 osutils.SafeMakedirs(os.path.join(output_dir, 'usr', target, 'usr/lib'))
1096
1097
Mike Frysinger35247af2012-11-16 18:58:06 -05001098def _ProcessDistroCleanups(target, output_dir):
1099 """Clean up the tree and remove all distro-specific requirements
1100
1101 Args:
1102 target: The toolchain target name
1103 output_dir: The output directory to clean up
1104 """
1105 _ProcessBinutilsConfig(target, output_dir)
1106 gcc_path = _ProcessGccConfig(target, output_dir)
Frank Henigman179ec7c2015-02-06 03:01:09 -05001107 _ProcessSysrootWrappers(target, output_dir, gcc_path)
Yunlian Jiang5ad6b512017-09-20 09:27:45 -07001108 _CreateMainLibDir(target, output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001109
1110 osutils.RmDir(os.path.join(output_dir, 'etc'))
1111
1112
1113def CreatePackagableRoot(target, output_dir, ldpaths, root='/'):
1114 """Setup a tree from the packages for the specified target
1115
1116 This populates a path with all the files from toolchain packages so that
1117 a tarball can easily be generated from the result.
1118
1119 Args:
1120 target: The target to create a packagable root from
1121 output_dir: The output directory to place all the files
1122 ldpaths: A dict of static ldpath information
1123 root: The root path to pull all packages/files from
1124 """
1125 # Find all the files owned by the packages for this target.
1126 paths, elfs = _GetFilesForTarget(target, root=root)
1127
1128 # Link in all the package's files, any ELF dependencies, and wrap any
1129 # executable ELFs with helper scripts.
1130 def MoveUsrBinToBin(path):
Han Shen699ea192016-03-02 10:42:47 -08001131 """Move /usr/bin to /bin so people can just use that toplevel dir
1132
1133 Note we do not apply this to clang - there is correlation between clang's
1134 search path for libraries / inclusion and its installation path.
1135 """
1136 if path.startswith('/usr/bin/') and path.find('clang') == -1:
1137 return path[4:]
1138 return path
Mike Frysinger35247af2012-11-16 18:58:06 -05001139 _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
1140 path_rewrite_func=MoveUsrBinToBin, root=root)
1141
1142 # The packages, when part of the normal distro, have helper scripts
1143 # that setup paths and such. Since we are making this standalone, we
1144 # need to preprocess all that ourselves.
1145 _ProcessDistroCleanups(target, output_dir)
1146
1147
1148def CreatePackages(targets_wanted, output_dir, root='/'):
1149 """Create redistributable cross-compiler packages for the specified targets
1150
1151 This creates toolchain packages that should be usable in conjunction with
1152 a downloaded sysroot (created elsewhere).
1153
1154 Tarballs (one per target) will be created in $PWD.
1155
1156 Args:
Don Garrett25f309a2014-03-19 14:02:12 -07001157 targets_wanted: The targets to package up.
1158 output_dir: The directory to put the packages in.
1159 root: The root path to pull all packages/files from.
Mike Frysinger35247af2012-11-16 18:58:06 -05001160 """
Ralph Nathan03047282015-03-23 11:09:32 -07001161 logging.info('Writing tarballs to %s', output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001162 osutils.SafeMakedirs(output_dir)
1163 ldpaths = lddtree.LoadLdpaths(root)
1164 targets = ExpandTargets(targets_wanted)
1165
Mike Frysinger221bd822017-09-29 02:51:47 -04001166 with osutils.TempDir(prefix='create-packages') as tempdir:
1167 logging.debug('Using tempdir: %s', tempdir)
1168
Mike Frysinger35247af2012-11-16 18:58:06 -05001169 # We have to split the root generation from the compression stages. This is
1170 # because we hardlink in all the files (to avoid overhead of reading/writing
1171 # the copies multiple times). But tar gets angry if a file's hardlink count
1172 # changes from when it starts reading a file to when it finishes.
1173 with parallel.BackgroundTaskRunner(CreatePackagableRoot) as queue:
1174 for target in targets:
1175 output_target_dir = os.path.join(tempdir, target)
1176 queue.put([target, output_target_dir, ldpaths, root])
1177
1178 # Build the tarball.
1179 with parallel.BackgroundTaskRunner(cros_build_lib.CreateTarball) as queue:
1180 for target in targets:
1181 tar_file = os.path.join(output_dir, target + '.tar.xz')
1182 queue.put([tar_file, os.path.join(tempdir, target)])
1183
1184
Mike Frysinger07534cf2017-09-12 17:40:21 -04001185def GetParser():
1186 """Return a command line parser."""
Mike Frysinger0c808452014-11-06 17:30:23 -05001187 parser = commandline.ArgumentParser(description=__doc__)
1188 parser.add_argument('-u', '--nousepkg',
1189 action='store_false', dest='usepkg', default=True,
1190 help='Use prebuilt packages if possible')
1191 parser.add_argument('-d', '--deleteold',
1192 action='store_true', dest='deleteold', default=False,
1193 help='Unmerge deprecated packages')
1194 parser.add_argument('-t', '--targets',
1195 dest='targets', default='sdk',
Gilad Arnold8195b532015-04-07 10:56:30 +03001196 help="Comma separated list of tuples. Special keywords "
Don Garrettc0c74002015-10-09 12:58:19 -07001197 "'host', 'sdk', 'boards', and 'all' are "
Gilad Arnold8195b532015-04-07 10:56:30 +03001198 "allowed. Defaults to 'sdk'.")
1199 parser.add_argument('--include-boards', default='', metavar='BOARDS',
1200 help='Comma separated list of boards whose toolchains we '
1201 'will always include. Default: none')
Mike Frysinger0c808452014-11-06 17:30:23 -05001202 parser.add_argument('--hostonly',
1203 dest='hostonly', default=False, action='store_true',
1204 help='Only setup the host toolchain. '
1205 'Useful for bootstrapping chroot')
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001206 parser.add_argument('--show-board-cfg', '--show-cfg',
1207 dest='cfg_name', default=None,
Don Garrettc0c74002015-10-09 12:58:19 -07001208 help='Board to list toolchains tuples for')
Mike Frysinger91f52882017-09-13 00:16:58 -04001209 parser.add_argument('--show-packages', default=None,
1210 help='List all packages the specified target uses')
Mike Frysinger0c808452014-11-06 17:30:23 -05001211 parser.add_argument('--create-packages',
1212 action='store_true', default=False,
1213 help='Build redistributable packages')
1214 parser.add_argument('--output-dir', default=os.getcwd(), type='path',
1215 help='Output directory')
1216 parser.add_argument('--reconfig', default=False, action='store_true',
1217 help='Reload crossdev config and reselect toolchains')
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001218 parser.add_argument('--sysroot', type='path',
1219 help='The sysroot in which to install the toolchains')
Mike Frysinger07534cf2017-09-12 17:40:21 -04001220 return parser
Zdenek Behan508dcce2011-12-05 15:39:32 +01001221
Mike Frysinger07534cf2017-09-12 17:40:21 -04001222
1223def main(argv):
1224 parser = GetParser()
Mike Frysinger0c808452014-11-06 17:30:23 -05001225 options = parser.parse_args(argv)
1226 options.Freeze()
Zdenek Behan508dcce2011-12-05 15:39:32 +01001227
Mike Frysinger35247af2012-11-16 18:58:06 -05001228 # Figure out what we're supposed to do and reject conflicting options.
Mike Frysinger91f52882017-09-13 00:16:58 -04001229 conflicting_options = (
1230 options.cfg_name,
1231 options.show_packages,
1232 options.create_packages,
1233 )
1234 if sum(bool(x) for x in conflicting_options) > 1:
1235 parser.error('conflicting options: create-packages & show-packages & '
1236 'show-board-cfg')
Mike Frysinger984d0622012-06-01 16:08:44 -04001237
Gilad Arnold8195b532015-04-07 10:56:30 +03001238 targets_wanted = set(options.targets.split(','))
1239 boards_wanted = (set(options.include_boards.split(','))
1240 if options.include_boards else set())
Mike Frysinger35247af2012-11-16 18:58:06 -05001241
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001242 if options.cfg_name:
1243 ShowConfig(options.cfg_name)
Mike Frysinger91f52882017-09-13 00:16:58 -04001244 elif options.show_packages is not None:
1245 cros_build_lib.AssertInsideChroot()
1246 target = options.show_packages
1247 Crossdev.Load(False)
1248 for package in GetTargetPackages(target):
1249 print(GetPortagePackage(target, package))
Mike Frysinger35247af2012-11-16 18:58:06 -05001250 elif options.create_packages:
1251 cros_build_lib.AssertInsideChroot()
1252 Crossdev.Load(False)
Gilad Arnold8195b532015-04-07 10:56:30 +03001253 CreatePackages(targets_wanted, options.output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001254 else:
1255 cros_build_lib.AssertInsideChroot()
1256 # This has to be always run as root.
1257 if os.geteuid() != 0:
1258 cros_build_lib.Die('this script must be run as root')
1259
1260 Crossdev.Load(options.reconfig)
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001261 root = options.sysroot or '/'
Mike Frysinger35247af2012-11-16 18:58:06 -05001262 UpdateToolchains(options.usepkg, options.deleteold, options.hostonly,
Gilad Arnold8195b532015-04-07 10:56:30 +03001263 options.reconfig, targets_wanted, boards_wanted,
Don Garrettc0c74002015-10-09 12:58:19 -07001264 root=root)
Mike Frysinger35247af2012-11-16 18:58:06 -05001265 Crossdev.Save()
1266
1267 return 0