blob: 34ce84a8a84ec3606bdea15ad57ee8f553cb07db [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',
Yunlian Jiangf5721f32017-10-31 11:43:11 -070057 'sys-devel/lld',
Mike Frysinger66bfde52017-09-12 16:42:57 -040058 'sys-devel/llvm',
59 'sys-kernel/linux-headers',
60 'sys-libs/glibc',
61 'sys-libs/libcxx',
62 'sys-libs/libcxxabi',
63)
64
Mike Frysinger785b0c32017-09-13 01:35:59 -040065# These packages are also installed into the host SDK. However, they require
66# the cross-compilers to be installed first (because they need them to actually
67# build), so we have to delay their installation.
68HOST_POST_CROSS_PACKAGES = (
Mike Frysinger61a24392017-10-17 17:14:27 -040069 'virtual/target-sdk-post-cross',
Mike Frysinger785b0c32017-09-13 01:35:59 -040070)
71
72# New packages that we're in the process of adding to the SDK. Since the SDK
73# bot hasn't had a chance to run yet, there are no binary packages available,
74# so we have to list them here and wait. Once it completes, entries here can
75# be removed so they'll end up on bots & dev's systems.
76NEW_PACKAGES = (
Mike Frysinger785b0c32017-09-13 01:35:59 -040077)
78
Rahul Chaudhry4b803052015-05-13 15:25:56 -070079# Enable the Go compiler for these targets.
80TARGET_GO_ENABLED = (
81 'x86_64-cros-linux-gnu',
Rahul Chaudhry4b803052015-05-13 15:25:56 -070082 'armv7a-cros-linux-gnueabi',
Yunlian Jiang16c1a422017-10-04 10:33:22 -070083 'armv7a-cros-linux-gnueabihf',
Rahul Chaudhry4d416582017-10-25 12:31:58 -070084 'aarch64-cros-linux-gnu',
Rahul Chaudhry4b803052015-05-13 15:25:56 -070085)
86CROSSDEV_GO_ARGS = ['--ex-pkg', 'dev-lang/go']
87
Manoj Gupta1b5642e2017-03-08 16:44:12 -080088# Enable llvm's compiler-rt for these targets.
89TARGET_COMPILER_RT_ENABLED = (
90 'armv7a-cros-linux-gnueabi',
Yunlian Jiang1b77ee42017-10-06 13:44:29 -070091 'armv7a-cros-linux-gnueabihf',
Manoj Gupta946abb42017-04-12 14:27:19 -070092 'aarch64-cros-linux-gnu',
Manoj Gupta21f3a082018-03-06 21:25:39 -080093 'armv7m-cros-eabi',
Manoj Gupta1b5642e2017-03-08 16:44:12 -080094)
95CROSSDEV_COMPILER_RT_ARGS = ['--ex-pkg', 'sys-libs/compiler-rt']
96
Manoj Gupta946abb42017-04-12 14:27:19 -070097TARGET_LLVM_PKGS_ENABLED = (
98 'armv7a-cros-linux-gnueabi',
Yunlian Jiang16c1a422017-10-04 10:33:22 -070099 'armv7a-cros-linux-gnueabihf',
Manoj Gupta946abb42017-04-12 14:27:19 -0700100 'aarch64-cros-linux-gnu',
101 'x86_64-cros-linux-gnu',
102)
103
104LLVM_PKGS_TABLE = {
Yunlian Jiangbb2a3d32017-04-26 14:44:09 -0700105 'ex_libcxxabi' : ['--ex-pkg', 'sys-libs/libcxxabi'],
106 'ex_libcxx' : ['--ex-pkg', 'sys-libs/libcxx'],
Manoj Gupta946abb42017-04-12 14:27:19 -0700107}
108
Zdenek Behan508dcce2011-12-05 15:39:32 +0100109# Overrides for {gcc,binutils}-config, pick a package with particular suffix.
110CONFIG_TARGET_SUFFIXES = {
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500111 'binutils' : {
Mike Frysinger8a83c622015-05-28 00:35:05 -0400112 'armv6j-cros-linux-gnueabi': '-gold',
Han Shen43b84422015-02-19 11:38:13 -0800113 'armv7a-cros-linux-gnueabi': '-gold',
Yunlian Jiang16c1a422017-10-04 10:33:22 -0700114 'armv7a-cros-linux-gnueabihf': '-gold',
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500115 'i686-pc-linux-gnu' : '-gold',
116 'x86_64-cros-linux-gnu' : '-gold',
117 },
Zdenek Behan508dcce2011-12-05 15:39:32 +0100118}
Zdenek Behan508dcce2011-12-05 15:39:32 +0100119
120
David James66a09c42012-11-05 13:31:38 -0800121class Crossdev(object):
122 """Class for interacting with crossdev and caching its output."""
123
124 _CACHE_FILE = os.path.join(CROSSDEV_OVERLAY, '.configured.json')
125 _CACHE = {}
Han Shene23782f2016-02-18 12:20:00 -0800126 # Packages that needs separate handling, in addition to what we have from
127 # crossdev.
128 MANUAL_PKGS = {
Manoj Guptaf0a602e2017-08-02 10:25:45 -0700129 'clang': 'sys-devel',
Yunlian Jiang18ae9982017-11-03 09:15:31 -0700130 'lld': 'sys-devel',
Han Shene23782f2016-02-18 12:20:00 -0800131 'llvm': 'sys-devel',
Manoj Gupta20cfc6c2017-07-19 15:49:55 -0700132 'libcxxabi': 'sys-libs',
133 'libcxx': 'sys-libs',
Han Shene23782f2016-02-18 12:20:00 -0800134 }
David James66a09c42012-11-05 13:31:38 -0800135
136 @classmethod
137 def Load(cls, reconfig):
Mike Frysinger3ed47722017-08-08 14:59:08 -0400138 """Load crossdev cache from disk.
139
140 We invalidate the cache when crossdev updates or this script changes.
141 """
David James90239b92012-11-05 15:31:34 -0800142 crossdev_version = GetStablePackageVersion('sys-devel/crossdev', True)
Mike Frysinger3ed47722017-08-08 14:59:08 -0400143 # If we run the compiled/cached .pyc file, we'll read/hash that when we
144 # really always want to track the source .py file.
145 script = os.path.abspath(__file__)
146 if script.endswith('.pyc'):
147 script = script[:-1]
148 setup_toolchains_hash = hashlib.md5(osutils.ReadFile(script)).hexdigest()
149
150 cls._CACHE = {
151 'crossdev_version': crossdev_version,
152 'setup_toolchains_hash': setup_toolchains_hash,
153 }
154
155 logging.debug('cache: checking file: %s', cls._CACHE_FILE)
156 if reconfig:
157 logging.debug('cache: forcing regen due to reconfig')
158 return
159
160 try:
161 file_data = osutils.ReadFile(cls._CACHE_FILE)
162 except IOError as e:
163 if e.errno != errno.ENOENT:
164 logging.warning('cache: reading failed: %s', e)
165 osutils.SafeUnlink(cls._CACHE_FILE)
166 return
167
168 try:
169 data = json.loads(file_data)
170 except ValueError as e:
171 logging.warning('cache: ignoring invalid content: %s', e)
172 return
173
174 if crossdev_version != data.get('crossdev_version'):
175 logging.debug('cache: rebuilding after crossdev upgrade')
176 elif setup_toolchains_hash != data.get('setup_toolchains_hash'):
177 logging.debug('cache: rebuilding after cros_setup_toolchains change')
178 else:
179 logging.debug('cache: content is up-to-date!')
180 cls._CACHE = data
David James66a09c42012-11-05 13:31:38 -0800181
182 @classmethod
183 def Save(cls):
184 """Store crossdev cache on disk."""
185 # Save the cache from the successful run.
186 with open(cls._CACHE_FILE, 'w') as f:
187 json.dump(cls._CACHE, f)
188
189 @classmethod
190 def GetConfig(cls, target):
191 """Returns a map of crossdev provided variables about a tuple."""
192 CACHE_ATTR = '_target_tuple_map'
193
194 val = cls._CACHE.setdefault(CACHE_ATTR, {})
195 if not target in val:
Mike Frysinger785b0c32017-09-13 01:35:59 -0400196 if target.startswith('host'):
Mike Frysinger66bfde52017-09-12 16:42:57 -0400197 conf = {
198 'crosspkgs': [],
199 'target': toolchain.GetHostTuple(),
200 }
Mike Frysinger785b0c32017-09-13 01:35:59 -0400201 if target == 'host':
202 packages_list = HOST_PACKAGES
203 else:
204 packages_list = HOST_POST_CROSS_PACKAGES
Mike Frysinger66bfde52017-09-12 16:42:57 -0400205 manual_pkgs = dict((pkg, cat) for cat, pkg in
Mike Frysinger785b0c32017-09-13 01:35:59 -0400206 [x.split('/') for x in packages_list])
Mike Frysinger66bfde52017-09-12 16:42:57 -0400207 else:
208 # Build the crossdev command.
209 cmd = ['crossdev', '--show-target-cfg', '--ex-gdb']
210 if target in TARGET_COMPILER_RT_ENABLED:
211 cmd.extend(CROSSDEV_COMPILER_RT_ARGS)
212 if target in TARGET_GO_ENABLED:
213 cmd.extend(CROSSDEV_GO_ARGS)
214 if target in TARGET_LLVM_PKGS_ENABLED:
215 for pkg in LLVM_PKGS_TABLE:
216 cmd.extend(LLVM_PKGS_TABLE[pkg])
217 cmd.extend(['-t', target])
218 # Catch output of crossdev.
219 out = cros_build_lib.RunCommand(
220 cmd, print_cmd=False, redirect_stdout=True).output.splitlines()
221 # List of tuples split at the first '=', converted into dict.
222 conf = dict((k, cros_build_lib.ShellUnquote(v))
223 for k, v in (x.split('=', 1) for x in out))
224 conf['crosspkgs'] = conf['crosspkgs'].split()
Han Shene23782f2016-02-18 12:20:00 -0800225
Mike Frysinger66bfde52017-09-12 16:42:57 -0400226 manual_pkgs = cls.MANUAL_PKGS
227
228 for pkg, cat in manual_pkgs.items():
Mike Frysinger3bba5032016-09-20 14:15:04 -0400229 conf[pkg + '_pn'] = pkg
230 conf[pkg + '_category'] = cat
231 if pkg not in conf['crosspkgs']:
232 conf['crosspkgs'].append(pkg)
Han Shene23782f2016-02-18 12:20:00 -0800233
234 val[target] = conf
235
David James66a09c42012-11-05 13:31:38 -0800236 return val[target]
237
238 @classmethod
239 def UpdateTargets(cls, targets, usepkg, config_only=False):
240 """Calls crossdev to initialize a cross target.
241
242 Args:
Don Garrett25f309a2014-03-19 14:02:12 -0700243 targets: The list of targets to initialize using crossdev.
244 usepkg: Copies the commandline opts.
245 config_only: Just update.
David James66a09c42012-11-05 13:31:38 -0800246 """
247 configured_targets = cls._CACHE.setdefault('configured_targets', [])
248
249 cmdbase = ['crossdev', '--show-fail-log']
250 cmdbase.extend(['--env', 'FEATURES=splitdebug'])
251 # Pick stable by default, and override as necessary.
252 cmdbase.extend(['-P', '--oneshot'])
253 if usepkg:
254 cmdbase.extend(['-P', '--getbinpkg',
255 '-P', '--usepkgonly',
256 '--without-headers'])
257
Christopher Wileyb22c0712015-06-02 10:37:03 -0700258 overlays = ' '.join((CHROMIUMOS_OVERLAY, ECLASS_OVERLAY, STABLE_OVERLAY))
David James66a09c42012-11-05 13:31:38 -0800259 cmdbase.extend(['--overlays', overlays])
260 cmdbase.extend(['--ov-output', CROSSDEV_OVERLAY])
261
Yunlian Jiang85c606a2017-10-10 20:58:53 -0700262 # Build target by the alphabetical order to make sure
263 # armv7a-cros-linux-gnueabihf builds after armv7a-cros-linux-gnueabi
264 # because some dependency issue. This can be reverted once we
265 # migrated to armv7a-cros-linux-gnueabihf. crbug.com/711369
266 for target in sorted(targets):
David James66a09c42012-11-05 13:31:38 -0800267 if config_only and target in configured_targets:
268 continue
269
270 cmd = cmdbase + ['-t', target]
271
272 for pkg in GetTargetPackages(target):
273 if pkg == 'gdb':
274 # Gdb does not have selectable versions.
275 cmd.append('--ex-gdb')
Manoj Guptab8181562017-05-21 10:18:59 -0700276 elif pkg == 'ex_compiler-rt':
277 cmd.extend(CROSSDEV_COMPILER_RT_ARGS)
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700278 elif pkg == 'ex_go':
279 # Go does not have selectable versions.
280 cmd.extend(CROSSDEV_GO_ARGS)
Manoj Gupta946abb42017-04-12 14:27:19 -0700281 elif pkg in LLVM_PKGS_TABLE:
282 cmd.extend(LLVM_PKGS_TABLE[pkg])
Han Shene23782f2016-02-18 12:20:00 -0800283 elif pkg in cls.MANUAL_PKGS:
284 pass
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700285 else:
286 # The first of the desired versions is the "primary" one.
287 version = GetDesiredPackageVersions(target, pkg)[0]
288 cmd.extend(['--%s' % pkg, version])
David James66a09c42012-11-05 13:31:38 -0800289
290 cmd.extend(targets[target]['crossdev'].split())
291 if config_only:
292 # In this case we want to just quietly reinit
293 cmd.append('--init-target')
294 cros_build_lib.RunCommand(cmd, print_cmd=False, redirect_stdout=True)
295 else:
296 cros_build_lib.RunCommand(cmd)
297
298 configured_targets.append(target)
299
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100300
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100301def GetTargetPackages(target):
302 """Returns a list of packages for a given target."""
David James66a09c42012-11-05 13:31:38 -0800303 conf = Crossdev.GetConfig(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100304 # Undesired packages are denoted by empty ${pkg}_pn variable.
Han Shene23782f2016-02-18 12:20:00 -0800305 return [x for x in conf['crosspkgs'] if conf.get(x+'_pn')]
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100306
307
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100308# Portage helper functions:
309def GetPortagePackage(target, package):
310 """Returns a package name for the given target."""
David James66a09c42012-11-05 13:31:38 -0800311 conf = Crossdev.GetConfig(target)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100312 # Portage category:
Mike Frysinger785b0c32017-09-13 01:35:59 -0400313 if target.startswith('host') or package in Crossdev.MANUAL_PKGS:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100314 category = conf[package + '_category']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100315 else:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100316 category = conf['category']
317 # Portage package:
318 pn = conf[package + '_pn']
319 # Final package name:
Mike Frysinger422faf42014-11-12 23:16:48 -0500320 assert category
321 assert pn
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100322 return '%s/%s' % (category, pn)
323
324
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700325def PortageTrees(root):
326 """Return the portage trees for a given root."""
327 if root == '/':
328 return portage.db['/']
329 # The portage logic requires the path always end in a slash.
330 root = root.rstrip('/') + '/'
331 return portage.create_trees(target_root=root, config_root=root)[root]
332
333
334def GetInstalledPackageVersions(atom, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100335 """Extracts the list of current versions of a target, package pair.
336
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500337 Args:
338 atom: The atom to operate on (e.g. sys-devel/gcc)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700339 root: The root to check for installed packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100340
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500341 Returns:
342 The list of versions of the package currently installed.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100343 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100344 versions = []
Mike Frysinger506e75f2012-12-17 14:21:13 -0500345 # pylint: disable=E1101
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700346 for pkg in PortageTrees(root)['vartree'].dbapi.match(atom, use_cache=0):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100347 version = portage.versions.cpv_getversion(pkg)
348 versions.append(version)
349 return versions
350
351
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700352def GetStablePackageVersion(atom, installed, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100353 """Extracts the current stable version for a given package.
354
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500355 Args:
356 atom: The target/package to operate on eg. i686-pc-linux-gnu,gcc
357 installed: Whether we want installed packages or ebuilds
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700358 root: The root to use when querying packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100359
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500360 Returns:
361 A string containing the latest version.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100362 """
David James90239b92012-11-05 15:31:34 -0800363 pkgtype = 'vartree' if installed else 'porttree'
Mike Frysinger506e75f2012-12-17 14:21:13 -0500364 # pylint: disable=E1101
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700365 cpv = portage.best(PortageTrees(root)[pkgtype].dbapi.match(atom, use_cache=0))
David James90239b92012-11-05 15:31:34 -0800366 return portage.versions.cpv_getversion(cpv) if cpv else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100367
368
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700369def VersionListToNumeric(target, package, versions, installed, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100370 """Resolves keywords in a given version list for a particular package.
371
372 Resolving means replacing PACKAGE_STABLE with the actual number.
373
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500374 Args:
375 target: The target to operate on (e.g. i686-pc-linux-gnu)
376 package: The target/package to operate on (e.g. gcc)
377 versions: List of versions to resolve
378 installed: Query installed packages
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700379 root: The install root to use; ignored if |installed| is False.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100380
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500381 Returns:
382 List of purely numeric versions equivalent to argument
Zdenek Behan508dcce2011-12-05 15:39:32 +0100383 """
384 resolved = []
David James90239b92012-11-05 15:31:34 -0800385 atom = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700386 if not installed:
387 root = '/'
Zdenek Behan508dcce2011-12-05 15:39:32 +0100388 for version in versions:
389 if version == PACKAGE_STABLE:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700390 resolved.append(GetStablePackageVersion(atom, installed, root=root))
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400391 else:
Zdenek Behan508dcce2011-12-05 15:39:32 +0100392 resolved.append(version)
393 return resolved
394
395
396def GetDesiredPackageVersions(target, package):
397 """Produces the list of desired versions for each target, package pair.
398
399 The first version in the list is implicitly treated as primary, ie.
400 the version that will be initialized by crossdev and selected.
401
402 If the version is PACKAGE_STABLE, it really means the current version which
403 is emerged by using the package atom with no particular version key.
404 Since crossdev unmasks all packages by default, this will actually
405 mean 'unstable' in most cases.
406
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500407 Args:
408 target: The target to operate on (e.g. i686-pc-linux-gnu)
409 package: The target/package to operate on (e.g. gcc)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100410
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500411 Returns:
412 A list composed of either a version string, PACKAGE_STABLE
Zdenek Behan508dcce2011-12-05 15:39:32 +0100413 """
Mike Frysingerd23be272017-09-12 17:18:44 -0400414 if package in GetTargetPackages(target):
415 return [PACKAGE_STABLE]
416 else:
417 return []
Zdenek Behan508dcce2011-12-05 15:39:32 +0100418
419
420def TargetIsInitialized(target):
421 """Verifies if the given list of targets has been correctly initialized.
422
423 This determines whether we have to call crossdev while emerging
424 toolchain packages or can do it using emerge. Emerge is naturally
425 preferred, because all packages can be updated in a single pass.
426
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500427 Args:
428 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100429
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500430 Returns:
431 True if |target| is completely initialized, else False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100432 """
433 # Check if packages for the given target all have a proper version.
434 try:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100435 for package in GetTargetPackages(target):
David James66a09c42012-11-05 13:31:38 -0800436 atom = GetPortagePackage(target, package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100437 # Do we even want this package && is it initialized?
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400438 if not (GetStablePackageVersion(atom, True) and
439 GetStablePackageVersion(atom, False)):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100440 return False
441 return True
442 except cros_build_lib.RunCommandError:
443 # Fails - The target has likely never been initialized before.
444 return False
445
446
447def RemovePackageMask(target):
448 """Removes a package.mask file for the given platform.
449
450 The pre-existing package.mask files can mess with the keywords.
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 """
455 maskfile = os.path.join('/etc/portage/package.mask', 'cross-' + target)
Brian Harringaf019fb2012-05-10 15:06:13 -0700456 osutils.SafeUnlink(maskfile)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100457
458
Zdenek Behan508dcce2011-12-05 15:39:32 +0100459# Main functions performing the actual update steps.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700460def RebuildLibtool(root='/'):
Mike Frysingerc880a962013-11-08 13:59:06 -0500461 """Rebuild libtool as needed
462
463 Libtool hardcodes full paths to internal gcc files, so whenever we upgrade
464 gcc, libtool will break. We can't use binary packages either as those will
465 most likely be compiled against the previous version of gcc.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700466
467 Args:
468 root: The install root where we want libtool rebuilt.
Mike Frysingerc880a962013-11-08 13:59:06 -0500469 """
470 needs_update = False
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700471 with open(os.path.join(root, 'usr/bin/libtool')) as f:
Mike Frysingerc880a962013-11-08 13:59:06 -0500472 for line in f:
473 # Look for a line like:
474 # sys_lib_search_path_spec="..."
475 # It'll be a list of paths and gcc will be one of them.
476 if line.startswith('sys_lib_search_path_spec='):
477 line = line.rstrip()
478 for path in line.split('=', 1)[1].strip('"').split():
Mike Frysinger3bba5032016-09-20 14:15:04 -0400479 root_path = os.path.join(root, path.lstrip(os.path.sep))
480 logging.debug('Libtool: checking %s', root_path)
481 if not os.path.exists(root_path):
482 logging.info('Rebuilding libtool after gcc upgrade')
483 logging.info(' %s', line)
484 logging.info(' missing path: %s', path)
Mike Frysingerc880a962013-11-08 13:59:06 -0500485 needs_update = True
486 break
487
488 if needs_update:
489 break
490
491 if needs_update:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700492 cmd = [EMERGE_CMD, '--oneshot']
493 if root != '/':
494 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
495 cmd.append('sys-devel/libtool')
Mike Frysingerc880a962013-11-08 13:59:06 -0500496 cros_build_lib.RunCommand(cmd)
Mike Frysinger3bba5032016-09-20 14:15:04 -0400497 else:
498 logging.debug('Libtool is up-to-date; no need to rebuild')
Mike Frysingerc880a962013-11-08 13:59:06 -0500499
500
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700501def UpdateTargets(targets, usepkg, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100502 """Determines which packages need update/unmerge and defers to portage.
503
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500504 Args:
505 targets: The list of targets to update
506 usepkg: Copies the commandline option
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700507 root: The install root in which we want packages updated.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100508 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100509 # For each target, we do two things. Figure out the list of updates,
510 # and figure out the appropriate keywords/masks. Crossdev will initialize
511 # these, but they need to be regenerated on every update.
Mike Frysinger3bba5032016-09-20 14:15:04 -0400512 logging.info('Determining required toolchain updates...')
David James90239b92012-11-05 15:31:34 -0800513 mergemap = {}
Zdenek Behan508dcce2011-12-05 15:39:32 +0100514 for target in targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400515 logging.debug('Updating target %s', target)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100516 # Record the highest needed version for each target, for masking purposes.
517 RemovePackageMask(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100518 for package in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100519 # Portage name for the package
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400520 logging.debug(' Checking package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100521 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700522 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100523 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200524 desired_num = VersionListToNumeric(target, package, desired, False)
Mike Frysinger785b0c32017-09-13 01:35:59 -0400525 if pkg in NEW_PACKAGES and usepkg:
526 # Skip this binary package (for now).
527 continue
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100528 mergemap[pkg] = set(desired_num).difference(current)
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400529 logging.debug(' %s -> %s', current, desired_num)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100530
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400531 packages = [pkg for pkg, vers in mergemap.items() if vers]
Zdenek Behan508dcce2011-12-05 15:39:32 +0100532 if not packages:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400533 logging.info('Nothing to update!')
David Jamesf8c672f2012-11-06 13:38:11 -0800534 return False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100535
Mike Frysinger3bba5032016-09-20 14:15:04 -0400536 logging.info('Updating packages:')
537 logging.info('%s', packages)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100538
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100539 cmd = [EMERGE_CMD, '--oneshot', '--update']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100540 if usepkg:
541 cmd.extend(['--getbinpkg', '--usepkgonly'])
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700542 if root != '/':
543 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100544
545 cmd.extend(packages)
546 cros_build_lib.RunCommand(cmd)
David Jamesf8c672f2012-11-06 13:38:11 -0800547 return True
Zdenek Behan508dcce2011-12-05 15:39:32 +0100548
549
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700550def CleanTargets(targets, root='/'):
551 """Unmerges old packages that are assumed unnecessary.
552
553 Args:
554 targets: The list of targets to clean up.
555 root: The install root in which we want packages cleaned up.
556 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100557 unmergemap = {}
558 for target in targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400559 logging.debug('Cleaning target %s', target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100560 for package in GetTargetPackages(target):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400561 logging.debug(' Cleaning package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100562 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700563 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100564 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2fcb0aa2015-05-21 14:51:41 -0700565 # NOTE: This refers to installed packages (vartree) rather than the
566 # Portage version (porttree and/or bintree) when determining the current
567 # version. While this isn't the most accurate thing to do, it is probably
568 # a good simple compromise, which should have the desired result of
569 # uninstalling everything but the latest installed version. In
570 # particular, using the bintree (--usebinpkg) requires a non-trivial
571 # binhost sync and is probably more complex than useful.
Zdenek Behan699ddd32012-04-13 07:14:08 +0200572 desired_num = VersionListToNumeric(target, package, desired, True)
573 if not set(desired_num).issubset(current):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400574 logging.warning('Error detecting stable version for %s, '
575 'skipping clean!', pkg)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200576 return
Zdenek Behan508dcce2011-12-05 15:39:32 +0100577 unmergemap[pkg] = set(current).difference(desired_num)
578
579 # Cleaning doesn't care about consistency and rebuilding package.* files.
580 packages = []
581 for pkg, vers in unmergemap.iteritems():
582 packages.extend('=%s-%s' % (pkg, ver) for ver in vers if ver != '9999')
583
584 if packages:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400585 logging.info('Cleaning packages:')
586 logging.info('%s', packages)
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100587 cmd = [EMERGE_CMD, '--unmerge']
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700588 if root != '/':
589 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100590 cmd.extend(packages)
591 cros_build_lib.RunCommand(cmd)
592 else:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400593 logging.info('Nothing to clean!')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100594
595
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700596def SelectActiveToolchains(targets, suffixes, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100597 """Runs gcc-config and binutils-config to select the desired.
598
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500599 Args:
600 targets: The targets to select
601 suffixes: Optional target-specific hacks
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700602 root: The root where we want to select toolchain versions.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100603 """
604 for package in ['gcc', 'binutils']:
605 for target in targets:
Mike Frysinger785b0c32017-09-13 01:35:59 -0400606 # See if this package is part of this target.
607 if package not in GetTargetPackages(target):
608 logging.debug('%s: %s is not used', target, package)
609 continue
610
Zdenek Behan508dcce2011-12-05 15:39:32 +0100611 # Pick the first version in the numbered list as the selected one.
612 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700613 desired_num = VersionListToNumeric(target, package, desired, True,
614 root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100615 desired = desired_num[0]
616 # *-config does not play revisions, strip them, keep just PV.
617 desired = portage.versions.pkgsplit('%s-%s' % (package, desired))[1]
618
Mike Frysinger785b0c32017-09-13 01:35:59 -0400619 if target.startswith('host'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100620 # *-config is the only tool treating host identically (by tuple).
David James27ac4ae2012-12-03 23:16:15 -0800621 target = toolchain.GetHostTuple()
Zdenek Behan508dcce2011-12-05 15:39:32 +0100622
623 # And finally, attach target to it.
624 desired = '%s-%s' % (target, desired)
625
626 # Target specific hacks
627 if package in suffixes:
628 if target in suffixes[package]:
629 desired += suffixes[package][target]
630
David James7ec5efc2012-11-06 09:39:49 -0800631 extra_env = {'CHOST': target}
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700632 if root != '/':
633 extra_env['ROOT'] = root
David James7ec5efc2012-11-06 09:39:49 -0800634 cmd = ['%s-config' % package, '-c', target]
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500635 result = cros_build_lib.RunCommand(
636 cmd, print_cmd=False, redirect_stdout=True, extra_env=extra_env)
637 current = result.output.splitlines()[0]
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700638
639 # Do not reconfig when the current is live or nothing needs to be done.
640 extra_env = {'ROOT': root} if root != '/' else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100641 if current != desired and current != '9999':
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500642 cmd = [package + '-config', desired]
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700643 cros_build_lib.RunCommand(cmd, print_cmd=False, extra_env=extra_env)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100644
645
Mike Frysinger35247af2012-11-16 18:58:06 -0500646def ExpandTargets(targets_wanted):
647 """Expand any possible toolchain aliases into full targets
648
649 This will expand 'all' and 'sdk' into the respective toolchain tuples.
650
651 Args:
652 targets_wanted: The targets specified by the user.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500653
Mike Frysinger35247af2012-11-16 18:58:06 -0500654 Returns:
Gilad Arnold8195b532015-04-07 10:56:30 +0300655 Dictionary of concrete targets and their toolchain tuples.
Mike Frysinger35247af2012-11-16 18:58:06 -0500656 """
Mike Frysinger35247af2012-11-16 18:58:06 -0500657 targets_wanted = set(targets_wanted)
Don Garrettc0c74002015-10-09 12:58:19 -0700658 if targets_wanted == set(['boards']):
659 # Only pull targets from the included boards.
Gilad Arnold8195b532015-04-07 10:56:30 +0300660 return {}
661
662 all_targets = toolchain.GetAllTargets()
Mike Frysinger35247af2012-11-16 18:58:06 -0500663 if targets_wanted == set(['all']):
Gilad Arnold8195b532015-04-07 10:56:30 +0300664 return all_targets
665 if targets_wanted == set(['sdk']):
Mike Frysinger35247af2012-11-16 18:58:06 -0500666 # Filter out all the non-sdk toolchains as we don't want to mess
667 # with those in all of our builds.
Gilad Arnold8195b532015-04-07 10:56:30 +0300668 return toolchain.FilterToolchains(all_targets, 'sdk', True)
669
670 # Verify user input.
671 nonexistent = targets_wanted.difference(all_targets)
672 if nonexistent:
673 raise ValueError('Invalid targets: %s', ','.join(nonexistent))
674 return {t: all_targets[t] for t in targets_wanted}
Mike Frysinger35247af2012-11-16 18:58:06 -0500675
676
David Jamesf8c672f2012-11-06 13:38:11 -0800677def UpdateToolchains(usepkg, deleteold, hostonly, reconfig,
Don Garrettc0c74002015-10-09 12:58:19 -0700678 targets_wanted, boards_wanted, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100679 """Performs all steps to create a synchronized toolchain enviroment.
680
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500681 Args:
682 usepkg: Use prebuilt packages
683 deleteold: Unmerge deprecated packages
684 hostonly: Only setup the host toolchain
685 reconfig: Reload crossdev config and reselect toolchains
686 targets_wanted: All the targets to update
687 boards_wanted: Load targets from these boards
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700688 root: The root in which to install the toolchains.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100689 """
David Jamesf8c672f2012-11-06 13:38:11 -0800690 targets, crossdev_targets, reconfig_targets = {}, {}, {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100691 if not hostonly:
692 # For hostonly, we can skip most of the below logic, much of which won't
693 # work on bare systems where this is useful.
Mike Frysinger35247af2012-11-16 18:58:06 -0500694 targets = ExpandTargets(targets_wanted)
Mike Frysinger7ccee992012-06-01 21:27:59 -0400695
Don Garrettc0c74002015-10-09 12:58:19 -0700696 # Now re-add any targets that might be from this board. This is to
Gilad Arnold8195b532015-04-07 10:56:30 +0300697 # allow unofficial boards to declare their own toolchains.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400698 for board in boards_wanted:
David James27ac4ae2012-12-03 23:16:15 -0800699 targets.update(toolchain.GetToolchainsForBoard(board))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100700
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100701 # First check and initialize all cross targets that need to be.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400702 for target in targets:
703 if TargetIsInitialized(target):
704 reconfig_targets[target] = targets[target]
705 else:
706 crossdev_targets[target] = targets[target]
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100707 if crossdev_targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400708 logging.info('The following targets need to be re-initialized:')
709 logging.info('%s', crossdev_targets)
David James66a09c42012-11-05 13:31:38 -0800710 Crossdev.UpdateTargets(crossdev_targets, usepkg)
Zdenek Behan8be29ba2012-05-29 23:10:34 +0200711 # Those that were not initialized may need a config update.
David James66a09c42012-11-05 13:31:38 -0800712 Crossdev.UpdateTargets(reconfig_targets, usepkg, config_only=True)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100713
Mike Frysinger66814c32017-10-09 18:11:46 -0400714 # If we're building a subset of toolchains for a board, we might not have
715 # all the tuples that the packages expect. We don't define the "full" set
716 # of tuples currently other than "whatever the full sdk has normally".
717 if usepkg or set(('all', 'sdk')) & targets_wanted:
718 # Since we have cross-compilers now, we can update these packages.
719 targets['host-post-cross'] = {}
Mike Frysinger785b0c32017-09-13 01:35:59 -0400720
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100721 # We want host updated.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400722 targets['host'] = {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100723
724 # Now update all packages.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700725 if UpdateTargets(targets, usepkg, root=root) or crossdev_targets or reconfig:
726 SelectActiveToolchains(targets, CONFIG_TARGET_SUFFIXES, root=root)
David James7ec5efc2012-11-06 09:39:49 -0800727
728 if deleteold:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700729 CleanTargets(targets, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100730
Mike Frysingerc880a962013-11-08 13:59:06 -0500731 # Now that we've cleared out old versions, see if we need to rebuild
732 # anything. Can't do this earlier as it might not be broken.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700733 RebuildLibtool(root=root)
Mike Frysingerc880a962013-11-08 13:59:06 -0500734
Zdenek Behan508dcce2011-12-05 15:39:32 +0100735
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -0700736def ShowConfig(name):
737 """Show the toolchain tuples used by |name|
Mike Frysinger35247af2012-11-16 18:58:06 -0500738
739 Args:
Don Garrettc0c74002015-10-09 12:58:19 -0700740 name: The board name to query.
Mike Frysinger35247af2012-11-16 18:58:06 -0500741 """
Don Garrettc0c74002015-10-09 12:58:19 -0700742 toolchains = toolchain.GetToolchainsForBoard(name)
Mike Frysinger35247af2012-11-16 18:58:06 -0500743 # Make sure we display the default toolchain first.
Mike Frysinger3bba5032016-09-20 14:15:04 -0400744 # Note: Do not use logging here as this is meant to be used by other tools.
Mike Frysinger383367e2014-09-16 15:06:17 -0400745 print(','.join(
David James27ac4ae2012-12-03 23:16:15 -0800746 toolchain.FilterToolchains(toolchains, 'default', True).keys() +
Mike Frysinger383367e2014-09-16 15:06:17 -0400747 toolchain.FilterToolchains(toolchains, 'default', False).keys()))
Mike Frysinger35247af2012-11-16 18:58:06 -0500748
749
Mike Frysinger35247af2012-11-16 18:58:06 -0500750def GeneratePathWrapper(root, wrappath, path):
751 """Generate a shell script to execute another shell script
752
753 Since we can't symlink a wrapped ELF (see GenerateLdsoWrapper) because the
754 argv[0] won't be pointing to the correct path, generate a shell script that
755 just executes another program with its full path.
756
757 Args:
758 root: The root tree to generate scripts inside of
759 wrappath: The full path (inside |root|) to create the wrapper
760 path: The target program which this wrapper will execute
761 """
762 replacements = {
763 'path': path,
764 'relroot': os.path.relpath('/', os.path.dirname(wrappath)),
765 }
766 wrapper = """#!/bin/sh
767base=$(realpath "$0")
768basedir=${base%%/*}
769exec "${basedir}/%(relroot)s%(path)s" "$@"
770""" % replacements
771 root_wrapper = root + wrappath
772 if os.path.islink(root_wrapper):
773 os.unlink(root_wrapper)
774 else:
775 osutils.SafeMakedirs(os.path.dirname(root_wrapper))
776 osutils.WriteFile(root_wrapper, wrapper)
Mike Frysinger60ec1012013-10-21 00:11:10 -0400777 os.chmod(root_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -0500778
779
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -0700780def FixClangXXWrapper(root, path):
781 """Fix wrapper shell scripts and symlinks for invoking clang++
782
783 In a typical installation, clang++ symlinks to clang, which symlinks to the
784 elf executable. The executable distinguishes between clang and clang++ based
785 on argv[0].
786
787 When invoked through the LdsoWrapper, argv[0] always contains the path to the
788 executable elf file, making clang/clang++ invocations indistinguishable.
789
790 This function detects if the elf executable being wrapped is clang-X.Y, and
791 fixes wrappers/symlinks as necessary so that clang++ will work correctly.
792
793 The calling sequence now becomes:
794 -) clang++ invocation turns into clang++-3.9 (which is a copy of clang-3.9,
795 the Ldsowrapper).
796 -) clang++-3.9 uses the Ldso to invoke clang++-3.9.elf, which is a symlink
797 to the original clang-3.9 elf.
798 -) The difference this time is that inside the elf file execution, $0 is
799 set as .../usr/bin/clang++-3.9.elf, which contains 'clang++' in the name.
800
801 Args:
802 root: The root tree to generate scripts / symlinks inside of
803 path: The target elf for which LdsoWrapper was created
804 """
805 if re.match(r'/usr/bin/clang-\d+\.\d+$', path):
806 logging.info('fixing clang++ invocation for %s', path)
807 clangdir = os.path.dirname(root + path)
808 clang = os.path.basename(path)
809 clangxx = clang.replace('clang', 'clang++')
810
811 # Create a symlink clang++-X.Y.elf to point to clang-X.Y.elf
812 os.symlink(clang + '.elf', os.path.join(clangdir, clangxx + '.elf'))
813
814 # Create a hardlink clang++-X.Y pointing to clang-X.Y
815 os.link(os.path.join(clangdir, clang), os.path.join(clangdir, clangxx))
816
817 # Adjust the clang++ symlink to point to clang++-X.Y
818 os.unlink(os.path.join(clangdir, 'clang++'))
819 os.symlink(clangxx, os.path.join(clangdir, 'clang++'))
820
821
Mike Frysinger35247af2012-11-16 18:58:06 -0500822def FileIsCrosSdkElf(elf):
823 """Determine if |elf| is an ELF that we execute in the cros_sdk
824
825 We don't need this to be perfect, just quick. It makes sure the ELF
826 is a 64bit LSB x86_64 ELF. That is the native type of cros_sdk.
827
828 Args:
829 elf: The file to check
Mike Frysinger1a736a82013-12-12 01:50:59 -0500830
Mike Frysinger35247af2012-11-16 18:58:06 -0500831 Returns:
832 True if we think |elf| is a native ELF
833 """
834 with open(elf) as f:
835 data = f.read(20)
836 # Check the magic number, EI_CLASS, EI_DATA, and e_machine.
837 return (data[0:4] == '\x7fELF' and
838 data[4] == '\x02' and
839 data[5] == '\x01' and
840 data[18] == '\x3e')
841
842
843def IsPathPackagable(ptype, path):
844 """Should the specified file be included in a toolchain package?
845
846 We only need to handle files as we'll create dirs as we need them.
847
848 Further, trim files that won't be useful:
849 - non-english translations (.mo) since it'd require env vars
850 - debug files since these are for the host compiler itself
851 - info/man pages as they're big, and docs are online, and the
852 native docs should work fine for the most part (`man gcc`)
853
854 Args:
855 ptype: A string describing the path type (i.e. 'file' or 'dir' or 'sym')
856 path: The full path to inspect
Mike Frysinger1a736a82013-12-12 01:50:59 -0500857
Mike Frysinger35247af2012-11-16 18:58:06 -0500858 Returns:
859 True if we want to include this path in the package
860 """
861 return not (ptype in ('dir',) or
862 path.startswith('/usr/lib/debug/') or
863 os.path.splitext(path)[1] == '.mo' or
864 ('/man/' in path or '/info/' in path))
865
866
867def ReadlinkRoot(path, root):
868 """Like os.readlink(), but relative to a |root|
869
870 Args:
871 path: The symlink to read
872 root: The path to use for resolving absolute symlinks
Mike Frysinger1a736a82013-12-12 01:50:59 -0500873
Mike Frysinger35247af2012-11-16 18:58:06 -0500874 Returns:
875 A fully resolved symlink path
876 """
877 while os.path.islink(root + path):
878 path = os.path.join(os.path.dirname(path), os.readlink(root + path))
879 return path
880
881
882def _GetFilesForTarget(target, root='/'):
883 """Locate all the files to package for |target|
884
885 This does not cover ELF dependencies.
886
887 Args:
888 target: The toolchain target name
889 root: The root path to pull all packages from
Mike Frysinger1a736a82013-12-12 01:50:59 -0500890
Mike Frysinger35247af2012-11-16 18:58:06 -0500891 Returns:
892 A tuple of a set of all packable paths, and a set of all paths which
893 are also native ELFs
894 """
895 paths = set()
896 elfs = set()
897
898 # Find all the files owned by the packages for this target.
899 for pkg in GetTargetPackages(target):
Mike Frysinger35247af2012-11-16 18:58:06 -0500900
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700901 # Skip Go compiler from redistributable packages.
902 # The "go" executable has GOROOT=/usr/lib/go/${CTARGET} hardcoded
903 # into it. Due to this, the toolchain cannot be unpacked anywhere
904 # else and be readily useful. To enable packaging Go, we need to:
905 # -) Tweak the wrappers/environment to override GOROOT
906 # automatically based on the unpack location.
907 # -) Make sure the ELF dependency checking and wrapping logic
908 # below skips the Go toolchain executables and libraries.
909 # -) Make sure the packaging process maintains the relative
910 # timestamps of precompiled standard library packages.
911 # (see dev-lang/go ebuild for details).
912 if pkg == 'ex_go':
913 continue
914
Mike Frysinger35247af2012-11-16 18:58:06 -0500915 atom = GetPortagePackage(target, pkg)
916 cat, pn = atom.split('/')
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700917 ver = GetInstalledPackageVersions(atom, root=root)[0]
Ralph Nathan03047282015-03-23 11:09:32 -0700918 logging.info('packaging %s-%s', atom, ver)
Mike Frysinger35247af2012-11-16 18:58:06 -0500919
920 # pylint: disable=E1101
921 dblink = portage.dblink(cat, pn + '-' + ver, myroot=root,
922 settings=portage.settings)
923 contents = dblink.getcontents()
924 for obj in contents:
925 ptype = contents[obj][0]
926 if not IsPathPackagable(ptype, obj):
927 continue
928
929 if ptype == 'obj':
930 # For native ELFs, we need to pull in their dependencies too.
931 if FileIsCrosSdkElf(obj):
932 elfs.add(obj)
933 paths.add(obj)
934
935 return paths, elfs
936
937
938def _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500939 path_rewrite_func=lambda x: x, root='/'):
Mike Frysinger35247af2012-11-16 18:58:06 -0500940 """Link in all packable files and their runtime dependencies
941
942 This also wraps up executable ELFs with helper scripts.
943
944 Args:
945 output_dir: The output directory to store files
946 paths: All the files to include
947 elfs: All the files which are ELFs (a subset of |paths|)
948 ldpaths: A dict of static ldpath information
949 path_rewrite_func: User callback to rewrite paths in output_dir
950 root: The root path to pull all packages/files from
951 """
952 # Link in all the files.
Mike Frysinger221bd822017-09-29 02:51:47 -0400953 sym_paths = {}
Mike Frysinger35247af2012-11-16 18:58:06 -0500954 for path in paths:
955 new_path = path_rewrite_func(path)
956 dst = output_dir + new_path
957 osutils.SafeMakedirs(os.path.dirname(dst))
958
959 # Is this a symlink which we have to rewrite or wrap?
960 # Delay wrap check until after we have created all paths.
961 src = root + path
962 if os.path.islink(src):
963 tgt = os.readlink(src)
964 if os.path.sep in tgt:
Mike Frysinger221bd822017-09-29 02:51:47 -0400965 sym_paths[lddtree.normpath(ReadlinkRoot(src, root))] = new_path
Mike Frysinger35247af2012-11-16 18:58:06 -0500966
967 # Rewrite absolute links to relative and then generate the symlink
968 # ourselves. All other symlinks can be hardlinked below.
969 if tgt[0] == '/':
970 tgt = os.path.relpath(tgt, os.path.dirname(new_path))
971 os.symlink(tgt, dst)
972 continue
973
974 os.link(src, dst)
975
Mike Frysinger35247af2012-11-16 18:58:06 -0500976 # Locate all the dependencies for all the ELFs. Stick them all in the
977 # top level "lib" dir to make the wrapper simpler. This exact path does
978 # not matter since we execute ldso directly, and we tell the ldso the
979 # exact path to search for its libraries.
980 libdir = os.path.join(output_dir, 'lib')
981 osutils.SafeMakedirs(libdir)
982 donelibs = set()
Mike Frysinger4331fc62017-09-28 14:03:25 -0400983 glibc_re = re.compile(r'/lib(c|pthread)-[0-9.]+\.so$')
Mike Frysinger35247af2012-11-16 18:58:06 -0500984 for elf in elfs:
Mike Frysingerea7688e2014-07-31 22:40:33 -0400985 e = lddtree.ParseELF(elf, root=root, ldpaths=ldpaths)
Mike Frysinger35247af2012-11-16 18:58:06 -0500986 interp = e['interp']
Yunlian Jiang196e8f42017-09-20 12:29:47 -0700987 # Do not create wrapper for libc. crbug.com/766827
988 if interp and not glibc_re.search(elf):
Mike Frysinger35247af2012-11-16 18:58:06 -0500989 # Generate a wrapper if it is executable.
Mike Frysingerc2ec0902013-03-26 01:28:45 -0400990 interp = os.path.join('/lib', os.path.basename(interp))
991 lddtree.GenerateLdsoWrapper(output_dir, path_rewrite_func(elf), interp,
992 libpaths=e['rpath'] + e['runpath'])
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -0700993 FixClangXXWrapper(output_dir, path_rewrite_func(elf))
Mike Frysinger35247af2012-11-16 18:58:06 -0500994
Mike Frysinger221bd822017-09-29 02:51:47 -0400995 # Wrap any symlinks to the wrapper.
996 if elf in sym_paths:
997 link = sym_paths[elf]
998 GeneratePathWrapper(output_dir, link, elf)
999
Mike Frysinger35247af2012-11-16 18:58:06 -05001000 for lib, lib_data in e['libs'].iteritems():
1001 if lib in donelibs:
1002 continue
1003
1004 src = path = lib_data['path']
1005 if path is None:
Ralph Nathan446aee92015-03-23 14:44:56 -07001006 logging.warning('%s: could not locate %s', elf, lib)
Mike Frysinger35247af2012-11-16 18:58:06 -05001007 continue
1008 donelibs.add(lib)
1009
1010 # Needed libs are the SONAME, but that is usually a symlink, not a
1011 # real file. So link in the target rather than the symlink itself.
1012 # We have to walk all the possible symlinks (SONAME could point to a
1013 # symlink which points to a symlink), and we have to handle absolute
1014 # ourselves (since we have a "root" argument).
1015 dst = os.path.join(libdir, os.path.basename(path))
1016 src = ReadlinkRoot(src, root)
1017
1018 os.link(root + src, dst)
1019
1020
1021def _EnvdGetVar(envd, var):
1022 """Given a Gentoo env.d file, extract a var from it
1023
1024 Args:
1025 envd: The env.d file to load (may be a glob path)
1026 var: The var to extract
Mike Frysinger1a736a82013-12-12 01:50:59 -05001027
Mike Frysinger35247af2012-11-16 18:58:06 -05001028 Returns:
1029 The value of |var|
1030 """
1031 envds = glob.glob(envd)
1032 assert len(envds) == 1, '%s: should have exactly 1 env.d file' % envd
1033 envd = envds[0]
1034 return cros_build_lib.LoadKeyValueFile(envd)[var]
1035
1036
1037def _ProcessBinutilsConfig(target, output_dir):
1038 """Do what binutils-config would have done"""
1039 binpath = os.path.join('/bin', target + '-')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001040
1041 # Locate the bin dir holding the gold linker.
1042 binutils_bin_path = os.path.join(output_dir, 'usr', toolchain.GetHostTuple(),
1043 target, 'binutils-bin')
1044 globpath = os.path.join(binutils_bin_path, '*-gold')
Mike Frysinger35247af2012-11-16 18:58:06 -05001045 srcpath = glob.glob(globpath)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001046 if not srcpath:
1047 # Maybe this target doesn't support gold.
1048 globpath = os.path.join(binutils_bin_path, '*')
1049 srcpath = glob.glob(globpath)
1050 assert len(srcpath) == 1, ('%s: matched more than one path (but not *-gold)'
1051 % globpath)
1052 srcpath = srcpath[0]
1053 ld_path = os.path.join(srcpath, 'ld')
1054 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1055 ld_path = os.path.join(srcpath, 'ld.bfd')
1056 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1057 ld_path = os.path.join(srcpath, 'ld.gold')
1058 assert not os.path.exists(ld_path), ('%s: exists, but gold dir does not!'
1059 % ld_path)
1060
1061 # Nope, no gold support to be found.
1062 gold_supported = False
Ralph Nathan446aee92015-03-23 14:44:56 -07001063 logging.warning('%s: binutils lacks support for the gold linker', target)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001064 else:
1065 assert len(srcpath) == 1, '%s: did not match exactly 1 path' % globpath
Mike Frysinger78b7a812014-11-26 19:45:23 -05001066 srcpath = srcpath[0]
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001067
Rahul Chaudhry4891b4d2017-03-08 10:31:27 -08001068 # Package the binutils-bin directory without the '-gold' suffix
1069 # if gold is not enabled as the default linker for this target.
1070 gold_supported = CONFIG_TARGET_SUFFIXES['binutils'].get(target) == '-gold'
1071 if not gold_supported:
1072 srcpath = srcpath[:-len('-gold')]
1073 ld_path = os.path.join(srcpath, 'ld')
1074 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1075
Mike Frysinger78b7a812014-11-26 19:45:23 -05001076 srcpath = srcpath[len(output_dir):]
Mike Frysinger35247af2012-11-16 18:58:06 -05001077 gccpath = os.path.join('/usr', 'libexec', 'gcc')
1078 for prog in os.listdir(output_dir + srcpath):
1079 # Skip binaries already wrapped.
1080 if not prog.endswith('.real'):
1081 GeneratePathWrapper(output_dir, binpath + prog,
1082 os.path.join(srcpath, prog))
1083 GeneratePathWrapper(output_dir, os.path.join(gccpath, prog),
1084 os.path.join(srcpath, prog))
1085
David James27ac4ae2012-12-03 23:16:15 -08001086 libpath = os.path.join('/usr', toolchain.GetHostTuple(), target, 'lib')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001087 envd = os.path.join(output_dir, 'etc', 'env.d', 'binutils', '*')
1088 if gold_supported:
1089 envd += '-gold'
Rahul Chaudhry4891b4d2017-03-08 10:31:27 -08001090 else:
1091 # If gold is not enabled as the default linker and 2 env.d
1092 # files exist, pick the one without the '-gold' suffix.
1093 envds = sorted(glob.glob(envd))
1094 if len(envds) == 2 and envds[1] == envds[0] + '-gold':
1095 envd = envds[0]
Mike Frysinger35247af2012-11-16 18:58:06 -05001096 srcpath = _EnvdGetVar(envd, 'LIBPATH')
1097 os.symlink(os.path.relpath(srcpath, os.path.dirname(libpath)),
1098 output_dir + libpath)
1099
1100
1101def _ProcessGccConfig(target, output_dir):
1102 """Do what gcc-config would have done"""
1103 binpath = '/bin'
1104 envd = os.path.join(output_dir, 'etc', 'env.d', 'gcc', '*')
1105 srcpath = _EnvdGetVar(envd, 'GCC_PATH')
1106 for prog in os.listdir(output_dir + srcpath):
1107 # Skip binaries already wrapped.
1108 if (not prog.endswith('.real') and
1109 not prog.endswith('.elf') and
1110 prog.startswith(target)):
1111 GeneratePathWrapper(output_dir, os.path.join(binpath, prog),
1112 os.path.join(srcpath, prog))
1113 return srcpath
1114
1115
Frank Henigman179ec7c2015-02-06 03:01:09 -05001116def _ProcessSysrootWrappers(_target, output_dir, srcpath):
1117 """Remove chroot-specific things from our sysroot wrappers"""
Mike Frysinger35247af2012-11-16 18:58:06 -05001118 # Disable ccache since we know it won't work outside of chroot.
Frank Henigman179ec7c2015-02-06 03:01:09 -05001119 for sysroot_wrapper in glob.glob(os.path.join(
1120 output_dir + srcpath, 'sysroot_wrapper*')):
1121 contents = osutils.ReadFile(sysroot_wrapper).splitlines()
Douglas Andersoncc828a52017-10-13 13:07:25 -07001122
1123 # In order to optimize startup time in the chroot we run python a little
1124 # differently there. Put it back to the more portable way here.
1125 # See http://crbug.com/773138 for some details.
1126 if contents[0] == '#!/usr/bin/python2 -S':
1127 contents[0] = '#!/usr/bin/env python2'
1128
Frank Henigman179ec7c2015-02-06 03:01:09 -05001129 for num in xrange(len(contents)):
1130 if '@CCACHE_DEFAULT@' in contents[num]:
Caroline Ticece9e9232017-06-02 09:38:42 -07001131 assert 'True' in contents[num]
1132 contents[num] = contents[num].replace('True', 'False')
Frank Henigman179ec7c2015-02-06 03:01:09 -05001133 break
1134 # Can't update the wrapper in place since it's a hardlink to a file in /.
1135 os.unlink(sysroot_wrapper)
1136 osutils.WriteFile(sysroot_wrapper, '\n'.join(contents))
1137 os.chmod(sysroot_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -05001138
1139
Yunlian Jiang5ad6b512017-09-20 09:27:45 -07001140def _CreateMainLibDir(target, output_dir):
1141 """Create some lib dirs so that compiler can get the right Gcc paths"""
1142 osutils.SafeMakedirs(os.path.join(output_dir, 'usr', target, 'lib'))
1143 osutils.SafeMakedirs(os.path.join(output_dir, 'usr', target, 'usr/lib'))
1144
1145
Mike Frysinger35247af2012-11-16 18:58:06 -05001146def _ProcessDistroCleanups(target, output_dir):
1147 """Clean up the tree and remove all distro-specific requirements
1148
1149 Args:
1150 target: The toolchain target name
1151 output_dir: The output directory to clean up
1152 """
1153 _ProcessBinutilsConfig(target, output_dir)
1154 gcc_path = _ProcessGccConfig(target, output_dir)
Frank Henigman179ec7c2015-02-06 03:01:09 -05001155 _ProcessSysrootWrappers(target, output_dir, gcc_path)
Yunlian Jiang5ad6b512017-09-20 09:27:45 -07001156 _CreateMainLibDir(target, output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001157
1158 osutils.RmDir(os.path.join(output_dir, 'etc'))
1159
1160
1161def CreatePackagableRoot(target, output_dir, ldpaths, root='/'):
1162 """Setup a tree from the packages for the specified target
1163
1164 This populates a path with all the files from toolchain packages so that
1165 a tarball can easily be generated from the result.
1166
1167 Args:
1168 target: The target to create a packagable root from
1169 output_dir: The output directory to place all the files
1170 ldpaths: A dict of static ldpath information
1171 root: The root path to pull all packages/files from
1172 """
1173 # Find all the files owned by the packages for this target.
1174 paths, elfs = _GetFilesForTarget(target, root=root)
1175
1176 # Link in all the package's files, any ELF dependencies, and wrap any
1177 # executable ELFs with helper scripts.
1178 def MoveUsrBinToBin(path):
Han Shen699ea192016-03-02 10:42:47 -08001179 """Move /usr/bin to /bin so people can just use that toplevel dir
1180
1181 Note we do not apply this to clang - there is correlation between clang's
1182 search path for libraries / inclusion and its installation path.
1183 """
1184 if path.startswith('/usr/bin/') and path.find('clang') == -1:
1185 return path[4:]
1186 return path
Mike Frysinger35247af2012-11-16 18:58:06 -05001187 _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
1188 path_rewrite_func=MoveUsrBinToBin, root=root)
1189
1190 # The packages, when part of the normal distro, have helper scripts
1191 # that setup paths and such. Since we are making this standalone, we
1192 # need to preprocess all that ourselves.
1193 _ProcessDistroCleanups(target, output_dir)
1194
1195
1196def CreatePackages(targets_wanted, output_dir, root='/'):
1197 """Create redistributable cross-compiler packages for the specified targets
1198
1199 This creates toolchain packages that should be usable in conjunction with
1200 a downloaded sysroot (created elsewhere).
1201
1202 Tarballs (one per target) will be created in $PWD.
1203
1204 Args:
Don Garrett25f309a2014-03-19 14:02:12 -07001205 targets_wanted: The targets to package up.
1206 output_dir: The directory to put the packages in.
1207 root: The root path to pull all packages/files from.
Mike Frysinger35247af2012-11-16 18:58:06 -05001208 """
Ralph Nathan03047282015-03-23 11:09:32 -07001209 logging.info('Writing tarballs to %s', output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001210 osutils.SafeMakedirs(output_dir)
1211 ldpaths = lddtree.LoadLdpaths(root)
1212 targets = ExpandTargets(targets_wanted)
1213
Mike Frysinger221bd822017-09-29 02:51:47 -04001214 with osutils.TempDir(prefix='create-packages') as tempdir:
1215 logging.debug('Using tempdir: %s', tempdir)
1216
Mike Frysinger35247af2012-11-16 18:58:06 -05001217 # We have to split the root generation from the compression stages. This is
1218 # because we hardlink in all the files (to avoid overhead of reading/writing
1219 # the copies multiple times). But tar gets angry if a file's hardlink count
1220 # changes from when it starts reading a file to when it finishes.
1221 with parallel.BackgroundTaskRunner(CreatePackagableRoot) as queue:
1222 for target in targets:
1223 output_target_dir = os.path.join(tempdir, target)
1224 queue.put([target, output_target_dir, ldpaths, root])
1225
1226 # Build the tarball.
1227 with parallel.BackgroundTaskRunner(cros_build_lib.CreateTarball) as queue:
1228 for target in targets:
1229 tar_file = os.path.join(output_dir, target + '.tar.xz')
1230 queue.put([tar_file, os.path.join(tempdir, target)])
1231
1232
Mike Frysinger07534cf2017-09-12 17:40:21 -04001233def GetParser():
1234 """Return a command line parser."""
Mike Frysinger0c808452014-11-06 17:30:23 -05001235 parser = commandline.ArgumentParser(description=__doc__)
1236 parser.add_argument('-u', '--nousepkg',
1237 action='store_false', dest='usepkg', default=True,
1238 help='Use prebuilt packages if possible')
1239 parser.add_argument('-d', '--deleteold',
1240 action='store_true', dest='deleteold', default=False,
1241 help='Unmerge deprecated packages')
1242 parser.add_argument('-t', '--targets',
1243 dest='targets', default='sdk',
Gilad Arnold8195b532015-04-07 10:56:30 +03001244 help="Comma separated list of tuples. Special keywords "
Don Garrettc0c74002015-10-09 12:58:19 -07001245 "'host', 'sdk', 'boards', and 'all' are "
Gilad Arnold8195b532015-04-07 10:56:30 +03001246 "allowed. Defaults to 'sdk'.")
1247 parser.add_argument('--include-boards', default='', metavar='BOARDS',
1248 help='Comma separated list of boards whose toolchains we '
1249 'will always include. Default: none')
Mike Frysinger0c808452014-11-06 17:30:23 -05001250 parser.add_argument('--hostonly',
1251 dest='hostonly', default=False, action='store_true',
1252 help='Only setup the host toolchain. '
1253 'Useful for bootstrapping chroot')
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001254 parser.add_argument('--show-board-cfg', '--show-cfg',
1255 dest='cfg_name', default=None,
Don Garrettc0c74002015-10-09 12:58:19 -07001256 help='Board to list toolchains tuples for')
Mike Frysinger91f52882017-09-13 00:16:58 -04001257 parser.add_argument('--show-packages', default=None,
1258 help='List all packages the specified target uses')
Mike Frysinger0c808452014-11-06 17:30:23 -05001259 parser.add_argument('--create-packages',
1260 action='store_true', default=False,
1261 help='Build redistributable packages')
1262 parser.add_argument('--output-dir', default=os.getcwd(), type='path',
1263 help='Output directory')
1264 parser.add_argument('--reconfig', default=False, action='store_true',
1265 help='Reload crossdev config and reselect toolchains')
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001266 parser.add_argument('--sysroot', type='path',
1267 help='The sysroot in which to install the toolchains')
Mike Frysinger07534cf2017-09-12 17:40:21 -04001268 return parser
Zdenek Behan508dcce2011-12-05 15:39:32 +01001269
Mike Frysinger07534cf2017-09-12 17:40:21 -04001270
1271def main(argv):
1272 parser = GetParser()
Mike Frysinger0c808452014-11-06 17:30:23 -05001273 options = parser.parse_args(argv)
1274 options.Freeze()
Zdenek Behan508dcce2011-12-05 15:39:32 +01001275
Mike Frysinger35247af2012-11-16 18:58:06 -05001276 # Figure out what we're supposed to do and reject conflicting options.
Mike Frysinger91f52882017-09-13 00:16:58 -04001277 conflicting_options = (
1278 options.cfg_name,
1279 options.show_packages,
1280 options.create_packages,
1281 )
1282 if sum(bool(x) for x in conflicting_options) > 1:
1283 parser.error('conflicting options: create-packages & show-packages & '
1284 'show-board-cfg')
Mike Frysinger984d0622012-06-01 16:08:44 -04001285
Gilad Arnold8195b532015-04-07 10:56:30 +03001286 targets_wanted = set(options.targets.split(','))
1287 boards_wanted = (set(options.include_boards.split(','))
1288 if options.include_boards else set())
Mike Frysinger35247af2012-11-16 18:58:06 -05001289
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001290 if options.cfg_name:
1291 ShowConfig(options.cfg_name)
Mike Frysinger91f52882017-09-13 00:16:58 -04001292 elif options.show_packages is not None:
1293 cros_build_lib.AssertInsideChroot()
1294 target = options.show_packages
1295 Crossdev.Load(False)
1296 for package in GetTargetPackages(target):
1297 print(GetPortagePackage(target, package))
Mike Frysinger35247af2012-11-16 18:58:06 -05001298 elif options.create_packages:
1299 cros_build_lib.AssertInsideChroot()
1300 Crossdev.Load(False)
Gilad Arnold8195b532015-04-07 10:56:30 +03001301 CreatePackages(targets_wanted, options.output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001302 else:
1303 cros_build_lib.AssertInsideChroot()
1304 # This has to be always run as root.
1305 if os.geteuid() != 0:
1306 cros_build_lib.Die('this script must be run as root')
1307
1308 Crossdev.Load(options.reconfig)
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001309 root = options.sysroot or '/'
Mike Frysinger35247af2012-11-16 18:58:06 -05001310 UpdateToolchains(options.usepkg, options.deleteold, options.hostonly,
Gilad Arnold8195b532015-04-07 10:56:30 +03001311 options.reconfig, targets_wanted, boards_wanted,
Don Garrettc0c74002015-10-09 12:58:19 -07001312 root=root)
Mike Frysinger35247af2012-11-16 18:58:06 -05001313 Crossdev.Save()
1314
1315 return 0