blob: b08cf256bbc03e570b35d7ecc1d71c02d568dd8e [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]'
38PACKAGE_NONE = '[none]'
Zdenek Behan4eb6fd22012-03-12 17:00:56 +010039
40CHROMIUMOS_OVERLAY = '/usr/local/portage/chromiumos'
Christopher Wileyb22c0712015-06-02 10:37:03 -070041ECLASS_OVERLAY = '/usr/local/portage/eclass-overlay'
Zdenek Behan4eb6fd22012-03-12 17:00:56 +010042STABLE_OVERLAY = '/usr/local/portage/stable'
43CROSSDEV_OVERLAY = '/usr/local/portage/crossdev'
Zdenek Behan508dcce2011-12-05 15:39:32 +010044
45
46# TODO: The versions are stored here very much like in setup_board.
47# The goal for future is to differentiate these using a config file.
48# This is done essentially by messing with GetDesiredPackageVersions()
49DEFAULT_VERSION = PACKAGE_STABLE
50DEFAULT_TARGET_VERSION_MAP = {
Zdenek Behan508dcce2011-12-05 15:39:32 +010051}
52TARGET_VERSION_MAP = {
Zdenek Behan508dcce2011-12-05 15:39:32 +010053}
Rahul Chaudhry4b803052015-05-13 15:25:56 -070054
Mike Frysinger66bfde52017-09-12 16:42:57 -040055# The exact list of host toolchain packages we care about. These are the
56# packages that bots/devs install only from binpkgs and rely on the SDK bot
57# (chromiumos-sdk) to validate+uprev.
58#
59# These also need to be manually kept in sync with update_chroot.
60#
61# We don't use crossdev to manage the host toolchain for us, especially since
62# we diverge significantly now (with llvm/clang/etc...), and we don't need or
63# want crossdev managing /etc/portage config files for the sdk
64HOST_PACKAGES = (
65 'dev-lang/go',
66 'sys-devel/binutils',
67 'sys-devel/clang',
68 'sys-devel/gcc',
69 'sys-devel/llvm',
70 'sys-kernel/linux-headers',
71 'sys-libs/glibc',
72 'sys-libs/libcxx',
73 'sys-libs/libcxxabi',
74)
75
Rahul Chaudhry4b803052015-05-13 15:25:56 -070076# Enable the Go compiler for these targets.
77TARGET_GO_ENABLED = (
78 'x86_64-cros-linux-gnu',
Rahul Chaudhry4b803052015-05-13 15:25:56 -070079 'armv7a-cros-linux-gnueabi',
80)
81CROSSDEV_GO_ARGS = ['--ex-pkg', 'dev-lang/go']
82
Manoj Gupta1b5642e2017-03-08 16:44:12 -080083# Enable llvm's compiler-rt for these targets.
84TARGET_COMPILER_RT_ENABLED = (
85 'armv7a-cros-linux-gnueabi',
Manoj Gupta946abb42017-04-12 14:27:19 -070086 'aarch64-cros-linux-gnu',
Manoj Gupta1b5642e2017-03-08 16:44:12 -080087)
88CROSSDEV_COMPILER_RT_ARGS = ['--ex-pkg', 'sys-libs/compiler-rt']
89
Manoj Gupta946abb42017-04-12 14:27:19 -070090TARGET_LLVM_PKGS_ENABLED = (
91 'armv7a-cros-linux-gnueabi',
92 'aarch64-cros-linux-gnu',
93 'x86_64-cros-linux-gnu',
94)
95
96LLVM_PKGS_TABLE = {
Yunlian Jiangbb2a3d32017-04-26 14:44:09 -070097 'ex_libcxxabi' : ['--ex-pkg', 'sys-libs/libcxxabi'],
98 'ex_libcxx' : ['--ex-pkg', 'sys-libs/libcxx'],
Manoj Gupta946abb42017-04-12 14:27:19 -070099}
100
Zdenek Behan508dcce2011-12-05 15:39:32 +0100101# Overrides for {gcc,binutils}-config, pick a package with particular suffix.
102CONFIG_TARGET_SUFFIXES = {
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500103 'binutils' : {
Mike Frysinger8a83c622015-05-28 00:35:05 -0400104 'armv6j-cros-linux-gnueabi': '-gold',
Han Shen43b84422015-02-19 11:38:13 -0800105 'armv7a-cros-linux-gnueabi': '-gold',
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500106 'i686-pc-linux-gnu' : '-gold',
107 'x86_64-cros-linux-gnu' : '-gold',
108 },
Zdenek Behan508dcce2011-12-05 15:39:32 +0100109}
Zdenek Behan508dcce2011-12-05 15:39:32 +0100110# Global per-run cache that will be filled ondemand in by GetPackageMap()
111# function as needed.
112target_version_map = {
113}
114
115
David James66a09c42012-11-05 13:31:38 -0800116class Crossdev(object):
117 """Class for interacting with crossdev and caching its output."""
118
119 _CACHE_FILE = os.path.join(CROSSDEV_OVERLAY, '.configured.json')
120 _CACHE = {}
Han Shene23782f2016-02-18 12:20:00 -0800121 # Packages that needs separate handling, in addition to what we have from
122 # crossdev.
123 MANUAL_PKGS = {
Manoj Guptaf0a602e2017-08-02 10:25:45 -0700124 'clang': 'sys-devel',
Han Shene23782f2016-02-18 12:20:00 -0800125 'llvm': 'sys-devel',
Manoj Gupta20cfc6c2017-07-19 15:49:55 -0700126 'libcxxabi': 'sys-libs',
127 'libcxx': 'sys-libs',
Han Shene23782f2016-02-18 12:20:00 -0800128 }
David James66a09c42012-11-05 13:31:38 -0800129
130 @classmethod
131 def Load(cls, reconfig):
Mike Frysinger3ed47722017-08-08 14:59:08 -0400132 """Load crossdev cache from disk.
133
134 We invalidate the cache when crossdev updates or this script changes.
135 """
David James90239b92012-11-05 15:31:34 -0800136 crossdev_version = GetStablePackageVersion('sys-devel/crossdev', True)
Mike Frysinger3ed47722017-08-08 14:59:08 -0400137 # If we run the compiled/cached .pyc file, we'll read/hash that when we
138 # really always want to track the source .py file.
139 script = os.path.abspath(__file__)
140 if script.endswith('.pyc'):
141 script = script[:-1]
142 setup_toolchains_hash = hashlib.md5(osutils.ReadFile(script)).hexdigest()
143
144 cls._CACHE = {
145 'crossdev_version': crossdev_version,
146 'setup_toolchains_hash': setup_toolchains_hash,
147 }
148
149 logging.debug('cache: checking file: %s', cls._CACHE_FILE)
150 if reconfig:
151 logging.debug('cache: forcing regen due to reconfig')
152 return
153
154 try:
155 file_data = osutils.ReadFile(cls._CACHE_FILE)
156 except IOError as e:
157 if e.errno != errno.ENOENT:
158 logging.warning('cache: reading failed: %s', e)
159 osutils.SafeUnlink(cls._CACHE_FILE)
160 return
161
162 try:
163 data = json.loads(file_data)
164 except ValueError as e:
165 logging.warning('cache: ignoring invalid content: %s', e)
166 return
167
168 if crossdev_version != data.get('crossdev_version'):
169 logging.debug('cache: rebuilding after crossdev upgrade')
170 elif setup_toolchains_hash != data.get('setup_toolchains_hash'):
171 logging.debug('cache: rebuilding after cros_setup_toolchains change')
172 else:
173 logging.debug('cache: content is up-to-date!')
174 cls._CACHE = data
David James66a09c42012-11-05 13:31:38 -0800175
176 @classmethod
177 def Save(cls):
178 """Store crossdev cache on disk."""
179 # Save the cache from the successful run.
180 with open(cls._CACHE_FILE, 'w') as f:
181 json.dump(cls._CACHE, f)
182
183 @classmethod
184 def GetConfig(cls, target):
185 """Returns a map of crossdev provided variables about a tuple."""
186 CACHE_ATTR = '_target_tuple_map'
187
188 val = cls._CACHE.setdefault(CACHE_ATTR, {})
189 if not target in val:
David James66a09c42012-11-05 13:31:38 -0800190 if target == 'host':
Mike Frysinger66bfde52017-09-12 16:42:57 -0400191 conf = {
192 'crosspkgs': [],
193 'target': toolchain.GetHostTuple(),
194 }
195 manual_pkgs = dict((pkg, cat) for cat, pkg in
196 [x.split('/') for x in HOST_PACKAGES])
197 else:
198 # Build the crossdev command.
199 cmd = ['crossdev', '--show-target-cfg', '--ex-gdb']
200 if target in TARGET_COMPILER_RT_ENABLED:
201 cmd.extend(CROSSDEV_COMPILER_RT_ARGS)
202 if target in TARGET_GO_ENABLED:
203 cmd.extend(CROSSDEV_GO_ARGS)
204 if target in TARGET_LLVM_PKGS_ENABLED:
205 for pkg in LLVM_PKGS_TABLE:
206 cmd.extend(LLVM_PKGS_TABLE[pkg])
207 cmd.extend(['-t', target])
208 # Catch output of crossdev.
209 out = cros_build_lib.RunCommand(
210 cmd, print_cmd=False, redirect_stdout=True).output.splitlines()
211 # List of tuples split at the first '=', converted into dict.
212 conf = dict((k, cros_build_lib.ShellUnquote(v))
213 for k, v in (x.split('=', 1) for x in out))
214 conf['crosspkgs'] = conf['crosspkgs'].split()
Han Shene23782f2016-02-18 12:20:00 -0800215
Mike Frysinger66bfde52017-09-12 16:42:57 -0400216 manual_pkgs = cls.MANUAL_PKGS
217
218 for pkg, cat in manual_pkgs.items():
Mike Frysinger3bba5032016-09-20 14:15:04 -0400219 conf[pkg + '_pn'] = pkg
220 conf[pkg + '_category'] = cat
221 if pkg not in conf['crosspkgs']:
222 conf['crosspkgs'].append(pkg)
Han Shene23782f2016-02-18 12:20:00 -0800223
224 val[target] = conf
225
David James66a09c42012-11-05 13:31:38 -0800226 return val[target]
227
228 @classmethod
229 def UpdateTargets(cls, targets, usepkg, config_only=False):
230 """Calls crossdev to initialize a cross target.
231
232 Args:
Don Garrett25f309a2014-03-19 14:02:12 -0700233 targets: The list of targets to initialize using crossdev.
234 usepkg: Copies the commandline opts.
235 config_only: Just update.
David James66a09c42012-11-05 13:31:38 -0800236 """
237 configured_targets = cls._CACHE.setdefault('configured_targets', [])
238
239 cmdbase = ['crossdev', '--show-fail-log']
240 cmdbase.extend(['--env', 'FEATURES=splitdebug'])
241 # Pick stable by default, and override as necessary.
242 cmdbase.extend(['-P', '--oneshot'])
243 if usepkg:
244 cmdbase.extend(['-P', '--getbinpkg',
245 '-P', '--usepkgonly',
246 '--without-headers'])
247
Christopher Wileyb22c0712015-06-02 10:37:03 -0700248 overlays = ' '.join((CHROMIUMOS_OVERLAY, ECLASS_OVERLAY, STABLE_OVERLAY))
David James66a09c42012-11-05 13:31:38 -0800249 cmdbase.extend(['--overlays', overlays])
250 cmdbase.extend(['--ov-output', CROSSDEV_OVERLAY])
251
252 for target in targets:
253 if config_only and target in configured_targets:
254 continue
255
256 cmd = cmdbase + ['-t', target]
257
258 for pkg in GetTargetPackages(target):
259 if pkg == 'gdb':
260 # Gdb does not have selectable versions.
261 cmd.append('--ex-gdb')
Manoj Guptab8181562017-05-21 10:18:59 -0700262 elif pkg == 'ex_compiler-rt':
263 cmd.extend(CROSSDEV_COMPILER_RT_ARGS)
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700264 elif pkg == 'ex_go':
265 # Go does not have selectable versions.
266 cmd.extend(CROSSDEV_GO_ARGS)
Manoj Gupta946abb42017-04-12 14:27:19 -0700267 elif pkg in LLVM_PKGS_TABLE:
268 cmd.extend(LLVM_PKGS_TABLE[pkg])
Han Shene23782f2016-02-18 12:20:00 -0800269 elif pkg in cls.MANUAL_PKGS:
270 pass
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700271 else:
272 # The first of the desired versions is the "primary" one.
273 version = GetDesiredPackageVersions(target, pkg)[0]
274 cmd.extend(['--%s' % pkg, version])
David James66a09c42012-11-05 13:31:38 -0800275
276 cmd.extend(targets[target]['crossdev'].split())
277 if config_only:
278 # In this case we want to just quietly reinit
279 cmd.append('--init-target')
280 cros_build_lib.RunCommand(cmd, print_cmd=False, redirect_stdout=True)
281 else:
282 cros_build_lib.RunCommand(cmd)
283
284 configured_targets.append(target)
285
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100286
Zdenek Behan508dcce2011-12-05 15:39:32 +0100287def GetPackageMap(target):
288 """Compiles a package map for the given target from the constants.
289
290 Uses a cache in target_version_map, that is dynamically filled in as needed,
291 since here everything is static data and the structuring is for ease of
292 configurability only.
293
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500294 Args:
295 target: The target for which to return a version map
Zdenek Behan508dcce2011-12-05 15:39:32 +0100296
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500297 Returns:
298 A map between packages and desired versions in internal format
299 (using the PACKAGE_* constants)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100300 """
301 if target in target_version_map:
302 return target_version_map[target]
303
304 # Start from copy of the global defaults.
305 result = copy.copy(DEFAULT_TARGET_VERSION_MAP)
306
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100307 for pkg in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100308 # prefer any specific overrides
309 if pkg in TARGET_VERSION_MAP.get(target, {}):
310 result[pkg] = TARGET_VERSION_MAP[target][pkg]
311 else:
312 # finally, if not already set, set a sane default
313 result.setdefault(pkg, DEFAULT_VERSION)
314 target_version_map[target] = result
315 return result
316
317
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100318def GetTargetPackages(target):
319 """Returns a list of packages for a given target."""
David James66a09c42012-11-05 13:31:38 -0800320 conf = Crossdev.GetConfig(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100321 # Undesired packages are denoted by empty ${pkg}_pn variable.
Han Shene23782f2016-02-18 12:20:00 -0800322 return [x for x in conf['crosspkgs'] if conf.get(x+'_pn')]
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100323
324
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100325# Portage helper functions:
326def GetPortagePackage(target, package):
327 """Returns a package name for the given target."""
David James66a09c42012-11-05 13:31:38 -0800328 conf = Crossdev.GetConfig(target)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100329 # Portage category:
Han Shene23782f2016-02-18 12:20:00 -0800330 if target == 'host' or package in Crossdev.MANUAL_PKGS:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100331 category = conf[package + '_category']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100332 else:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100333 category = conf['category']
334 # Portage package:
335 pn = conf[package + '_pn']
336 # Final package name:
Mike Frysinger422faf42014-11-12 23:16:48 -0500337 assert category
338 assert pn
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100339 return '%s/%s' % (category, pn)
340
341
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100342def IsPackageDisabled(target, package):
343 """Returns if the given package is not used for the target."""
344 return GetDesiredPackageVersions(target, package) == [PACKAGE_NONE]
345
Liam McLoughlinf54a0782012-05-17 23:36:52 +0100346
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700347def PortageTrees(root):
348 """Return the portage trees for a given root."""
349 if root == '/':
350 return portage.db['/']
351 # The portage logic requires the path always end in a slash.
352 root = root.rstrip('/') + '/'
353 return portage.create_trees(target_root=root, config_root=root)[root]
354
355
356def GetInstalledPackageVersions(atom, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100357 """Extracts the list of current versions of a target, package pair.
358
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500359 Args:
360 atom: The atom to operate on (e.g. sys-devel/gcc)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700361 root: The root to check for installed packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100362
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500363 Returns:
364 The list of versions of the package currently installed.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100365 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100366 versions = []
Mike Frysinger506e75f2012-12-17 14:21:13 -0500367 # pylint: disable=E1101
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700368 for pkg in PortageTrees(root)['vartree'].dbapi.match(atom, use_cache=0):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100369 version = portage.versions.cpv_getversion(pkg)
370 versions.append(version)
371 return versions
372
373
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700374def GetStablePackageVersion(atom, installed, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100375 """Extracts the current stable version for a given package.
376
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500377 Args:
378 atom: The target/package to operate on eg. i686-pc-linux-gnu,gcc
379 installed: Whether we want installed packages or ebuilds
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700380 root: The root to use when querying packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100381
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500382 Returns:
383 A string containing the latest version.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100384 """
David James90239b92012-11-05 15:31:34 -0800385 pkgtype = 'vartree' if installed else 'porttree'
Mike Frysinger506e75f2012-12-17 14:21:13 -0500386 # pylint: disable=E1101
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700387 cpv = portage.best(PortageTrees(root)[pkgtype].dbapi.match(atom, use_cache=0))
David James90239b92012-11-05 15:31:34 -0800388 return portage.versions.cpv_getversion(cpv) if cpv else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100389
390
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700391def VersionListToNumeric(target, package, versions, installed, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100392 """Resolves keywords in a given version list for a particular package.
393
394 Resolving means replacing PACKAGE_STABLE with the actual number.
395
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500396 Args:
397 target: The target to operate on (e.g. i686-pc-linux-gnu)
398 package: The target/package to operate on (e.g. gcc)
399 versions: List of versions to resolve
400 installed: Query installed packages
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700401 root: The install root to use; ignored if |installed| is False.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100402
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500403 Returns:
404 List of purely numeric versions equivalent to argument
Zdenek Behan508dcce2011-12-05 15:39:32 +0100405 """
406 resolved = []
David James90239b92012-11-05 15:31:34 -0800407 atom = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700408 if not installed:
409 root = '/'
Zdenek Behan508dcce2011-12-05 15:39:32 +0100410 for version in versions:
411 if version == PACKAGE_STABLE:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700412 resolved.append(GetStablePackageVersion(atom, installed, root=root))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100413 elif version != PACKAGE_NONE:
414 resolved.append(version)
415 return resolved
416
417
418def GetDesiredPackageVersions(target, package):
419 """Produces the list of desired versions for each target, package pair.
420
421 The first version in the list is implicitly treated as primary, ie.
422 the version that will be initialized by crossdev and selected.
423
424 If the version is PACKAGE_STABLE, it really means the current version which
425 is emerged by using the package atom with no particular version key.
426 Since crossdev unmasks all packages by default, this will actually
427 mean 'unstable' in most cases.
428
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500429 Args:
430 target: The target to operate on (e.g. i686-pc-linux-gnu)
431 package: The target/package to operate on (e.g. gcc)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100432
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500433 Returns:
434 A list composed of either a version string, PACKAGE_STABLE
Zdenek Behan508dcce2011-12-05 15:39:32 +0100435 """
436 packagemap = GetPackageMap(target)
437
438 versions = []
439 if package in packagemap:
440 versions.append(packagemap[package])
441
442 return versions
443
444
445def TargetIsInitialized(target):
446 """Verifies if the given list of targets has been correctly initialized.
447
448 This determines whether we have to call crossdev while emerging
449 toolchain packages or can do it using emerge. Emerge is naturally
450 preferred, because all packages can be updated in a single pass.
451
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500452 Args:
453 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100454
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500455 Returns:
456 True if |target| is completely initialized, else False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100457 """
458 # Check if packages for the given target all have a proper version.
459 try:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100460 for package in GetTargetPackages(target):
David James66a09c42012-11-05 13:31:38 -0800461 atom = GetPortagePackage(target, package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100462 # Do we even want this package && is it initialized?
David James90239b92012-11-05 15:31:34 -0800463 if not IsPackageDisabled(target, package) and not (
464 GetStablePackageVersion(atom, True) and
465 GetStablePackageVersion(atom, False)):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100466 return False
467 return True
468 except cros_build_lib.RunCommandError:
469 # Fails - The target has likely never been initialized before.
470 return False
471
472
473def RemovePackageMask(target):
474 """Removes a package.mask file for the given platform.
475
476 The pre-existing package.mask files can mess with the keywords.
477
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500478 Args:
479 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100480 """
481 maskfile = os.path.join('/etc/portage/package.mask', 'cross-' + target)
Brian Harringaf019fb2012-05-10 15:06:13 -0700482 osutils.SafeUnlink(maskfile)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100483
484
Zdenek Behan508dcce2011-12-05 15:39:32 +0100485# Main functions performing the actual update steps.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700486def RebuildLibtool(root='/'):
Mike Frysingerc880a962013-11-08 13:59:06 -0500487 """Rebuild libtool as needed
488
489 Libtool hardcodes full paths to internal gcc files, so whenever we upgrade
490 gcc, libtool will break. We can't use binary packages either as those will
491 most likely be compiled against the previous version of gcc.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700492
493 Args:
494 root: The install root where we want libtool rebuilt.
Mike Frysingerc880a962013-11-08 13:59:06 -0500495 """
496 needs_update = False
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700497 with open(os.path.join(root, 'usr/bin/libtool')) as f:
Mike Frysingerc880a962013-11-08 13:59:06 -0500498 for line in f:
499 # Look for a line like:
500 # sys_lib_search_path_spec="..."
501 # It'll be a list of paths and gcc will be one of them.
502 if line.startswith('sys_lib_search_path_spec='):
503 line = line.rstrip()
504 for path in line.split('=', 1)[1].strip('"').split():
Mike Frysinger3bba5032016-09-20 14:15:04 -0400505 root_path = os.path.join(root, path.lstrip(os.path.sep))
506 logging.debug('Libtool: checking %s', root_path)
507 if not os.path.exists(root_path):
508 logging.info('Rebuilding libtool after gcc upgrade')
509 logging.info(' %s', line)
510 logging.info(' missing path: %s', path)
Mike Frysingerc880a962013-11-08 13:59:06 -0500511 needs_update = True
512 break
513
514 if needs_update:
515 break
516
517 if needs_update:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700518 cmd = [EMERGE_CMD, '--oneshot']
519 if root != '/':
520 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
521 cmd.append('sys-devel/libtool')
Mike Frysingerc880a962013-11-08 13:59:06 -0500522 cros_build_lib.RunCommand(cmd)
Mike Frysinger3bba5032016-09-20 14:15:04 -0400523 else:
524 logging.debug('Libtool is up-to-date; no need to rebuild')
Mike Frysingerc880a962013-11-08 13:59:06 -0500525
526
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700527def UpdateTargets(targets, usepkg, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100528 """Determines which packages need update/unmerge and defers to portage.
529
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500530 Args:
531 targets: The list of targets to update
532 usepkg: Copies the commandline option
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700533 root: The install root in which we want packages updated.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100534 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100535 # For each target, we do two things. Figure out the list of updates,
536 # and figure out the appropriate keywords/masks. Crossdev will initialize
537 # these, but they need to be regenerated on every update.
Mike Frysinger3bba5032016-09-20 14:15:04 -0400538 logging.info('Determining required toolchain updates...')
David James90239b92012-11-05 15:31:34 -0800539 mergemap = {}
Zdenek Behan508dcce2011-12-05 15:39:32 +0100540 for target in targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400541 logging.debug('Updating target %s', target)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100542 # Record the highest needed version for each target, for masking purposes.
543 RemovePackageMask(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100544 for package in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100545 # Portage name for the package
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100546 if IsPackageDisabled(target, package):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400547 logging.debug(' Skipping disabled package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100548 continue
Mike Frysinger3bba5032016-09-20 14:15:04 -0400549 logging.debug(' Updating package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100550 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700551 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100552 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200553 desired_num = VersionListToNumeric(target, package, desired, False)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100554 mergemap[pkg] = set(desired_num).difference(current)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100555
Zdenek Behan508dcce2011-12-05 15:39:32 +0100556 packages = []
557 for pkg in mergemap:
558 for ver in mergemap[pkg]:
Zdenek Behan677b6d82012-04-11 05:31:47 +0200559 if ver != PACKAGE_NONE:
David James90239b92012-11-05 15:31:34 -0800560 packages.append(pkg)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100561
562 if not packages:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400563 logging.info('Nothing to update!')
David Jamesf8c672f2012-11-06 13:38:11 -0800564 return False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100565
Mike Frysinger3bba5032016-09-20 14:15:04 -0400566 logging.info('Updating packages:')
567 logging.info('%s', packages)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100568
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100569 cmd = [EMERGE_CMD, '--oneshot', '--update']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100570 if usepkg:
571 cmd.extend(['--getbinpkg', '--usepkgonly'])
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700572 if root != '/':
573 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100574
575 cmd.extend(packages)
576 cros_build_lib.RunCommand(cmd)
David Jamesf8c672f2012-11-06 13:38:11 -0800577 return True
Zdenek Behan508dcce2011-12-05 15:39:32 +0100578
579
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700580def CleanTargets(targets, root='/'):
581 """Unmerges old packages that are assumed unnecessary.
582
583 Args:
584 targets: The list of targets to clean up.
585 root: The install root in which we want packages cleaned up.
586 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100587 unmergemap = {}
588 for target in targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400589 logging.debug('Cleaning target %s', target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100590 for package in GetTargetPackages(target):
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100591 if IsPackageDisabled(target, package):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400592 logging.debug(' Skipping disabled package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100593 continue
Mike Frysinger3bba5032016-09-20 14:15:04 -0400594 logging.debug(' Cleaning package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100595 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700596 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100597 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2fcb0aa2015-05-21 14:51:41 -0700598 # NOTE: This refers to installed packages (vartree) rather than the
599 # Portage version (porttree and/or bintree) when determining the current
600 # version. While this isn't the most accurate thing to do, it is probably
601 # a good simple compromise, which should have the desired result of
602 # uninstalling everything but the latest installed version. In
603 # particular, using the bintree (--usebinpkg) requires a non-trivial
604 # binhost sync and is probably more complex than useful.
Zdenek Behan699ddd32012-04-13 07:14:08 +0200605 desired_num = VersionListToNumeric(target, package, desired, True)
606 if not set(desired_num).issubset(current):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400607 logging.warning('Error detecting stable version for %s, '
608 'skipping clean!', pkg)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200609 return
Zdenek Behan508dcce2011-12-05 15:39:32 +0100610 unmergemap[pkg] = set(current).difference(desired_num)
611
612 # Cleaning doesn't care about consistency and rebuilding package.* files.
613 packages = []
614 for pkg, vers in unmergemap.iteritems():
615 packages.extend('=%s-%s' % (pkg, ver) for ver in vers if ver != '9999')
616
617 if packages:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400618 logging.info('Cleaning packages:')
619 logging.info('%s', packages)
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100620 cmd = [EMERGE_CMD, '--unmerge']
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700621 if root != '/':
622 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100623 cmd.extend(packages)
624 cros_build_lib.RunCommand(cmd)
625 else:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400626 logging.info('Nothing to clean!')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100627
628
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700629def SelectActiveToolchains(targets, suffixes, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100630 """Runs gcc-config and binutils-config to select the desired.
631
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500632 Args:
633 targets: The targets to select
634 suffixes: Optional target-specific hacks
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700635 root: The root where we want to select toolchain versions.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100636 """
637 for package in ['gcc', 'binutils']:
638 for target in targets:
639 # Pick the first version in the numbered list as the selected one.
640 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700641 desired_num = VersionListToNumeric(target, package, desired, True,
642 root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100643 desired = desired_num[0]
644 # *-config does not play revisions, strip them, keep just PV.
645 desired = portage.versions.pkgsplit('%s-%s' % (package, desired))[1]
646
647 if target == 'host':
648 # *-config is the only tool treating host identically (by tuple).
David James27ac4ae2012-12-03 23:16:15 -0800649 target = toolchain.GetHostTuple()
Zdenek Behan508dcce2011-12-05 15:39:32 +0100650
651 # And finally, attach target to it.
652 desired = '%s-%s' % (target, desired)
653
654 # Target specific hacks
655 if package in suffixes:
656 if target in suffixes[package]:
657 desired += suffixes[package][target]
658
David James7ec5efc2012-11-06 09:39:49 -0800659 extra_env = {'CHOST': target}
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700660 if root != '/':
661 extra_env['ROOT'] = root
David James7ec5efc2012-11-06 09:39:49 -0800662 cmd = ['%s-config' % package, '-c', target]
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500663 result = cros_build_lib.RunCommand(
664 cmd, print_cmd=False, redirect_stdout=True, extra_env=extra_env)
665 current = result.output.splitlines()[0]
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700666
667 # Do not reconfig when the current is live or nothing needs to be done.
668 extra_env = {'ROOT': root} if root != '/' else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100669 if current != desired and current != '9999':
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500670 cmd = [package + '-config', desired]
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700671 cros_build_lib.RunCommand(cmd, print_cmd=False, extra_env=extra_env)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100672
673
Mike Frysinger35247af2012-11-16 18:58:06 -0500674def ExpandTargets(targets_wanted):
675 """Expand any possible toolchain aliases into full targets
676
677 This will expand 'all' and 'sdk' into the respective toolchain tuples.
678
679 Args:
680 targets_wanted: The targets specified by the user.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500681
Mike Frysinger35247af2012-11-16 18:58:06 -0500682 Returns:
Gilad Arnold8195b532015-04-07 10:56:30 +0300683 Dictionary of concrete targets and their toolchain tuples.
Mike Frysinger35247af2012-11-16 18:58:06 -0500684 """
Mike Frysinger35247af2012-11-16 18:58:06 -0500685 targets_wanted = set(targets_wanted)
Don Garrettc0c74002015-10-09 12:58:19 -0700686 if targets_wanted == set(['boards']):
687 # Only pull targets from the included boards.
Gilad Arnold8195b532015-04-07 10:56:30 +0300688 return {}
689
690 all_targets = toolchain.GetAllTargets()
Mike Frysinger35247af2012-11-16 18:58:06 -0500691 if targets_wanted == set(['all']):
Gilad Arnold8195b532015-04-07 10:56:30 +0300692 return all_targets
693 if targets_wanted == set(['sdk']):
Mike Frysinger35247af2012-11-16 18:58:06 -0500694 # Filter out all the non-sdk toolchains as we don't want to mess
695 # with those in all of our builds.
Gilad Arnold8195b532015-04-07 10:56:30 +0300696 return toolchain.FilterToolchains(all_targets, 'sdk', True)
697
698 # Verify user input.
699 nonexistent = targets_wanted.difference(all_targets)
700 if nonexistent:
701 raise ValueError('Invalid targets: %s', ','.join(nonexistent))
702 return {t: all_targets[t] for t in targets_wanted}
Mike Frysinger35247af2012-11-16 18:58:06 -0500703
704
David Jamesf8c672f2012-11-06 13:38:11 -0800705def UpdateToolchains(usepkg, deleteold, hostonly, reconfig,
Don Garrettc0c74002015-10-09 12:58:19 -0700706 targets_wanted, boards_wanted, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100707 """Performs all steps to create a synchronized toolchain enviroment.
708
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500709 Args:
710 usepkg: Use prebuilt packages
711 deleteold: Unmerge deprecated packages
712 hostonly: Only setup the host toolchain
713 reconfig: Reload crossdev config and reselect toolchains
714 targets_wanted: All the targets to update
715 boards_wanted: Load targets from these boards
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700716 root: The root in which to install the toolchains.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100717 """
David Jamesf8c672f2012-11-06 13:38:11 -0800718 targets, crossdev_targets, reconfig_targets = {}, {}, {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100719 if not hostonly:
720 # For hostonly, we can skip most of the below logic, much of which won't
721 # work on bare systems where this is useful.
Mike Frysinger35247af2012-11-16 18:58:06 -0500722 targets = ExpandTargets(targets_wanted)
Mike Frysinger7ccee992012-06-01 21:27:59 -0400723
Don Garrettc0c74002015-10-09 12:58:19 -0700724 # Now re-add any targets that might be from this board. This is to
Gilad Arnold8195b532015-04-07 10:56:30 +0300725 # allow unofficial boards to declare their own toolchains.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400726 for board in boards_wanted:
David James27ac4ae2012-12-03 23:16:15 -0800727 targets.update(toolchain.GetToolchainsForBoard(board))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100728
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100729 # First check and initialize all cross targets that need to be.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400730 for target in targets:
731 if TargetIsInitialized(target):
732 reconfig_targets[target] = targets[target]
733 else:
734 crossdev_targets[target] = targets[target]
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100735 if crossdev_targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400736 logging.info('The following targets need to be re-initialized:')
737 logging.info('%s', crossdev_targets)
David James66a09c42012-11-05 13:31:38 -0800738 Crossdev.UpdateTargets(crossdev_targets, usepkg)
Zdenek Behan8be29ba2012-05-29 23:10:34 +0200739 # Those that were not initialized may need a config update.
David James66a09c42012-11-05 13:31:38 -0800740 Crossdev.UpdateTargets(reconfig_targets, usepkg, config_only=True)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100741
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100742 # We want host updated.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400743 targets['host'] = {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100744
745 # Now update all packages.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700746 if UpdateTargets(targets, usepkg, root=root) or crossdev_targets or reconfig:
747 SelectActiveToolchains(targets, CONFIG_TARGET_SUFFIXES, root=root)
David James7ec5efc2012-11-06 09:39:49 -0800748
749 if deleteold:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700750 CleanTargets(targets, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100751
Mike Frysingerc880a962013-11-08 13:59:06 -0500752 # Now that we've cleared out old versions, see if we need to rebuild
753 # anything. Can't do this earlier as it might not be broken.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700754 RebuildLibtool(root=root)
Mike Frysingerc880a962013-11-08 13:59:06 -0500755
Zdenek Behan508dcce2011-12-05 15:39:32 +0100756
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -0700757def ShowConfig(name):
758 """Show the toolchain tuples used by |name|
Mike Frysinger35247af2012-11-16 18:58:06 -0500759
760 Args:
Don Garrettc0c74002015-10-09 12:58:19 -0700761 name: The board name to query.
Mike Frysinger35247af2012-11-16 18:58:06 -0500762 """
Don Garrettc0c74002015-10-09 12:58:19 -0700763 toolchains = toolchain.GetToolchainsForBoard(name)
Mike Frysinger35247af2012-11-16 18:58:06 -0500764 # Make sure we display the default toolchain first.
Mike Frysinger3bba5032016-09-20 14:15:04 -0400765 # Note: Do not use logging here as this is meant to be used by other tools.
Mike Frysinger383367e2014-09-16 15:06:17 -0400766 print(','.join(
David James27ac4ae2012-12-03 23:16:15 -0800767 toolchain.FilterToolchains(toolchains, 'default', True).keys() +
Mike Frysinger383367e2014-09-16 15:06:17 -0400768 toolchain.FilterToolchains(toolchains, 'default', False).keys()))
Mike Frysinger35247af2012-11-16 18:58:06 -0500769
770
Mike Frysinger35247af2012-11-16 18:58:06 -0500771def GeneratePathWrapper(root, wrappath, path):
772 """Generate a shell script to execute another shell script
773
774 Since we can't symlink a wrapped ELF (see GenerateLdsoWrapper) because the
775 argv[0] won't be pointing to the correct path, generate a shell script that
776 just executes another program with its full path.
777
778 Args:
779 root: The root tree to generate scripts inside of
780 wrappath: The full path (inside |root|) to create the wrapper
781 path: The target program which this wrapper will execute
782 """
783 replacements = {
784 'path': path,
785 'relroot': os.path.relpath('/', os.path.dirname(wrappath)),
786 }
787 wrapper = """#!/bin/sh
788base=$(realpath "$0")
789basedir=${base%%/*}
790exec "${basedir}/%(relroot)s%(path)s" "$@"
791""" % replacements
792 root_wrapper = root + wrappath
793 if os.path.islink(root_wrapper):
794 os.unlink(root_wrapper)
795 else:
796 osutils.SafeMakedirs(os.path.dirname(root_wrapper))
797 osutils.WriteFile(root_wrapper, wrapper)
Mike Frysinger60ec1012013-10-21 00:11:10 -0400798 os.chmod(root_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -0500799
800
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -0700801def FixClangXXWrapper(root, path):
802 """Fix wrapper shell scripts and symlinks for invoking clang++
803
804 In a typical installation, clang++ symlinks to clang, which symlinks to the
805 elf executable. The executable distinguishes between clang and clang++ based
806 on argv[0].
807
808 When invoked through the LdsoWrapper, argv[0] always contains the path to the
809 executable elf file, making clang/clang++ invocations indistinguishable.
810
811 This function detects if the elf executable being wrapped is clang-X.Y, and
812 fixes wrappers/symlinks as necessary so that clang++ will work correctly.
813
814 The calling sequence now becomes:
815 -) clang++ invocation turns into clang++-3.9 (which is a copy of clang-3.9,
816 the Ldsowrapper).
817 -) clang++-3.9 uses the Ldso to invoke clang++-3.9.elf, which is a symlink
818 to the original clang-3.9 elf.
819 -) The difference this time is that inside the elf file execution, $0 is
820 set as .../usr/bin/clang++-3.9.elf, which contains 'clang++' in the name.
821
822 Args:
823 root: The root tree to generate scripts / symlinks inside of
824 path: The target elf for which LdsoWrapper was created
825 """
826 if re.match(r'/usr/bin/clang-\d+\.\d+$', path):
827 logging.info('fixing clang++ invocation for %s', path)
828 clangdir = os.path.dirname(root + path)
829 clang = os.path.basename(path)
830 clangxx = clang.replace('clang', 'clang++')
831
832 # Create a symlink clang++-X.Y.elf to point to clang-X.Y.elf
833 os.symlink(clang + '.elf', os.path.join(clangdir, clangxx + '.elf'))
834
835 # Create a hardlink clang++-X.Y pointing to clang-X.Y
836 os.link(os.path.join(clangdir, clang), os.path.join(clangdir, clangxx))
837
838 # Adjust the clang++ symlink to point to clang++-X.Y
839 os.unlink(os.path.join(clangdir, 'clang++'))
840 os.symlink(clangxx, os.path.join(clangdir, 'clang++'))
841
842
Mike Frysinger35247af2012-11-16 18:58:06 -0500843def FileIsCrosSdkElf(elf):
844 """Determine if |elf| is an ELF that we execute in the cros_sdk
845
846 We don't need this to be perfect, just quick. It makes sure the ELF
847 is a 64bit LSB x86_64 ELF. That is the native type of cros_sdk.
848
849 Args:
850 elf: The file to check
Mike Frysinger1a736a82013-12-12 01:50:59 -0500851
Mike Frysinger35247af2012-11-16 18:58:06 -0500852 Returns:
853 True if we think |elf| is a native ELF
854 """
855 with open(elf) as f:
856 data = f.read(20)
857 # Check the magic number, EI_CLASS, EI_DATA, and e_machine.
858 return (data[0:4] == '\x7fELF' and
859 data[4] == '\x02' and
860 data[5] == '\x01' and
861 data[18] == '\x3e')
862
863
864def IsPathPackagable(ptype, path):
865 """Should the specified file be included in a toolchain package?
866
867 We only need to handle files as we'll create dirs as we need them.
868
869 Further, trim files that won't be useful:
870 - non-english translations (.mo) since it'd require env vars
871 - debug files since these are for the host compiler itself
872 - info/man pages as they're big, and docs are online, and the
873 native docs should work fine for the most part (`man gcc`)
874
875 Args:
876 ptype: A string describing the path type (i.e. 'file' or 'dir' or 'sym')
877 path: The full path to inspect
Mike Frysinger1a736a82013-12-12 01:50:59 -0500878
Mike Frysinger35247af2012-11-16 18:58:06 -0500879 Returns:
880 True if we want to include this path in the package
881 """
882 return not (ptype in ('dir',) or
883 path.startswith('/usr/lib/debug/') or
884 os.path.splitext(path)[1] == '.mo' or
885 ('/man/' in path or '/info/' in path))
886
887
888def ReadlinkRoot(path, root):
889 """Like os.readlink(), but relative to a |root|
890
891 Args:
892 path: The symlink to read
893 root: The path to use for resolving absolute symlinks
Mike Frysinger1a736a82013-12-12 01:50:59 -0500894
Mike Frysinger35247af2012-11-16 18:58:06 -0500895 Returns:
896 A fully resolved symlink path
897 """
898 while os.path.islink(root + path):
899 path = os.path.join(os.path.dirname(path), os.readlink(root + path))
900 return path
901
902
903def _GetFilesForTarget(target, root='/'):
904 """Locate all the files to package for |target|
905
906 This does not cover ELF dependencies.
907
908 Args:
909 target: The toolchain target name
910 root: The root path to pull all packages from
Mike Frysinger1a736a82013-12-12 01:50:59 -0500911
Mike Frysinger35247af2012-11-16 18:58:06 -0500912 Returns:
913 A tuple of a set of all packable paths, and a set of all paths which
914 are also native ELFs
915 """
916 paths = set()
917 elfs = set()
918
919 # Find all the files owned by the packages for this target.
920 for pkg in GetTargetPackages(target):
Mike Frysinger35247af2012-11-16 18:58:06 -0500921
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700922 # Skip Go compiler from redistributable packages.
923 # The "go" executable has GOROOT=/usr/lib/go/${CTARGET} hardcoded
924 # into it. Due to this, the toolchain cannot be unpacked anywhere
925 # else and be readily useful. To enable packaging Go, we need to:
926 # -) Tweak the wrappers/environment to override GOROOT
927 # automatically based on the unpack location.
928 # -) Make sure the ELF dependency checking and wrapping logic
929 # below skips the Go toolchain executables and libraries.
930 # -) Make sure the packaging process maintains the relative
931 # timestamps of precompiled standard library packages.
932 # (see dev-lang/go ebuild for details).
933 if pkg == 'ex_go':
934 continue
935
Mike Frysinger35247af2012-11-16 18:58:06 -0500936 atom = GetPortagePackage(target, pkg)
937 cat, pn = atom.split('/')
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700938 ver = GetInstalledPackageVersions(atom, root=root)[0]
Ralph Nathan03047282015-03-23 11:09:32 -0700939 logging.info('packaging %s-%s', atom, ver)
Mike Frysinger35247af2012-11-16 18:58:06 -0500940
941 # pylint: disable=E1101
942 dblink = portage.dblink(cat, pn + '-' + ver, myroot=root,
943 settings=portage.settings)
944 contents = dblink.getcontents()
945 for obj in contents:
946 ptype = contents[obj][0]
947 if not IsPathPackagable(ptype, obj):
948 continue
949
950 if ptype == 'obj':
951 # For native ELFs, we need to pull in their dependencies too.
952 if FileIsCrosSdkElf(obj):
953 elfs.add(obj)
954 paths.add(obj)
955
956 return paths, elfs
957
958
959def _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500960 path_rewrite_func=lambda x: x, root='/'):
Mike Frysinger35247af2012-11-16 18:58:06 -0500961 """Link in all packable files and their runtime dependencies
962
963 This also wraps up executable ELFs with helper scripts.
964
965 Args:
966 output_dir: The output directory to store files
967 paths: All the files to include
968 elfs: All the files which are ELFs (a subset of |paths|)
969 ldpaths: A dict of static ldpath information
970 path_rewrite_func: User callback to rewrite paths in output_dir
971 root: The root path to pull all packages/files from
972 """
973 # Link in all the files.
974 sym_paths = []
975 for path in paths:
976 new_path = path_rewrite_func(path)
977 dst = output_dir + new_path
978 osutils.SafeMakedirs(os.path.dirname(dst))
979
980 # Is this a symlink which we have to rewrite or wrap?
981 # Delay wrap check until after we have created all paths.
982 src = root + path
983 if os.path.islink(src):
984 tgt = os.readlink(src)
985 if os.path.sep in tgt:
986 sym_paths.append((new_path, lddtree.normpath(ReadlinkRoot(src, root))))
987
988 # Rewrite absolute links to relative and then generate the symlink
989 # ourselves. All other symlinks can be hardlinked below.
990 if tgt[0] == '/':
991 tgt = os.path.relpath(tgt, os.path.dirname(new_path))
992 os.symlink(tgt, dst)
993 continue
994
995 os.link(src, dst)
996
997 # Now see if any of the symlinks need to be wrapped.
998 for sym, tgt in sym_paths:
999 if tgt in elfs:
1000 GeneratePathWrapper(output_dir, sym, tgt)
1001
1002 # Locate all the dependencies for all the ELFs. Stick them all in the
1003 # top level "lib" dir to make the wrapper simpler. This exact path does
1004 # not matter since we execute ldso directly, and we tell the ldso the
1005 # exact path to search for its libraries.
1006 libdir = os.path.join(output_dir, 'lib')
1007 osutils.SafeMakedirs(libdir)
1008 donelibs = set()
1009 for elf in elfs:
Mike Frysingerea7688e2014-07-31 22:40:33 -04001010 e = lddtree.ParseELF(elf, root=root, ldpaths=ldpaths)
Mike Frysinger35247af2012-11-16 18:58:06 -05001011 interp = e['interp']
1012 if interp:
1013 # Generate a wrapper if it is executable.
Mike Frysingerc2ec0902013-03-26 01:28:45 -04001014 interp = os.path.join('/lib', os.path.basename(interp))
1015 lddtree.GenerateLdsoWrapper(output_dir, path_rewrite_func(elf), interp,
1016 libpaths=e['rpath'] + e['runpath'])
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -07001017 FixClangXXWrapper(output_dir, path_rewrite_func(elf))
Mike Frysinger35247af2012-11-16 18:58:06 -05001018
1019 for lib, lib_data in e['libs'].iteritems():
1020 if lib in donelibs:
1021 continue
1022
1023 src = path = lib_data['path']
1024 if path is None:
Ralph Nathan446aee92015-03-23 14:44:56 -07001025 logging.warning('%s: could not locate %s', elf, lib)
Mike Frysinger35247af2012-11-16 18:58:06 -05001026 continue
1027 donelibs.add(lib)
1028
1029 # Needed libs are the SONAME, but that is usually a symlink, not a
1030 # real file. So link in the target rather than the symlink itself.
1031 # We have to walk all the possible symlinks (SONAME could point to a
1032 # symlink which points to a symlink), and we have to handle absolute
1033 # ourselves (since we have a "root" argument).
1034 dst = os.path.join(libdir, os.path.basename(path))
1035 src = ReadlinkRoot(src, root)
1036
1037 os.link(root + src, dst)
1038
1039
1040def _EnvdGetVar(envd, var):
1041 """Given a Gentoo env.d file, extract a var from it
1042
1043 Args:
1044 envd: The env.d file to load (may be a glob path)
1045 var: The var to extract
Mike Frysinger1a736a82013-12-12 01:50:59 -05001046
Mike Frysinger35247af2012-11-16 18:58:06 -05001047 Returns:
1048 The value of |var|
1049 """
1050 envds = glob.glob(envd)
1051 assert len(envds) == 1, '%s: should have exactly 1 env.d file' % envd
1052 envd = envds[0]
1053 return cros_build_lib.LoadKeyValueFile(envd)[var]
1054
1055
1056def _ProcessBinutilsConfig(target, output_dir):
1057 """Do what binutils-config would have done"""
1058 binpath = os.path.join('/bin', target + '-')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001059
1060 # Locate the bin dir holding the gold linker.
1061 binutils_bin_path = os.path.join(output_dir, 'usr', toolchain.GetHostTuple(),
1062 target, 'binutils-bin')
1063 globpath = os.path.join(binutils_bin_path, '*-gold')
Mike Frysinger35247af2012-11-16 18:58:06 -05001064 srcpath = glob.glob(globpath)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001065 if not srcpath:
1066 # Maybe this target doesn't support gold.
1067 globpath = os.path.join(binutils_bin_path, '*')
1068 srcpath = glob.glob(globpath)
1069 assert len(srcpath) == 1, ('%s: matched more than one path (but not *-gold)'
1070 % globpath)
1071 srcpath = srcpath[0]
1072 ld_path = os.path.join(srcpath, 'ld')
1073 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1074 ld_path = os.path.join(srcpath, 'ld.bfd')
1075 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1076 ld_path = os.path.join(srcpath, 'ld.gold')
1077 assert not os.path.exists(ld_path), ('%s: exists, but gold dir does not!'
1078 % ld_path)
1079
1080 # Nope, no gold support to be found.
1081 gold_supported = False
Ralph Nathan446aee92015-03-23 14:44:56 -07001082 logging.warning('%s: binutils lacks support for the gold linker', target)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001083 else:
1084 assert len(srcpath) == 1, '%s: did not match exactly 1 path' % globpath
Mike Frysinger78b7a812014-11-26 19:45:23 -05001085 srcpath = srcpath[0]
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001086
Rahul Chaudhry4891b4d2017-03-08 10:31:27 -08001087 # Package the binutils-bin directory without the '-gold' suffix
1088 # if gold is not enabled as the default linker for this target.
1089 gold_supported = CONFIG_TARGET_SUFFIXES['binutils'].get(target) == '-gold'
1090 if not gold_supported:
1091 srcpath = srcpath[:-len('-gold')]
1092 ld_path = os.path.join(srcpath, 'ld')
1093 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1094
Mike Frysinger78b7a812014-11-26 19:45:23 -05001095 srcpath = srcpath[len(output_dir):]
Mike Frysinger35247af2012-11-16 18:58:06 -05001096 gccpath = os.path.join('/usr', 'libexec', 'gcc')
1097 for prog in os.listdir(output_dir + srcpath):
1098 # Skip binaries already wrapped.
1099 if not prog.endswith('.real'):
1100 GeneratePathWrapper(output_dir, binpath + prog,
1101 os.path.join(srcpath, prog))
1102 GeneratePathWrapper(output_dir, os.path.join(gccpath, prog),
1103 os.path.join(srcpath, prog))
1104
David James27ac4ae2012-12-03 23:16:15 -08001105 libpath = os.path.join('/usr', toolchain.GetHostTuple(), target, 'lib')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001106 envd = os.path.join(output_dir, 'etc', 'env.d', 'binutils', '*')
1107 if gold_supported:
1108 envd += '-gold'
Rahul Chaudhry4891b4d2017-03-08 10:31:27 -08001109 else:
1110 # If gold is not enabled as the default linker and 2 env.d
1111 # files exist, pick the one without the '-gold' suffix.
1112 envds = sorted(glob.glob(envd))
1113 if len(envds) == 2 and envds[1] == envds[0] + '-gold':
1114 envd = envds[0]
Mike Frysinger35247af2012-11-16 18:58:06 -05001115 srcpath = _EnvdGetVar(envd, 'LIBPATH')
1116 os.symlink(os.path.relpath(srcpath, os.path.dirname(libpath)),
1117 output_dir + libpath)
1118
1119
1120def _ProcessGccConfig(target, output_dir):
1121 """Do what gcc-config would have done"""
1122 binpath = '/bin'
1123 envd = os.path.join(output_dir, 'etc', 'env.d', 'gcc', '*')
1124 srcpath = _EnvdGetVar(envd, 'GCC_PATH')
1125 for prog in os.listdir(output_dir + srcpath):
1126 # Skip binaries already wrapped.
1127 if (not prog.endswith('.real') and
1128 not prog.endswith('.elf') and
1129 prog.startswith(target)):
1130 GeneratePathWrapper(output_dir, os.path.join(binpath, prog),
1131 os.path.join(srcpath, prog))
1132 return srcpath
1133
1134
Frank Henigman179ec7c2015-02-06 03:01:09 -05001135def _ProcessSysrootWrappers(_target, output_dir, srcpath):
1136 """Remove chroot-specific things from our sysroot wrappers"""
Mike Frysinger35247af2012-11-16 18:58:06 -05001137 # Disable ccache since we know it won't work outside of chroot.
Frank Henigman179ec7c2015-02-06 03:01:09 -05001138 for sysroot_wrapper in glob.glob(os.path.join(
1139 output_dir + srcpath, 'sysroot_wrapper*')):
1140 contents = osutils.ReadFile(sysroot_wrapper).splitlines()
1141 for num in xrange(len(contents)):
1142 if '@CCACHE_DEFAULT@' in contents[num]:
Caroline Ticece9e9232017-06-02 09:38:42 -07001143 assert 'True' in contents[num]
1144 contents[num] = contents[num].replace('True', 'False')
Frank Henigman179ec7c2015-02-06 03:01:09 -05001145 break
1146 # Can't update the wrapper in place since it's a hardlink to a file in /.
1147 os.unlink(sysroot_wrapper)
1148 osutils.WriteFile(sysroot_wrapper, '\n'.join(contents))
1149 os.chmod(sysroot_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -05001150
1151
1152def _ProcessDistroCleanups(target, output_dir):
1153 """Clean up the tree and remove all distro-specific requirements
1154
1155 Args:
1156 target: The toolchain target name
1157 output_dir: The output directory to clean up
1158 """
1159 _ProcessBinutilsConfig(target, output_dir)
1160 gcc_path = _ProcessGccConfig(target, output_dir)
Frank Henigman179ec7c2015-02-06 03:01:09 -05001161 _ProcessSysrootWrappers(target, output_dir, gcc_path)
Mike Frysinger35247af2012-11-16 18:58:06 -05001162
1163 osutils.RmDir(os.path.join(output_dir, 'etc'))
1164
1165
1166def CreatePackagableRoot(target, output_dir, ldpaths, root='/'):
1167 """Setup a tree from the packages for the specified target
1168
1169 This populates a path with all the files from toolchain packages so that
1170 a tarball can easily be generated from the result.
1171
1172 Args:
1173 target: The target to create a packagable root from
1174 output_dir: The output directory to place all the files
1175 ldpaths: A dict of static ldpath information
1176 root: The root path to pull all packages/files from
1177 """
1178 # Find all the files owned by the packages for this target.
1179 paths, elfs = _GetFilesForTarget(target, root=root)
1180
1181 # Link in all the package's files, any ELF dependencies, and wrap any
1182 # executable ELFs with helper scripts.
1183 def MoveUsrBinToBin(path):
Han Shen699ea192016-03-02 10:42:47 -08001184 """Move /usr/bin to /bin so people can just use that toplevel dir
1185
1186 Note we do not apply this to clang - there is correlation between clang's
1187 search path for libraries / inclusion and its installation path.
1188 """
1189 if path.startswith('/usr/bin/') and path.find('clang') == -1:
1190 return path[4:]
1191 return path
Mike Frysinger35247af2012-11-16 18:58:06 -05001192 _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
1193 path_rewrite_func=MoveUsrBinToBin, root=root)
1194
1195 # The packages, when part of the normal distro, have helper scripts
1196 # that setup paths and such. Since we are making this standalone, we
1197 # need to preprocess all that ourselves.
1198 _ProcessDistroCleanups(target, output_dir)
1199
1200
1201def CreatePackages(targets_wanted, output_dir, root='/'):
1202 """Create redistributable cross-compiler packages for the specified targets
1203
1204 This creates toolchain packages that should be usable in conjunction with
1205 a downloaded sysroot (created elsewhere).
1206
1207 Tarballs (one per target) will be created in $PWD.
1208
1209 Args:
Don Garrett25f309a2014-03-19 14:02:12 -07001210 targets_wanted: The targets to package up.
1211 output_dir: The directory to put the packages in.
1212 root: The root path to pull all packages/files from.
Mike Frysinger35247af2012-11-16 18:58:06 -05001213 """
Ralph Nathan03047282015-03-23 11:09:32 -07001214 logging.info('Writing tarballs to %s', output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001215 osutils.SafeMakedirs(output_dir)
1216 ldpaths = lddtree.LoadLdpaths(root)
1217 targets = ExpandTargets(targets_wanted)
1218
David James4bc13702013-03-26 08:08:04 -07001219 with osutils.TempDir() as tempdir:
Mike Frysinger35247af2012-11-16 18:58:06 -05001220 # We have to split the root generation from the compression stages. This is
1221 # because we hardlink in all the files (to avoid overhead of reading/writing
1222 # the copies multiple times). But tar gets angry if a file's hardlink count
1223 # changes from when it starts reading a file to when it finishes.
1224 with parallel.BackgroundTaskRunner(CreatePackagableRoot) as queue:
1225 for target in targets:
1226 output_target_dir = os.path.join(tempdir, target)
1227 queue.put([target, output_target_dir, ldpaths, root])
1228
1229 # Build the tarball.
1230 with parallel.BackgroundTaskRunner(cros_build_lib.CreateTarball) as queue:
1231 for target in targets:
1232 tar_file = os.path.join(output_dir, target + '.tar.xz')
1233 queue.put([tar_file, os.path.join(tempdir, target)])
1234
1235
Mike Frysinger07534cf2017-09-12 17:40:21 -04001236def GetParser():
1237 """Return a command line parser."""
Mike Frysinger0c808452014-11-06 17:30:23 -05001238 parser = commandline.ArgumentParser(description=__doc__)
1239 parser.add_argument('-u', '--nousepkg',
1240 action='store_false', dest='usepkg', default=True,
1241 help='Use prebuilt packages if possible')
1242 parser.add_argument('-d', '--deleteold',
1243 action='store_true', dest='deleteold', default=False,
1244 help='Unmerge deprecated packages')
1245 parser.add_argument('-t', '--targets',
1246 dest='targets', default='sdk',
Gilad Arnold8195b532015-04-07 10:56:30 +03001247 help="Comma separated list of tuples. Special keywords "
Don Garrettc0c74002015-10-09 12:58:19 -07001248 "'host', 'sdk', 'boards', and 'all' are "
Gilad Arnold8195b532015-04-07 10:56:30 +03001249 "allowed. Defaults to 'sdk'.")
1250 parser.add_argument('--include-boards', default='', metavar='BOARDS',
1251 help='Comma separated list of boards whose toolchains we '
1252 'will always include. Default: none')
Mike Frysinger0c808452014-11-06 17:30:23 -05001253 parser.add_argument('--hostonly',
1254 dest='hostonly', default=False, action='store_true',
1255 help='Only setup the host toolchain. '
1256 'Useful for bootstrapping chroot')
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001257 parser.add_argument('--show-board-cfg', '--show-cfg',
1258 dest='cfg_name', default=None,
Don Garrettc0c74002015-10-09 12:58:19 -07001259 help='Board to list toolchains tuples for')
Mike Frysinger0c808452014-11-06 17:30:23 -05001260 parser.add_argument('--create-packages',
1261 action='store_true', default=False,
1262 help='Build redistributable packages')
1263 parser.add_argument('--output-dir', default=os.getcwd(), type='path',
1264 help='Output directory')
1265 parser.add_argument('--reconfig', default=False, action='store_true',
1266 help='Reload crossdev config and reselect toolchains')
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001267 parser.add_argument('--sysroot', type='path',
1268 help='The sysroot in which to install the toolchains')
Mike Frysinger07534cf2017-09-12 17:40:21 -04001269 return parser
Zdenek Behan508dcce2011-12-05 15:39:32 +01001270
Mike Frysinger07534cf2017-09-12 17:40:21 -04001271
1272def main(argv):
1273 parser = GetParser()
Mike Frysinger0c808452014-11-06 17:30:23 -05001274 options = parser.parse_args(argv)
1275 options.Freeze()
Zdenek Behan508dcce2011-12-05 15:39:32 +01001276
Mike Frysinger35247af2012-11-16 18:58:06 -05001277 # Figure out what we're supposed to do and reject conflicting options.
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001278 if options.cfg_name and options.create_packages:
Mike Frysinger35247af2012-11-16 18:58:06 -05001279 parser.error('conflicting options: create-packages & show-board-cfg')
Mike Frysinger984d0622012-06-01 16:08:44 -04001280
Gilad Arnold8195b532015-04-07 10:56:30 +03001281 targets_wanted = set(options.targets.split(','))
1282 boards_wanted = (set(options.include_boards.split(','))
1283 if options.include_boards else set())
Mike Frysinger35247af2012-11-16 18:58:06 -05001284
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001285 if options.cfg_name:
1286 ShowConfig(options.cfg_name)
Mike Frysinger35247af2012-11-16 18:58:06 -05001287 elif options.create_packages:
1288 cros_build_lib.AssertInsideChroot()
1289 Crossdev.Load(False)
Gilad Arnold8195b532015-04-07 10:56:30 +03001290 CreatePackages(targets_wanted, options.output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001291 else:
1292 cros_build_lib.AssertInsideChroot()
1293 # This has to be always run as root.
1294 if os.geteuid() != 0:
1295 cros_build_lib.Die('this script must be run as root')
1296
1297 Crossdev.Load(options.reconfig)
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001298 root = options.sysroot or '/'
Mike Frysinger35247af2012-11-16 18:58:06 -05001299 UpdateToolchains(options.usepkg, options.deleteold, options.hostonly,
Gilad Arnold8195b532015-04-07 10:56:30 +03001300 options.reconfig, targets_wanted, boards_wanted,
Don Garrettc0c74002015-10-09 12:58:19 -07001301 root=root)
Mike Frysinger35247af2012-11-16 18:58:06 -05001302 Crossdev.Save()
1303
1304 return 0