blob: c9d85a5d21ec2cde0ca480173b3635d88ae580ee [file] [log] [blame]
Mike Frysingere58c0e22017-10-04 15:43:30 -04001# -*- coding: utf-8 -*-
Zdenek Behan508dcce2011-12-05 15:39:32 +01002# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
Mike Frysinger750c5f52014-09-16 16:16:57 -04006"""This script manages the installed toolchains in the chroot."""
Zdenek Behan508dcce2011-12-05 15:39:32 +01007
Mike Frysinger383367e2014-09-16 15:06:17 -04008from __future__ import print_function
9
Mike Frysinger3ed47722017-08-08 14:59:08 -040010import errno
Mike Frysinger35247af2012-11-16 18:58:06 -050011import glob
Mike Frysinger3ed47722017-08-08 14:59:08 -040012import hashlib
Mike Frysinger7ccee992012-06-01 21:27:59 -040013import json
Zdenek Behan508dcce2011-12-05 15:39:32 +010014import os
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -070015import re
Zdenek Behan508dcce2011-12-05 15:39:32 +010016
Aviv Keshetb7519e12016-10-04 00:50:00 -070017from chromite.lib import constants
Mike Frysinger506e75f2012-12-17 14:21:13 -050018from chromite.lib import commandline
Brian Harring503f3ab2012-03-09 21:39:41 -080019from chromite.lib import cros_build_lib
Ralph Nathan03047282015-03-23 11:09:32 -070020from chromite.lib import cros_logging as logging
Brian Harringaf019fb2012-05-10 15:06:13 -070021from chromite.lib import osutils
Mike Frysinger35247af2012-11-16 18:58:06 -050022from chromite.lib import parallel
David James27ac4ae2012-12-03 23:16:15 -080023from chromite.lib import toolchain
Mike Frysinger35247af2012-11-16 18:58:06 -050024
25# Needs to be after chromite imports.
26import lddtree
Zdenek Behan508dcce2011-12-05 15:39:32 +010027
Mike Frysinger31596002012-12-03 23:54:24 -050028if cros_build_lib.IsInsideChroot():
29 # Only import portage after we've checked that we're inside the chroot.
30 # Outside may not have portage, in which case the above may not happen.
31 # We'll check in main() if the operation needs portage.
Don Garrett25f309a2014-03-19 14:02:12 -070032 # pylint: disable=F0401
Mike Frysinger31596002012-12-03 23:54:24 -050033 import portage
Zdenek Behan508dcce2011-12-05 15:39:32 +010034
35
Matt Tennantf1e30972012-03-02 16:30:07 -080036EMERGE_CMD = os.path.join(constants.CHROMITE_BIN_DIR, 'parallel_emerge')
Zdenek Behan508dcce2011-12-05 15:39:32 +010037PACKAGE_STABLE = '[stable]'
Zdenek Behan4eb6fd22012-03-12 17:00:56 +010038
39CHROMIUMOS_OVERLAY = '/usr/local/portage/chromiumos'
Christopher Wileyb22c0712015-06-02 10:37:03 -070040ECLASS_OVERLAY = '/usr/local/portage/eclass-overlay'
Zdenek Behan4eb6fd22012-03-12 17:00:56 +010041STABLE_OVERLAY = '/usr/local/portage/stable'
42CROSSDEV_OVERLAY = '/usr/local/portage/crossdev'
Zdenek Behan508dcce2011-12-05 15:39:32 +010043
44
Mike Frysinger66bfde52017-09-12 16:42:57 -040045# The exact list of host toolchain packages we care about. These are the
46# packages that bots/devs install only from binpkgs and rely on the SDK bot
47# (chromiumos-sdk) to validate+uprev.
48#
Mike Frysinger66bfde52017-09-12 16:42:57 -040049# We don't use crossdev to manage the host toolchain for us, especially since
50# we diverge significantly now (with llvm/clang/etc...), and we don't need or
51# want crossdev managing /etc/portage config files for the sdk
52HOST_PACKAGES = (
53 'dev-lang/go',
54 'sys-devel/binutils',
55 'sys-devel/clang',
56 'sys-devel/gcc',
57 'sys-devel/llvm',
58 'sys-kernel/linux-headers',
59 'sys-libs/glibc',
60 'sys-libs/libcxx',
61 'sys-libs/libcxxabi',
62)
63
Mike Frysinger785b0c32017-09-13 01:35:59 -040064# These packages are also installed into the host SDK. However, they require
65# the cross-compilers to be installed first (because they need them to actually
66# build), so we have to delay their installation.
67HOST_POST_CROSS_PACKAGES = (
68 'dev-lang/rust',
69)
70
71# New packages that we're in the process of adding to the SDK. Since the SDK
72# bot hasn't had a chance to run yet, there are no binary packages available,
73# so we have to list them here and wait. Once it completes, entries here can
74# be removed so they'll end up on bots & dev's systems.
75NEW_PACKAGES = (
76 'dev-lang/rust',
77)
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 Chaudhry4b803052015-05-13 15:25:56 -070084)
85CROSSDEV_GO_ARGS = ['--ex-pkg', 'dev-lang/go']
86
Manoj Gupta1b5642e2017-03-08 16:44:12 -080087# Enable llvm's compiler-rt for these targets.
88TARGET_COMPILER_RT_ENABLED = (
89 'armv7a-cros-linux-gnueabi',
Yunlian Jiang1b77ee42017-10-06 13:44:29 -070090 'armv7a-cros-linux-gnueabihf',
Manoj Gupta946abb42017-04-12 14:27:19 -070091 'aarch64-cros-linux-gnu',
Manoj Gupta1b5642e2017-03-08 16:44:12 -080092)
93CROSSDEV_COMPILER_RT_ARGS = ['--ex-pkg', 'sys-libs/compiler-rt']
94
Manoj Gupta946abb42017-04-12 14:27:19 -070095TARGET_LLVM_PKGS_ENABLED = (
96 'armv7a-cros-linux-gnueabi',
Yunlian Jiang16c1a422017-10-04 10:33:22 -070097 'armv7a-cros-linux-gnueabihf',
Manoj Gupta946abb42017-04-12 14:27:19 -070098 'aarch64-cros-linux-gnu',
99 'x86_64-cros-linux-gnu',
100)
101
102LLVM_PKGS_TABLE = {
Yunlian Jiangbb2a3d32017-04-26 14:44:09 -0700103 'ex_libcxxabi' : ['--ex-pkg', 'sys-libs/libcxxabi'],
104 'ex_libcxx' : ['--ex-pkg', 'sys-libs/libcxx'],
Manoj Gupta946abb42017-04-12 14:27:19 -0700105}
106
Zdenek Behan508dcce2011-12-05 15:39:32 +0100107# Overrides for {gcc,binutils}-config, pick a package with particular suffix.
108CONFIG_TARGET_SUFFIXES = {
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500109 'binutils' : {
Mike Frysinger8a83c622015-05-28 00:35:05 -0400110 'armv6j-cros-linux-gnueabi': '-gold',
Han Shen43b84422015-02-19 11:38:13 -0800111 'armv7a-cros-linux-gnueabi': '-gold',
Yunlian Jiang16c1a422017-10-04 10:33:22 -0700112 'armv7a-cros-linux-gnueabihf': '-gold',
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500113 'i686-pc-linux-gnu' : '-gold',
114 'x86_64-cros-linux-gnu' : '-gold',
115 },
Zdenek Behan508dcce2011-12-05 15:39:32 +0100116}
Zdenek Behan508dcce2011-12-05 15:39:32 +0100117
118
David James66a09c42012-11-05 13:31:38 -0800119class Crossdev(object):
120 """Class for interacting with crossdev and caching its output."""
121
122 _CACHE_FILE = os.path.join(CROSSDEV_OVERLAY, '.configured.json')
123 _CACHE = {}
Han Shene23782f2016-02-18 12:20:00 -0800124 # Packages that needs separate handling, in addition to what we have from
125 # crossdev.
126 MANUAL_PKGS = {
Manoj Guptaf0a602e2017-08-02 10:25:45 -0700127 'clang': 'sys-devel',
Han Shene23782f2016-02-18 12:20:00 -0800128 'llvm': 'sys-devel',
Manoj Gupta20cfc6c2017-07-19 15:49:55 -0700129 'libcxxabi': 'sys-libs',
130 'libcxx': 'sys-libs',
Han Shene23782f2016-02-18 12:20:00 -0800131 }
David James66a09c42012-11-05 13:31:38 -0800132
133 @classmethod
134 def Load(cls, reconfig):
Mike Frysinger3ed47722017-08-08 14:59:08 -0400135 """Load crossdev cache from disk.
136
137 We invalidate the cache when crossdev updates or this script changes.
138 """
David James90239b92012-11-05 15:31:34 -0800139 crossdev_version = GetStablePackageVersion('sys-devel/crossdev', True)
Mike Frysinger3ed47722017-08-08 14:59:08 -0400140 # If we run the compiled/cached .pyc file, we'll read/hash that when we
141 # really always want to track the source .py file.
142 script = os.path.abspath(__file__)
143 if script.endswith('.pyc'):
144 script = script[:-1]
145 setup_toolchains_hash = hashlib.md5(osutils.ReadFile(script)).hexdigest()
146
147 cls._CACHE = {
148 'crossdev_version': crossdev_version,
149 'setup_toolchains_hash': setup_toolchains_hash,
150 }
151
152 logging.debug('cache: checking file: %s', cls._CACHE_FILE)
153 if reconfig:
154 logging.debug('cache: forcing regen due to reconfig')
155 return
156
157 try:
158 file_data = osutils.ReadFile(cls._CACHE_FILE)
159 except IOError as e:
160 if e.errno != errno.ENOENT:
161 logging.warning('cache: reading failed: %s', e)
162 osutils.SafeUnlink(cls._CACHE_FILE)
163 return
164
165 try:
166 data = json.loads(file_data)
167 except ValueError as e:
168 logging.warning('cache: ignoring invalid content: %s', e)
169 return
170
171 if crossdev_version != data.get('crossdev_version'):
172 logging.debug('cache: rebuilding after crossdev upgrade')
173 elif setup_toolchains_hash != data.get('setup_toolchains_hash'):
174 logging.debug('cache: rebuilding after cros_setup_toolchains change')
175 else:
176 logging.debug('cache: content is up-to-date!')
177 cls._CACHE = data
David James66a09c42012-11-05 13:31:38 -0800178
179 @classmethod
180 def Save(cls):
181 """Store crossdev cache on disk."""
182 # Save the cache from the successful run.
183 with open(cls._CACHE_FILE, 'w') as f:
184 json.dump(cls._CACHE, f)
185
186 @classmethod
187 def GetConfig(cls, target):
188 """Returns a map of crossdev provided variables about a tuple."""
189 CACHE_ATTR = '_target_tuple_map'
190
191 val = cls._CACHE.setdefault(CACHE_ATTR, {})
192 if not target in val:
Mike Frysinger785b0c32017-09-13 01:35:59 -0400193 if target.startswith('host'):
Mike Frysinger66bfde52017-09-12 16:42:57 -0400194 conf = {
195 'crosspkgs': [],
196 'target': toolchain.GetHostTuple(),
197 }
Mike Frysinger785b0c32017-09-13 01:35:59 -0400198 if target == 'host':
199 packages_list = HOST_PACKAGES
200 else:
201 packages_list = HOST_POST_CROSS_PACKAGES
Mike Frysinger66bfde52017-09-12 16:42:57 -0400202 manual_pkgs = dict((pkg, cat) for cat, pkg in
Mike Frysinger785b0c32017-09-13 01:35:59 -0400203 [x.split('/') for x in packages_list])
Mike Frysinger66bfde52017-09-12 16:42:57 -0400204 else:
205 # Build the crossdev command.
206 cmd = ['crossdev', '--show-target-cfg', '--ex-gdb']
207 if target in TARGET_COMPILER_RT_ENABLED:
208 cmd.extend(CROSSDEV_COMPILER_RT_ARGS)
209 if target in TARGET_GO_ENABLED:
210 cmd.extend(CROSSDEV_GO_ARGS)
211 if target in TARGET_LLVM_PKGS_ENABLED:
212 for pkg in LLVM_PKGS_TABLE:
213 cmd.extend(LLVM_PKGS_TABLE[pkg])
214 cmd.extend(['-t', target])
215 # Catch output of crossdev.
216 out = cros_build_lib.RunCommand(
217 cmd, print_cmd=False, redirect_stdout=True).output.splitlines()
218 # List of tuples split at the first '=', converted into dict.
219 conf = dict((k, cros_build_lib.ShellUnquote(v))
220 for k, v in (x.split('=', 1) for x in out))
221 conf['crosspkgs'] = conf['crosspkgs'].split()
Han Shene23782f2016-02-18 12:20:00 -0800222
Mike Frysinger66bfde52017-09-12 16:42:57 -0400223 manual_pkgs = cls.MANUAL_PKGS
224
225 for pkg, cat in manual_pkgs.items():
Mike Frysinger3bba5032016-09-20 14:15:04 -0400226 conf[pkg + '_pn'] = pkg
227 conf[pkg + '_category'] = cat
228 if pkg not in conf['crosspkgs']:
229 conf['crosspkgs'].append(pkg)
Han Shene23782f2016-02-18 12:20:00 -0800230
231 val[target] = conf
232
David James66a09c42012-11-05 13:31:38 -0800233 return val[target]
234
235 @classmethod
236 def UpdateTargets(cls, targets, usepkg, config_only=False):
237 """Calls crossdev to initialize a cross target.
238
239 Args:
Don Garrett25f309a2014-03-19 14:02:12 -0700240 targets: The list of targets to initialize using crossdev.
241 usepkg: Copies the commandline opts.
242 config_only: Just update.
David James66a09c42012-11-05 13:31:38 -0800243 """
244 configured_targets = cls._CACHE.setdefault('configured_targets', [])
245
246 cmdbase = ['crossdev', '--show-fail-log']
247 cmdbase.extend(['--env', 'FEATURES=splitdebug'])
248 # Pick stable by default, and override as necessary.
249 cmdbase.extend(['-P', '--oneshot'])
250 if usepkg:
251 cmdbase.extend(['-P', '--getbinpkg',
252 '-P', '--usepkgonly',
253 '--without-headers'])
254
Christopher Wileyb22c0712015-06-02 10:37:03 -0700255 overlays = ' '.join((CHROMIUMOS_OVERLAY, ECLASS_OVERLAY, STABLE_OVERLAY))
David James66a09c42012-11-05 13:31:38 -0800256 cmdbase.extend(['--overlays', overlays])
257 cmdbase.extend(['--ov-output', CROSSDEV_OVERLAY])
258
259 for target in targets:
260 if config_only and target in configured_targets:
261 continue
262
263 cmd = cmdbase + ['-t', target]
264
265 for pkg in GetTargetPackages(target):
266 if pkg == 'gdb':
267 # Gdb does not have selectable versions.
268 cmd.append('--ex-gdb')
Manoj Guptab8181562017-05-21 10:18:59 -0700269 elif pkg == 'ex_compiler-rt':
270 cmd.extend(CROSSDEV_COMPILER_RT_ARGS)
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700271 elif pkg == 'ex_go':
272 # Go does not have selectable versions.
273 cmd.extend(CROSSDEV_GO_ARGS)
Manoj Gupta946abb42017-04-12 14:27:19 -0700274 elif pkg in LLVM_PKGS_TABLE:
275 cmd.extend(LLVM_PKGS_TABLE[pkg])
Han Shene23782f2016-02-18 12:20:00 -0800276 elif pkg in cls.MANUAL_PKGS:
277 pass
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700278 else:
279 # The first of the desired versions is the "primary" one.
280 version = GetDesiredPackageVersions(target, pkg)[0]
281 cmd.extend(['--%s' % pkg, version])
David James66a09c42012-11-05 13:31:38 -0800282
283 cmd.extend(targets[target]['crossdev'].split())
284 if config_only:
285 # In this case we want to just quietly reinit
286 cmd.append('--init-target')
287 cros_build_lib.RunCommand(cmd, print_cmd=False, redirect_stdout=True)
288 else:
289 cros_build_lib.RunCommand(cmd)
290
291 configured_targets.append(target)
292
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100293
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100294def GetTargetPackages(target):
295 """Returns a list of packages for a given target."""
David James66a09c42012-11-05 13:31:38 -0800296 conf = Crossdev.GetConfig(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100297 # Undesired packages are denoted by empty ${pkg}_pn variable.
Han Shene23782f2016-02-18 12:20:00 -0800298 return [x for x in conf['crosspkgs'] if conf.get(x+'_pn')]
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100299
300
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100301# Portage helper functions:
302def GetPortagePackage(target, package):
303 """Returns a package name for the given target."""
David James66a09c42012-11-05 13:31:38 -0800304 conf = Crossdev.GetConfig(target)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100305 # Portage category:
Mike Frysinger785b0c32017-09-13 01:35:59 -0400306 if target.startswith('host') or package in Crossdev.MANUAL_PKGS:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100307 category = conf[package + '_category']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100308 else:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100309 category = conf['category']
310 # Portage package:
311 pn = conf[package + '_pn']
312 # Final package name:
Mike Frysinger422faf42014-11-12 23:16:48 -0500313 assert category
314 assert pn
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100315 return '%s/%s' % (category, pn)
316
317
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700318def PortageTrees(root):
319 """Return the portage trees for a given root."""
320 if root == '/':
321 return portage.db['/']
322 # The portage logic requires the path always end in a slash.
323 root = root.rstrip('/') + '/'
324 return portage.create_trees(target_root=root, config_root=root)[root]
325
326
327def GetInstalledPackageVersions(atom, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100328 """Extracts the list of current versions of a target, package pair.
329
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500330 Args:
331 atom: The atom to operate on (e.g. sys-devel/gcc)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700332 root: The root to check for installed packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100333
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500334 Returns:
335 The list of versions of the package currently installed.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100336 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100337 versions = []
Mike Frysinger506e75f2012-12-17 14:21:13 -0500338 # pylint: disable=E1101
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700339 for pkg in PortageTrees(root)['vartree'].dbapi.match(atom, use_cache=0):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100340 version = portage.versions.cpv_getversion(pkg)
341 versions.append(version)
342 return versions
343
344
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700345def GetStablePackageVersion(atom, installed, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100346 """Extracts the current stable version for a given package.
347
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500348 Args:
349 atom: The target/package to operate on eg. i686-pc-linux-gnu,gcc
350 installed: Whether we want installed packages or ebuilds
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700351 root: The root to use when querying packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100352
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500353 Returns:
354 A string containing the latest version.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100355 """
David James90239b92012-11-05 15:31:34 -0800356 pkgtype = 'vartree' if installed else 'porttree'
Mike Frysinger506e75f2012-12-17 14:21:13 -0500357 # pylint: disable=E1101
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700358 cpv = portage.best(PortageTrees(root)[pkgtype].dbapi.match(atom, use_cache=0))
David James90239b92012-11-05 15:31:34 -0800359 return portage.versions.cpv_getversion(cpv) if cpv else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100360
361
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700362def VersionListToNumeric(target, package, versions, installed, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100363 """Resolves keywords in a given version list for a particular package.
364
365 Resolving means replacing PACKAGE_STABLE with the actual number.
366
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500367 Args:
368 target: The target to operate on (e.g. i686-pc-linux-gnu)
369 package: The target/package to operate on (e.g. gcc)
370 versions: List of versions to resolve
371 installed: Query installed packages
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700372 root: The install root to use; ignored if |installed| is False.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100373
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500374 Returns:
375 List of purely numeric versions equivalent to argument
Zdenek Behan508dcce2011-12-05 15:39:32 +0100376 """
377 resolved = []
David James90239b92012-11-05 15:31:34 -0800378 atom = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700379 if not installed:
380 root = '/'
Zdenek Behan508dcce2011-12-05 15:39:32 +0100381 for version in versions:
382 if version == PACKAGE_STABLE:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700383 resolved.append(GetStablePackageVersion(atom, installed, root=root))
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400384 else:
Zdenek Behan508dcce2011-12-05 15:39:32 +0100385 resolved.append(version)
386 return resolved
387
388
389def GetDesiredPackageVersions(target, package):
390 """Produces the list of desired versions for each target, package pair.
391
392 The first version in the list is implicitly treated as primary, ie.
393 the version that will be initialized by crossdev and selected.
394
395 If the version is PACKAGE_STABLE, it really means the current version which
396 is emerged by using the package atom with no particular version key.
397 Since crossdev unmasks all packages by default, this will actually
398 mean 'unstable' in most cases.
399
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500400 Args:
401 target: The target to operate on (e.g. i686-pc-linux-gnu)
402 package: The target/package to operate on (e.g. gcc)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100403
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500404 Returns:
405 A list composed of either a version string, PACKAGE_STABLE
Zdenek Behan508dcce2011-12-05 15:39:32 +0100406 """
Mike Frysingerd23be272017-09-12 17:18:44 -0400407 if package in GetTargetPackages(target):
408 return [PACKAGE_STABLE]
409 else:
410 return []
Zdenek Behan508dcce2011-12-05 15:39:32 +0100411
412
413def TargetIsInitialized(target):
414 """Verifies if the given list of targets has been correctly initialized.
415
416 This determines whether we have to call crossdev while emerging
417 toolchain packages or can do it using emerge. Emerge is naturally
418 preferred, because all packages can be updated in a single pass.
419
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500420 Args:
421 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100422
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500423 Returns:
424 True if |target| is completely initialized, else False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100425 """
426 # Check if packages for the given target all have a proper version.
427 try:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100428 for package in GetTargetPackages(target):
David James66a09c42012-11-05 13:31:38 -0800429 atom = GetPortagePackage(target, package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100430 # Do we even want this package && is it initialized?
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400431 if not (GetStablePackageVersion(atom, True) and
432 GetStablePackageVersion(atom, False)):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100433 return False
434 return True
435 except cros_build_lib.RunCommandError:
436 # Fails - The target has likely never been initialized before.
437 return False
438
439
440def RemovePackageMask(target):
441 """Removes a package.mask file for the given platform.
442
443 The pre-existing package.mask files can mess with the keywords.
444
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500445 Args:
446 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100447 """
448 maskfile = os.path.join('/etc/portage/package.mask', 'cross-' + target)
Brian Harringaf019fb2012-05-10 15:06:13 -0700449 osutils.SafeUnlink(maskfile)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100450
451
Zdenek Behan508dcce2011-12-05 15:39:32 +0100452# Main functions performing the actual update steps.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700453def RebuildLibtool(root='/'):
Mike Frysingerc880a962013-11-08 13:59:06 -0500454 """Rebuild libtool as needed
455
456 Libtool hardcodes full paths to internal gcc files, so whenever we upgrade
457 gcc, libtool will break. We can't use binary packages either as those will
458 most likely be compiled against the previous version of gcc.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700459
460 Args:
461 root: The install root where we want libtool rebuilt.
Mike Frysingerc880a962013-11-08 13:59:06 -0500462 """
463 needs_update = False
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700464 with open(os.path.join(root, 'usr/bin/libtool')) as f:
Mike Frysingerc880a962013-11-08 13:59:06 -0500465 for line in f:
466 # Look for a line like:
467 # sys_lib_search_path_spec="..."
468 # It'll be a list of paths and gcc will be one of them.
469 if line.startswith('sys_lib_search_path_spec='):
470 line = line.rstrip()
471 for path in line.split('=', 1)[1].strip('"').split():
Mike Frysinger3bba5032016-09-20 14:15:04 -0400472 root_path = os.path.join(root, path.lstrip(os.path.sep))
473 logging.debug('Libtool: checking %s', root_path)
474 if not os.path.exists(root_path):
475 logging.info('Rebuilding libtool after gcc upgrade')
476 logging.info(' %s', line)
477 logging.info(' missing path: %s', path)
Mike Frysingerc880a962013-11-08 13:59:06 -0500478 needs_update = True
479 break
480
481 if needs_update:
482 break
483
484 if needs_update:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700485 cmd = [EMERGE_CMD, '--oneshot']
486 if root != '/':
487 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
488 cmd.append('sys-devel/libtool')
Mike Frysingerc880a962013-11-08 13:59:06 -0500489 cros_build_lib.RunCommand(cmd)
Mike Frysinger3bba5032016-09-20 14:15:04 -0400490 else:
491 logging.debug('Libtool is up-to-date; no need to rebuild')
Mike Frysingerc880a962013-11-08 13:59:06 -0500492
493
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700494def UpdateTargets(targets, usepkg, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100495 """Determines which packages need update/unmerge and defers to portage.
496
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500497 Args:
498 targets: The list of targets to update
499 usepkg: Copies the commandline option
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700500 root: The install root in which we want packages updated.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100501 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100502 # For each target, we do two things. Figure out the list of updates,
503 # and figure out the appropriate keywords/masks. Crossdev will initialize
504 # these, but they need to be regenerated on every update.
Mike Frysinger3bba5032016-09-20 14:15:04 -0400505 logging.info('Determining required toolchain updates...')
David James90239b92012-11-05 15:31:34 -0800506 mergemap = {}
Zdenek Behan508dcce2011-12-05 15:39:32 +0100507 for target in targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400508 logging.debug('Updating target %s', target)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100509 # Record the highest needed version for each target, for masking purposes.
510 RemovePackageMask(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100511 for package in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100512 # Portage name for the package
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400513 logging.debug(' Checking package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100514 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700515 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100516 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200517 desired_num = VersionListToNumeric(target, package, desired, False)
Mike Frysinger785b0c32017-09-13 01:35:59 -0400518 if pkg in NEW_PACKAGES and usepkg:
519 # Skip this binary package (for now).
520 continue
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100521 mergemap[pkg] = set(desired_num).difference(current)
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400522 logging.debug(' %s -> %s', current, desired_num)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100523
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400524 packages = [pkg for pkg, vers in mergemap.items() if vers]
Zdenek Behan508dcce2011-12-05 15:39:32 +0100525 if not packages:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400526 logging.info('Nothing to update!')
David Jamesf8c672f2012-11-06 13:38:11 -0800527 return False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100528
Mike Frysinger3bba5032016-09-20 14:15:04 -0400529 logging.info('Updating packages:')
530 logging.info('%s', packages)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100531
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100532 cmd = [EMERGE_CMD, '--oneshot', '--update']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100533 if usepkg:
534 cmd.extend(['--getbinpkg', '--usepkgonly'])
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700535 if root != '/':
536 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100537
538 cmd.extend(packages)
539 cros_build_lib.RunCommand(cmd)
David Jamesf8c672f2012-11-06 13:38:11 -0800540 return True
Zdenek Behan508dcce2011-12-05 15:39:32 +0100541
542
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700543def CleanTargets(targets, root='/'):
544 """Unmerges old packages that are assumed unnecessary.
545
546 Args:
547 targets: The list of targets to clean up.
548 root: The install root in which we want packages cleaned up.
549 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100550 unmergemap = {}
551 for target in targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400552 logging.debug('Cleaning target %s', target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100553 for package in GetTargetPackages(target):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400554 logging.debug(' Cleaning package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100555 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700556 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100557 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2fcb0aa2015-05-21 14:51:41 -0700558 # NOTE: This refers to installed packages (vartree) rather than the
559 # Portage version (porttree and/or bintree) when determining the current
560 # version. While this isn't the most accurate thing to do, it is probably
561 # a good simple compromise, which should have the desired result of
562 # uninstalling everything but the latest installed version. In
563 # particular, using the bintree (--usebinpkg) requires a non-trivial
564 # binhost sync and is probably more complex than useful.
Zdenek Behan699ddd32012-04-13 07:14:08 +0200565 desired_num = VersionListToNumeric(target, package, desired, True)
566 if not set(desired_num).issubset(current):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400567 logging.warning('Error detecting stable version for %s, '
568 'skipping clean!', pkg)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200569 return
Zdenek Behan508dcce2011-12-05 15:39:32 +0100570 unmergemap[pkg] = set(current).difference(desired_num)
571
572 # Cleaning doesn't care about consistency and rebuilding package.* files.
573 packages = []
574 for pkg, vers in unmergemap.iteritems():
575 packages.extend('=%s-%s' % (pkg, ver) for ver in vers if ver != '9999')
576
577 if packages:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400578 logging.info('Cleaning packages:')
579 logging.info('%s', packages)
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100580 cmd = [EMERGE_CMD, '--unmerge']
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700581 if root != '/':
582 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100583 cmd.extend(packages)
584 cros_build_lib.RunCommand(cmd)
585 else:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400586 logging.info('Nothing to clean!')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100587
588
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700589def SelectActiveToolchains(targets, suffixes, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100590 """Runs gcc-config and binutils-config to select the desired.
591
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500592 Args:
593 targets: The targets to select
594 suffixes: Optional target-specific hacks
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700595 root: The root where we want to select toolchain versions.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100596 """
597 for package in ['gcc', 'binutils']:
598 for target in targets:
Mike Frysinger785b0c32017-09-13 01:35:59 -0400599 # See if this package is part of this target.
600 if package not in GetTargetPackages(target):
601 logging.debug('%s: %s is not used', target, package)
602 continue
603
Zdenek Behan508dcce2011-12-05 15:39:32 +0100604 # Pick the first version in the numbered list as the selected one.
605 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700606 desired_num = VersionListToNumeric(target, package, desired, True,
607 root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100608 desired = desired_num[0]
609 # *-config does not play revisions, strip them, keep just PV.
610 desired = portage.versions.pkgsplit('%s-%s' % (package, desired))[1]
611
Mike Frysinger785b0c32017-09-13 01:35:59 -0400612 if target.startswith('host'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100613 # *-config is the only tool treating host identically (by tuple).
David James27ac4ae2012-12-03 23:16:15 -0800614 target = toolchain.GetHostTuple()
Zdenek Behan508dcce2011-12-05 15:39:32 +0100615
616 # And finally, attach target to it.
617 desired = '%s-%s' % (target, desired)
618
619 # Target specific hacks
620 if package in suffixes:
621 if target in suffixes[package]:
622 desired += suffixes[package][target]
623
David James7ec5efc2012-11-06 09:39:49 -0800624 extra_env = {'CHOST': target}
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700625 if root != '/':
626 extra_env['ROOT'] = root
David James7ec5efc2012-11-06 09:39:49 -0800627 cmd = ['%s-config' % package, '-c', target]
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500628 result = cros_build_lib.RunCommand(
629 cmd, print_cmd=False, redirect_stdout=True, extra_env=extra_env)
630 current = result.output.splitlines()[0]
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700631
632 # Do not reconfig when the current is live or nothing needs to be done.
633 extra_env = {'ROOT': root} if root != '/' else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100634 if current != desired and current != '9999':
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500635 cmd = [package + '-config', desired]
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700636 cros_build_lib.RunCommand(cmd, print_cmd=False, extra_env=extra_env)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100637
638
Mike Frysinger35247af2012-11-16 18:58:06 -0500639def ExpandTargets(targets_wanted):
640 """Expand any possible toolchain aliases into full targets
641
642 This will expand 'all' and 'sdk' into the respective toolchain tuples.
643
644 Args:
645 targets_wanted: The targets specified by the user.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500646
Mike Frysinger35247af2012-11-16 18:58:06 -0500647 Returns:
Gilad Arnold8195b532015-04-07 10:56:30 +0300648 Dictionary of concrete targets and their toolchain tuples.
Mike Frysinger35247af2012-11-16 18:58:06 -0500649 """
Mike Frysinger35247af2012-11-16 18:58:06 -0500650 targets_wanted = set(targets_wanted)
Don Garrettc0c74002015-10-09 12:58:19 -0700651 if targets_wanted == set(['boards']):
652 # Only pull targets from the included boards.
Gilad Arnold8195b532015-04-07 10:56:30 +0300653 return {}
654
655 all_targets = toolchain.GetAllTargets()
Mike Frysinger35247af2012-11-16 18:58:06 -0500656 if targets_wanted == set(['all']):
Gilad Arnold8195b532015-04-07 10:56:30 +0300657 return all_targets
658 if targets_wanted == set(['sdk']):
Mike Frysinger35247af2012-11-16 18:58:06 -0500659 # Filter out all the non-sdk toolchains as we don't want to mess
660 # with those in all of our builds.
Gilad Arnold8195b532015-04-07 10:56:30 +0300661 return toolchain.FilterToolchains(all_targets, 'sdk', True)
662
663 # Verify user input.
664 nonexistent = targets_wanted.difference(all_targets)
665 if nonexistent:
666 raise ValueError('Invalid targets: %s', ','.join(nonexistent))
667 return {t: all_targets[t] for t in targets_wanted}
Mike Frysinger35247af2012-11-16 18:58:06 -0500668
669
David Jamesf8c672f2012-11-06 13:38:11 -0800670def UpdateToolchains(usepkg, deleteold, hostonly, reconfig,
Don Garrettc0c74002015-10-09 12:58:19 -0700671 targets_wanted, boards_wanted, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100672 """Performs all steps to create a synchronized toolchain enviroment.
673
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500674 Args:
675 usepkg: Use prebuilt packages
676 deleteold: Unmerge deprecated packages
677 hostonly: Only setup the host toolchain
678 reconfig: Reload crossdev config and reselect toolchains
679 targets_wanted: All the targets to update
680 boards_wanted: Load targets from these boards
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700681 root: The root in which to install the toolchains.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100682 """
David Jamesf8c672f2012-11-06 13:38:11 -0800683 targets, crossdev_targets, reconfig_targets = {}, {}, {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100684 if not hostonly:
685 # For hostonly, we can skip most of the below logic, much of which won't
686 # work on bare systems where this is useful.
Mike Frysinger35247af2012-11-16 18:58:06 -0500687 targets = ExpandTargets(targets_wanted)
Mike Frysinger7ccee992012-06-01 21:27:59 -0400688
Don Garrettc0c74002015-10-09 12:58:19 -0700689 # Now re-add any targets that might be from this board. This is to
Gilad Arnold8195b532015-04-07 10:56:30 +0300690 # allow unofficial boards to declare their own toolchains.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400691 for board in boards_wanted:
David James27ac4ae2012-12-03 23:16:15 -0800692 targets.update(toolchain.GetToolchainsForBoard(board))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100693
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100694 # First check and initialize all cross targets that need to be.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400695 for target in targets:
696 if TargetIsInitialized(target):
697 reconfig_targets[target] = targets[target]
698 else:
699 crossdev_targets[target] = targets[target]
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100700 if crossdev_targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400701 logging.info('The following targets need to be re-initialized:')
702 logging.info('%s', crossdev_targets)
David James66a09c42012-11-05 13:31:38 -0800703 Crossdev.UpdateTargets(crossdev_targets, usepkg)
Zdenek Behan8be29ba2012-05-29 23:10:34 +0200704 # Those that were not initialized may need a config update.
David James66a09c42012-11-05 13:31:38 -0800705 Crossdev.UpdateTargets(reconfig_targets, usepkg, config_only=True)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100706
Mike Frysinger66814c32017-10-09 18:11:46 -0400707 # If we're building a subset of toolchains for a board, we might not have
708 # all the tuples that the packages expect. We don't define the "full" set
709 # of tuples currently other than "whatever the full sdk has normally".
710 if usepkg or set(('all', 'sdk')) & targets_wanted:
711 # Since we have cross-compilers now, we can update these packages.
712 targets['host-post-cross'] = {}
Mike Frysinger785b0c32017-09-13 01:35:59 -0400713
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100714 # We want host updated.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400715 targets['host'] = {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100716
717 # Now update all packages.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700718 if UpdateTargets(targets, usepkg, root=root) or crossdev_targets or reconfig:
719 SelectActiveToolchains(targets, CONFIG_TARGET_SUFFIXES, root=root)
David James7ec5efc2012-11-06 09:39:49 -0800720
721 if deleteold:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700722 CleanTargets(targets, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100723
Mike Frysingerc880a962013-11-08 13:59:06 -0500724 # Now that we've cleared out old versions, see if we need to rebuild
725 # anything. Can't do this earlier as it might not be broken.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700726 RebuildLibtool(root=root)
Mike Frysingerc880a962013-11-08 13:59:06 -0500727
Zdenek Behan508dcce2011-12-05 15:39:32 +0100728
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -0700729def ShowConfig(name):
730 """Show the toolchain tuples used by |name|
Mike Frysinger35247af2012-11-16 18:58:06 -0500731
732 Args:
Don Garrettc0c74002015-10-09 12:58:19 -0700733 name: The board name to query.
Mike Frysinger35247af2012-11-16 18:58:06 -0500734 """
Don Garrettc0c74002015-10-09 12:58:19 -0700735 toolchains = toolchain.GetToolchainsForBoard(name)
Mike Frysinger35247af2012-11-16 18:58:06 -0500736 # Make sure we display the default toolchain first.
Mike Frysinger3bba5032016-09-20 14:15:04 -0400737 # Note: Do not use logging here as this is meant to be used by other tools.
Mike Frysinger383367e2014-09-16 15:06:17 -0400738 print(','.join(
David James27ac4ae2012-12-03 23:16:15 -0800739 toolchain.FilterToolchains(toolchains, 'default', True).keys() +
Mike Frysinger383367e2014-09-16 15:06:17 -0400740 toolchain.FilterToolchains(toolchains, 'default', False).keys()))
Mike Frysinger35247af2012-11-16 18:58:06 -0500741
742
Mike Frysinger35247af2012-11-16 18:58:06 -0500743def GeneratePathWrapper(root, wrappath, path):
744 """Generate a shell script to execute another shell script
745
746 Since we can't symlink a wrapped ELF (see GenerateLdsoWrapper) because the
747 argv[0] won't be pointing to the correct path, generate a shell script that
748 just executes another program with its full path.
749
750 Args:
751 root: The root tree to generate scripts inside of
752 wrappath: The full path (inside |root|) to create the wrapper
753 path: The target program which this wrapper will execute
754 """
755 replacements = {
756 'path': path,
757 'relroot': os.path.relpath('/', os.path.dirname(wrappath)),
758 }
759 wrapper = """#!/bin/sh
760base=$(realpath "$0")
761basedir=${base%%/*}
762exec "${basedir}/%(relroot)s%(path)s" "$@"
763""" % replacements
764 root_wrapper = root + wrappath
765 if os.path.islink(root_wrapper):
766 os.unlink(root_wrapper)
767 else:
768 osutils.SafeMakedirs(os.path.dirname(root_wrapper))
769 osutils.WriteFile(root_wrapper, wrapper)
Mike Frysinger60ec1012013-10-21 00:11:10 -0400770 os.chmod(root_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -0500771
772
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -0700773def FixClangXXWrapper(root, path):
774 """Fix wrapper shell scripts and symlinks for invoking clang++
775
776 In a typical installation, clang++ symlinks to clang, which symlinks to the
777 elf executable. The executable distinguishes between clang and clang++ based
778 on argv[0].
779
780 When invoked through the LdsoWrapper, argv[0] always contains the path to the
781 executable elf file, making clang/clang++ invocations indistinguishable.
782
783 This function detects if the elf executable being wrapped is clang-X.Y, and
784 fixes wrappers/symlinks as necessary so that clang++ will work correctly.
785
786 The calling sequence now becomes:
787 -) clang++ invocation turns into clang++-3.9 (which is a copy of clang-3.9,
788 the Ldsowrapper).
789 -) clang++-3.9 uses the Ldso to invoke clang++-3.9.elf, which is a symlink
790 to the original clang-3.9 elf.
791 -) The difference this time is that inside the elf file execution, $0 is
792 set as .../usr/bin/clang++-3.9.elf, which contains 'clang++' in the name.
793
794 Args:
795 root: The root tree to generate scripts / symlinks inside of
796 path: The target elf for which LdsoWrapper was created
797 """
798 if re.match(r'/usr/bin/clang-\d+\.\d+$', path):
799 logging.info('fixing clang++ invocation for %s', path)
800 clangdir = os.path.dirname(root + path)
801 clang = os.path.basename(path)
802 clangxx = clang.replace('clang', 'clang++')
803
804 # Create a symlink clang++-X.Y.elf to point to clang-X.Y.elf
805 os.symlink(clang + '.elf', os.path.join(clangdir, clangxx + '.elf'))
806
807 # Create a hardlink clang++-X.Y pointing to clang-X.Y
808 os.link(os.path.join(clangdir, clang), os.path.join(clangdir, clangxx))
809
810 # Adjust the clang++ symlink to point to clang++-X.Y
811 os.unlink(os.path.join(clangdir, 'clang++'))
812 os.symlink(clangxx, os.path.join(clangdir, 'clang++'))
813
814
Mike Frysinger35247af2012-11-16 18:58:06 -0500815def FileIsCrosSdkElf(elf):
816 """Determine if |elf| is an ELF that we execute in the cros_sdk
817
818 We don't need this to be perfect, just quick. It makes sure the ELF
819 is a 64bit LSB x86_64 ELF. That is the native type of cros_sdk.
820
821 Args:
822 elf: The file to check
Mike Frysinger1a736a82013-12-12 01:50:59 -0500823
Mike Frysinger35247af2012-11-16 18:58:06 -0500824 Returns:
825 True if we think |elf| is a native ELF
826 """
827 with open(elf) as f:
828 data = f.read(20)
829 # Check the magic number, EI_CLASS, EI_DATA, and e_machine.
830 return (data[0:4] == '\x7fELF' and
831 data[4] == '\x02' and
832 data[5] == '\x01' and
833 data[18] == '\x3e')
834
835
836def IsPathPackagable(ptype, path):
837 """Should the specified file be included in a toolchain package?
838
839 We only need to handle files as we'll create dirs as we need them.
840
841 Further, trim files that won't be useful:
842 - non-english translations (.mo) since it'd require env vars
843 - debug files since these are for the host compiler itself
844 - info/man pages as they're big, and docs are online, and the
845 native docs should work fine for the most part (`man gcc`)
846
847 Args:
848 ptype: A string describing the path type (i.e. 'file' or 'dir' or 'sym')
849 path: The full path to inspect
Mike Frysinger1a736a82013-12-12 01:50:59 -0500850
Mike Frysinger35247af2012-11-16 18:58:06 -0500851 Returns:
852 True if we want to include this path in the package
853 """
854 return not (ptype in ('dir',) or
855 path.startswith('/usr/lib/debug/') or
856 os.path.splitext(path)[1] == '.mo' or
857 ('/man/' in path or '/info/' in path))
858
859
860def ReadlinkRoot(path, root):
861 """Like os.readlink(), but relative to a |root|
862
863 Args:
864 path: The symlink to read
865 root: The path to use for resolving absolute symlinks
Mike Frysinger1a736a82013-12-12 01:50:59 -0500866
Mike Frysinger35247af2012-11-16 18:58:06 -0500867 Returns:
868 A fully resolved symlink path
869 """
870 while os.path.islink(root + path):
871 path = os.path.join(os.path.dirname(path), os.readlink(root + path))
872 return path
873
874
875def _GetFilesForTarget(target, root='/'):
876 """Locate all the files to package for |target|
877
878 This does not cover ELF dependencies.
879
880 Args:
881 target: The toolchain target name
882 root: The root path to pull all packages from
Mike Frysinger1a736a82013-12-12 01:50:59 -0500883
Mike Frysinger35247af2012-11-16 18:58:06 -0500884 Returns:
885 A tuple of a set of all packable paths, and a set of all paths which
886 are also native ELFs
887 """
888 paths = set()
889 elfs = set()
890
891 # Find all the files owned by the packages for this target.
892 for pkg in GetTargetPackages(target):
Mike Frysinger35247af2012-11-16 18:58:06 -0500893
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700894 # Skip Go compiler from redistributable packages.
895 # The "go" executable has GOROOT=/usr/lib/go/${CTARGET} hardcoded
896 # into it. Due to this, the toolchain cannot be unpacked anywhere
897 # else and be readily useful. To enable packaging Go, we need to:
898 # -) Tweak the wrappers/environment to override GOROOT
899 # automatically based on the unpack location.
900 # -) Make sure the ELF dependency checking and wrapping logic
901 # below skips the Go toolchain executables and libraries.
902 # -) Make sure the packaging process maintains the relative
903 # timestamps of precompiled standard library packages.
904 # (see dev-lang/go ebuild for details).
905 if pkg == 'ex_go':
906 continue
907
Mike Frysinger35247af2012-11-16 18:58:06 -0500908 atom = GetPortagePackage(target, pkg)
909 cat, pn = atom.split('/')
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700910 ver = GetInstalledPackageVersions(atom, root=root)[0]
Ralph Nathan03047282015-03-23 11:09:32 -0700911 logging.info('packaging %s-%s', atom, ver)
Mike Frysinger35247af2012-11-16 18:58:06 -0500912
913 # pylint: disable=E1101
914 dblink = portage.dblink(cat, pn + '-' + ver, myroot=root,
915 settings=portage.settings)
916 contents = dblink.getcontents()
917 for obj in contents:
918 ptype = contents[obj][0]
919 if not IsPathPackagable(ptype, obj):
920 continue
921
922 if ptype == 'obj':
923 # For native ELFs, we need to pull in their dependencies too.
924 if FileIsCrosSdkElf(obj):
925 elfs.add(obj)
926 paths.add(obj)
927
928 return paths, elfs
929
930
931def _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500932 path_rewrite_func=lambda x: x, root='/'):
Mike Frysinger35247af2012-11-16 18:58:06 -0500933 """Link in all packable files and their runtime dependencies
934
935 This also wraps up executable ELFs with helper scripts.
936
937 Args:
938 output_dir: The output directory to store files
939 paths: All the files to include
940 elfs: All the files which are ELFs (a subset of |paths|)
941 ldpaths: A dict of static ldpath information
942 path_rewrite_func: User callback to rewrite paths in output_dir
943 root: The root path to pull all packages/files from
944 """
945 # Link in all the files.
Mike Frysinger221bd822017-09-29 02:51:47 -0400946 sym_paths = {}
Mike Frysinger35247af2012-11-16 18:58:06 -0500947 for path in paths:
948 new_path = path_rewrite_func(path)
949 dst = output_dir + new_path
950 osutils.SafeMakedirs(os.path.dirname(dst))
951
952 # Is this a symlink which we have to rewrite or wrap?
953 # Delay wrap check until after we have created all paths.
954 src = root + path
955 if os.path.islink(src):
956 tgt = os.readlink(src)
957 if os.path.sep in tgt:
Mike Frysinger221bd822017-09-29 02:51:47 -0400958 sym_paths[lddtree.normpath(ReadlinkRoot(src, root))] = new_path
Mike Frysinger35247af2012-11-16 18:58:06 -0500959
960 # Rewrite absolute links to relative and then generate the symlink
961 # ourselves. All other symlinks can be hardlinked below.
962 if tgt[0] == '/':
963 tgt = os.path.relpath(tgt, os.path.dirname(new_path))
964 os.symlink(tgt, dst)
965 continue
966
967 os.link(src, dst)
968
Mike Frysinger35247af2012-11-16 18:58:06 -0500969 # Locate all the dependencies for all the ELFs. Stick them all in the
970 # top level "lib" dir to make the wrapper simpler. This exact path does
971 # not matter since we execute ldso directly, and we tell the ldso the
972 # exact path to search for its libraries.
973 libdir = os.path.join(output_dir, 'lib')
974 osutils.SafeMakedirs(libdir)
975 donelibs = set()
Mike Frysinger4331fc62017-09-28 14:03:25 -0400976 glibc_re = re.compile(r'/lib(c|pthread)-[0-9.]+\.so$')
Mike Frysinger35247af2012-11-16 18:58:06 -0500977 for elf in elfs:
Mike Frysingerea7688e2014-07-31 22:40:33 -0400978 e = lddtree.ParseELF(elf, root=root, ldpaths=ldpaths)
Mike Frysinger35247af2012-11-16 18:58:06 -0500979 interp = e['interp']
Yunlian Jiang196e8f42017-09-20 12:29:47 -0700980 # Do not create wrapper for libc. crbug.com/766827
981 if interp and not glibc_re.search(elf):
Mike Frysinger35247af2012-11-16 18:58:06 -0500982 # Generate a wrapper if it is executable.
Mike Frysingerc2ec0902013-03-26 01:28:45 -0400983 interp = os.path.join('/lib', os.path.basename(interp))
984 lddtree.GenerateLdsoWrapper(output_dir, path_rewrite_func(elf), interp,
985 libpaths=e['rpath'] + e['runpath'])
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -0700986 FixClangXXWrapper(output_dir, path_rewrite_func(elf))
Mike Frysinger35247af2012-11-16 18:58:06 -0500987
Mike Frysinger221bd822017-09-29 02:51:47 -0400988 # Wrap any symlinks to the wrapper.
989 if elf in sym_paths:
990 link = sym_paths[elf]
991 GeneratePathWrapper(output_dir, link, elf)
992
Mike Frysinger35247af2012-11-16 18:58:06 -0500993 for lib, lib_data in e['libs'].iteritems():
994 if lib in donelibs:
995 continue
996
997 src = path = lib_data['path']
998 if path is None:
Ralph Nathan446aee92015-03-23 14:44:56 -0700999 logging.warning('%s: could not locate %s', elf, lib)
Mike Frysinger35247af2012-11-16 18:58:06 -05001000 continue
1001 donelibs.add(lib)
1002
1003 # Needed libs are the SONAME, but that is usually a symlink, not a
1004 # real file. So link in the target rather than the symlink itself.
1005 # We have to walk all the possible symlinks (SONAME could point to a
1006 # symlink which points to a symlink), and we have to handle absolute
1007 # ourselves (since we have a "root" argument).
1008 dst = os.path.join(libdir, os.path.basename(path))
1009 src = ReadlinkRoot(src, root)
1010
1011 os.link(root + src, dst)
1012
1013
1014def _EnvdGetVar(envd, var):
1015 """Given a Gentoo env.d file, extract a var from it
1016
1017 Args:
1018 envd: The env.d file to load (may be a glob path)
1019 var: The var to extract
Mike Frysinger1a736a82013-12-12 01:50:59 -05001020
Mike Frysinger35247af2012-11-16 18:58:06 -05001021 Returns:
1022 The value of |var|
1023 """
1024 envds = glob.glob(envd)
1025 assert len(envds) == 1, '%s: should have exactly 1 env.d file' % envd
1026 envd = envds[0]
1027 return cros_build_lib.LoadKeyValueFile(envd)[var]
1028
1029
1030def _ProcessBinutilsConfig(target, output_dir):
1031 """Do what binutils-config would have done"""
1032 binpath = os.path.join('/bin', target + '-')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001033
1034 # Locate the bin dir holding the gold linker.
1035 binutils_bin_path = os.path.join(output_dir, 'usr', toolchain.GetHostTuple(),
1036 target, 'binutils-bin')
1037 globpath = os.path.join(binutils_bin_path, '*-gold')
Mike Frysinger35247af2012-11-16 18:58:06 -05001038 srcpath = glob.glob(globpath)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001039 if not srcpath:
1040 # Maybe this target doesn't support gold.
1041 globpath = os.path.join(binutils_bin_path, '*')
1042 srcpath = glob.glob(globpath)
1043 assert len(srcpath) == 1, ('%s: matched more than one path (but not *-gold)'
1044 % globpath)
1045 srcpath = srcpath[0]
1046 ld_path = os.path.join(srcpath, 'ld')
1047 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1048 ld_path = os.path.join(srcpath, 'ld.bfd')
1049 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1050 ld_path = os.path.join(srcpath, 'ld.gold')
1051 assert not os.path.exists(ld_path), ('%s: exists, but gold dir does not!'
1052 % ld_path)
1053
1054 # Nope, no gold support to be found.
1055 gold_supported = False
Ralph Nathan446aee92015-03-23 14:44:56 -07001056 logging.warning('%s: binutils lacks support for the gold linker', target)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001057 else:
1058 assert len(srcpath) == 1, '%s: did not match exactly 1 path' % globpath
Mike Frysinger78b7a812014-11-26 19:45:23 -05001059 srcpath = srcpath[0]
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001060
Rahul Chaudhry4891b4d2017-03-08 10:31:27 -08001061 # Package the binutils-bin directory without the '-gold' suffix
1062 # if gold is not enabled as the default linker for this target.
1063 gold_supported = CONFIG_TARGET_SUFFIXES['binutils'].get(target) == '-gold'
1064 if not gold_supported:
1065 srcpath = srcpath[:-len('-gold')]
1066 ld_path = os.path.join(srcpath, 'ld')
1067 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1068
Mike Frysinger78b7a812014-11-26 19:45:23 -05001069 srcpath = srcpath[len(output_dir):]
Mike Frysinger35247af2012-11-16 18:58:06 -05001070 gccpath = os.path.join('/usr', 'libexec', 'gcc')
1071 for prog in os.listdir(output_dir + srcpath):
1072 # Skip binaries already wrapped.
1073 if not prog.endswith('.real'):
1074 GeneratePathWrapper(output_dir, binpath + prog,
1075 os.path.join(srcpath, prog))
1076 GeneratePathWrapper(output_dir, os.path.join(gccpath, prog),
1077 os.path.join(srcpath, prog))
1078
David James27ac4ae2012-12-03 23:16:15 -08001079 libpath = os.path.join('/usr', toolchain.GetHostTuple(), target, 'lib')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001080 envd = os.path.join(output_dir, 'etc', 'env.d', 'binutils', '*')
1081 if gold_supported:
1082 envd += '-gold'
Rahul Chaudhry4891b4d2017-03-08 10:31:27 -08001083 else:
1084 # If gold is not enabled as the default linker and 2 env.d
1085 # files exist, pick the one without the '-gold' suffix.
1086 envds = sorted(glob.glob(envd))
1087 if len(envds) == 2 and envds[1] == envds[0] + '-gold':
1088 envd = envds[0]
Mike Frysinger35247af2012-11-16 18:58:06 -05001089 srcpath = _EnvdGetVar(envd, 'LIBPATH')
1090 os.symlink(os.path.relpath(srcpath, os.path.dirname(libpath)),
1091 output_dir + libpath)
1092
1093
1094def _ProcessGccConfig(target, output_dir):
1095 """Do what gcc-config would have done"""
1096 binpath = '/bin'
1097 envd = os.path.join(output_dir, 'etc', 'env.d', 'gcc', '*')
1098 srcpath = _EnvdGetVar(envd, 'GCC_PATH')
1099 for prog in os.listdir(output_dir + srcpath):
1100 # Skip binaries already wrapped.
1101 if (not prog.endswith('.real') and
1102 not prog.endswith('.elf') and
1103 prog.startswith(target)):
1104 GeneratePathWrapper(output_dir, os.path.join(binpath, prog),
1105 os.path.join(srcpath, prog))
1106 return srcpath
1107
1108
Frank Henigman179ec7c2015-02-06 03:01:09 -05001109def _ProcessSysrootWrappers(_target, output_dir, srcpath):
1110 """Remove chroot-specific things from our sysroot wrappers"""
Mike Frysinger35247af2012-11-16 18:58:06 -05001111 # Disable ccache since we know it won't work outside of chroot.
Frank Henigman179ec7c2015-02-06 03:01:09 -05001112 for sysroot_wrapper in glob.glob(os.path.join(
1113 output_dir + srcpath, 'sysroot_wrapper*')):
1114 contents = osutils.ReadFile(sysroot_wrapper).splitlines()
1115 for num in xrange(len(contents)):
1116 if '@CCACHE_DEFAULT@' in contents[num]:
Caroline Ticece9e9232017-06-02 09:38:42 -07001117 assert 'True' in contents[num]
1118 contents[num] = contents[num].replace('True', 'False')
Frank Henigman179ec7c2015-02-06 03:01:09 -05001119 break
1120 # Can't update the wrapper in place since it's a hardlink to a file in /.
1121 os.unlink(sysroot_wrapper)
1122 osutils.WriteFile(sysroot_wrapper, '\n'.join(contents))
1123 os.chmod(sysroot_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -05001124
1125
Yunlian Jiang5ad6b512017-09-20 09:27:45 -07001126def _CreateMainLibDir(target, output_dir):
1127 """Create some lib dirs so that compiler can get the right Gcc paths"""
1128 osutils.SafeMakedirs(os.path.join(output_dir, 'usr', target, 'lib'))
1129 osutils.SafeMakedirs(os.path.join(output_dir, 'usr', target, 'usr/lib'))
1130
1131
Mike Frysinger35247af2012-11-16 18:58:06 -05001132def _ProcessDistroCleanups(target, output_dir):
1133 """Clean up the tree and remove all distro-specific requirements
1134
1135 Args:
1136 target: The toolchain target name
1137 output_dir: The output directory to clean up
1138 """
1139 _ProcessBinutilsConfig(target, output_dir)
1140 gcc_path = _ProcessGccConfig(target, output_dir)
Frank Henigman179ec7c2015-02-06 03:01:09 -05001141 _ProcessSysrootWrappers(target, output_dir, gcc_path)
Yunlian Jiang5ad6b512017-09-20 09:27:45 -07001142 _CreateMainLibDir(target, output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001143
1144 osutils.RmDir(os.path.join(output_dir, 'etc'))
1145
1146
1147def CreatePackagableRoot(target, output_dir, ldpaths, root='/'):
1148 """Setup a tree from the packages for the specified target
1149
1150 This populates a path with all the files from toolchain packages so that
1151 a tarball can easily be generated from the result.
1152
1153 Args:
1154 target: The target to create a packagable root from
1155 output_dir: The output directory to place all the files
1156 ldpaths: A dict of static ldpath information
1157 root: The root path to pull all packages/files from
1158 """
1159 # Find all the files owned by the packages for this target.
1160 paths, elfs = _GetFilesForTarget(target, root=root)
1161
1162 # Link in all the package's files, any ELF dependencies, and wrap any
1163 # executable ELFs with helper scripts.
1164 def MoveUsrBinToBin(path):
Han Shen699ea192016-03-02 10:42:47 -08001165 """Move /usr/bin to /bin so people can just use that toplevel dir
1166
1167 Note we do not apply this to clang - there is correlation between clang's
1168 search path for libraries / inclusion and its installation path.
1169 """
1170 if path.startswith('/usr/bin/') and path.find('clang') == -1:
1171 return path[4:]
1172 return path
Mike Frysinger35247af2012-11-16 18:58:06 -05001173 _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
1174 path_rewrite_func=MoveUsrBinToBin, root=root)
1175
1176 # The packages, when part of the normal distro, have helper scripts
1177 # that setup paths and such. Since we are making this standalone, we
1178 # need to preprocess all that ourselves.
1179 _ProcessDistroCleanups(target, output_dir)
1180
1181
1182def CreatePackages(targets_wanted, output_dir, root='/'):
1183 """Create redistributable cross-compiler packages for the specified targets
1184
1185 This creates toolchain packages that should be usable in conjunction with
1186 a downloaded sysroot (created elsewhere).
1187
1188 Tarballs (one per target) will be created in $PWD.
1189
1190 Args:
Don Garrett25f309a2014-03-19 14:02:12 -07001191 targets_wanted: The targets to package up.
1192 output_dir: The directory to put the packages in.
1193 root: The root path to pull all packages/files from.
Mike Frysinger35247af2012-11-16 18:58:06 -05001194 """
Ralph Nathan03047282015-03-23 11:09:32 -07001195 logging.info('Writing tarballs to %s', output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001196 osutils.SafeMakedirs(output_dir)
1197 ldpaths = lddtree.LoadLdpaths(root)
1198 targets = ExpandTargets(targets_wanted)
1199
Mike Frysinger221bd822017-09-29 02:51:47 -04001200 with osutils.TempDir(prefix='create-packages') as tempdir:
1201 logging.debug('Using tempdir: %s', tempdir)
1202
Mike Frysinger35247af2012-11-16 18:58:06 -05001203 # We have to split the root generation from the compression stages. This is
1204 # because we hardlink in all the files (to avoid overhead of reading/writing
1205 # the copies multiple times). But tar gets angry if a file's hardlink count
1206 # changes from when it starts reading a file to when it finishes.
1207 with parallel.BackgroundTaskRunner(CreatePackagableRoot) as queue:
1208 for target in targets:
1209 output_target_dir = os.path.join(tempdir, target)
1210 queue.put([target, output_target_dir, ldpaths, root])
1211
1212 # Build the tarball.
1213 with parallel.BackgroundTaskRunner(cros_build_lib.CreateTarball) as queue:
1214 for target in targets:
1215 tar_file = os.path.join(output_dir, target + '.tar.xz')
1216 queue.put([tar_file, os.path.join(tempdir, target)])
1217
1218
Mike Frysinger07534cf2017-09-12 17:40:21 -04001219def GetParser():
1220 """Return a command line parser."""
Mike Frysinger0c808452014-11-06 17:30:23 -05001221 parser = commandline.ArgumentParser(description=__doc__)
1222 parser.add_argument('-u', '--nousepkg',
1223 action='store_false', dest='usepkg', default=True,
1224 help='Use prebuilt packages if possible')
1225 parser.add_argument('-d', '--deleteold',
1226 action='store_true', dest='deleteold', default=False,
1227 help='Unmerge deprecated packages')
1228 parser.add_argument('-t', '--targets',
1229 dest='targets', default='sdk',
Gilad Arnold8195b532015-04-07 10:56:30 +03001230 help="Comma separated list of tuples. Special keywords "
Don Garrettc0c74002015-10-09 12:58:19 -07001231 "'host', 'sdk', 'boards', and 'all' are "
Gilad Arnold8195b532015-04-07 10:56:30 +03001232 "allowed. Defaults to 'sdk'.")
1233 parser.add_argument('--include-boards', default='', metavar='BOARDS',
1234 help='Comma separated list of boards whose toolchains we '
1235 'will always include. Default: none')
Mike Frysinger0c808452014-11-06 17:30:23 -05001236 parser.add_argument('--hostonly',
1237 dest='hostonly', default=False, action='store_true',
1238 help='Only setup the host toolchain. '
1239 'Useful for bootstrapping chroot')
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001240 parser.add_argument('--show-board-cfg', '--show-cfg',
1241 dest='cfg_name', default=None,
Don Garrettc0c74002015-10-09 12:58:19 -07001242 help='Board to list toolchains tuples for')
Mike Frysinger91f52882017-09-13 00:16:58 -04001243 parser.add_argument('--show-packages', default=None,
1244 help='List all packages the specified target uses')
Mike Frysinger0c808452014-11-06 17:30:23 -05001245 parser.add_argument('--create-packages',
1246 action='store_true', default=False,
1247 help='Build redistributable packages')
1248 parser.add_argument('--output-dir', default=os.getcwd(), type='path',
1249 help='Output directory')
1250 parser.add_argument('--reconfig', default=False, action='store_true',
1251 help='Reload crossdev config and reselect toolchains')
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001252 parser.add_argument('--sysroot', type='path',
1253 help='The sysroot in which to install the toolchains')
Mike Frysinger07534cf2017-09-12 17:40:21 -04001254 return parser
Zdenek Behan508dcce2011-12-05 15:39:32 +01001255
Mike Frysinger07534cf2017-09-12 17:40:21 -04001256
1257def main(argv):
1258 parser = GetParser()
Mike Frysinger0c808452014-11-06 17:30:23 -05001259 options = parser.parse_args(argv)
1260 options.Freeze()
Zdenek Behan508dcce2011-12-05 15:39:32 +01001261
Mike Frysinger35247af2012-11-16 18:58:06 -05001262 # Figure out what we're supposed to do and reject conflicting options.
Mike Frysinger91f52882017-09-13 00:16:58 -04001263 conflicting_options = (
1264 options.cfg_name,
1265 options.show_packages,
1266 options.create_packages,
1267 )
1268 if sum(bool(x) for x in conflicting_options) > 1:
1269 parser.error('conflicting options: create-packages & show-packages & '
1270 'show-board-cfg')
Mike Frysinger984d0622012-06-01 16:08:44 -04001271
Gilad Arnold8195b532015-04-07 10:56:30 +03001272 targets_wanted = set(options.targets.split(','))
1273 boards_wanted = (set(options.include_boards.split(','))
1274 if options.include_boards else set())
Mike Frysinger35247af2012-11-16 18:58:06 -05001275
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001276 if options.cfg_name:
1277 ShowConfig(options.cfg_name)
Mike Frysinger91f52882017-09-13 00:16:58 -04001278 elif options.show_packages is not None:
1279 cros_build_lib.AssertInsideChroot()
1280 target = options.show_packages
1281 Crossdev.Load(False)
1282 for package in GetTargetPackages(target):
1283 print(GetPortagePackage(target, package))
Mike Frysinger35247af2012-11-16 18:58:06 -05001284 elif options.create_packages:
1285 cros_build_lib.AssertInsideChroot()
1286 Crossdev.Load(False)
Gilad Arnold8195b532015-04-07 10:56:30 +03001287 CreatePackages(targets_wanted, options.output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001288 else:
1289 cros_build_lib.AssertInsideChroot()
1290 # This has to be always run as root.
1291 if os.geteuid() != 0:
1292 cros_build_lib.Die('this script must be run as root')
1293
1294 Crossdev.Load(options.reconfig)
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001295 root = options.sysroot or '/'
Mike Frysinger35247af2012-11-16 18:58:06 -05001296 UpdateToolchains(options.usepkg, options.deleteold, options.hostonly,
Gilad Arnold8195b532015-04-07 10:56:30 +03001297 options.reconfig, targets_wanted, boards_wanted,
Don Garrettc0c74002015-10-09 12:58:19 -07001298 root=root)
Mike Frysinger35247af2012-11-16 18:58:06 -05001299 Crossdev.Save()
1300
1301 return 0