blob: 79d77aa8befde5445bebdcfe29c14b04ee56aa2a [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 = (
Mike Frysinger785b0c32017-09-13 01:35:59 -040076)
77
Rahul Chaudhry4b803052015-05-13 15:25:56 -070078# Enable the Go compiler for these targets.
79TARGET_GO_ENABLED = (
80 'x86_64-cros-linux-gnu',
Rahul Chaudhry4b803052015-05-13 15:25:56 -070081 'armv7a-cros-linux-gnueabi',
Yunlian Jiang16c1a422017-10-04 10:33:22 -070082 'armv7a-cros-linux-gnueabihf',
Rahul Chaudhry4b803052015-05-13 15:25:56 -070083)
84CROSSDEV_GO_ARGS = ['--ex-pkg', 'dev-lang/go']
85
Manoj Gupta1b5642e2017-03-08 16:44:12 -080086# Enable llvm's compiler-rt for these targets.
87TARGET_COMPILER_RT_ENABLED = (
88 'armv7a-cros-linux-gnueabi',
Yunlian Jiang1b77ee42017-10-06 13:44:29 -070089 'armv7a-cros-linux-gnueabihf',
Manoj Gupta946abb42017-04-12 14:27:19 -070090 'aarch64-cros-linux-gnu',
Manoj Gupta1b5642e2017-03-08 16:44:12 -080091)
92CROSSDEV_COMPILER_RT_ARGS = ['--ex-pkg', 'sys-libs/compiler-rt']
93
Manoj Gupta946abb42017-04-12 14:27:19 -070094TARGET_LLVM_PKGS_ENABLED = (
95 'armv7a-cros-linux-gnueabi',
Yunlian Jiang16c1a422017-10-04 10:33:22 -070096 'armv7a-cros-linux-gnueabihf',
Manoj Gupta946abb42017-04-12 14:27:19 -070097 'aarch64-cros-linux-gnu',
98 'x86_64-cros-linux-gnu',
99)
100
101LLVM_PKGS_TABLE = {
Yunlian Jiangbb2a3d32017-04-26 14:44:09 -0700102 'ex_libcxxabi' : ['--ex-pkg', 'sys-libs/libcxxabi'],
103 'ex_libcxx' : ['--ex-pkg', 'sys-libs/libcxx'],
Manoj Gupta946abb42017-04-12 14:27:19 -0700104}
105
Zdenek Behan508dcce2011-12-05 15:39:32 +0100106# Overrides for {gcc,binutils}-config, pick a package with particular suffix.
107CONFIG_TARGET_SUFFIXES = {
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500108 'binutils' : {
Mike Frysinger8a83c622015-05-28 00:35:05 -0400109 'armv6j-cros-linux-gnueabi': '-gold',
Han Shen43b84422015-02-19 11:38:13 -0800110 'armv7a-cros-linux-gnueabi': '-gold',
Yunlian Jiang16c1a422017-10-04 10:33:22 -0700111 'armv7a-cros-linux-gnueabihf': '-gold',
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500112 'i686-pc-linux-gnu' : '-gold',
113 'x86_64-cros-linux-gnu' : '-gold',
114 },
Zdenek Behan508dcce2011-12-05 15:39:32 +0100115}
Zdenek Behan508dcce2011-12-05 15:39:32 +0100116
117
David James66a09c42012-11-05 13:31:38 -0800118class Crossdev(object):
119 """Class for interacting with crossdev and caching its output."""
120
121 _CACHE_FILE = os.path.join(CROSSDEV_OVERLAY, '.configured.json')
122 _CACHE = {}
Han Shene23782f2016-02-18 12:20:00 -0800123 # Packages that needs separate handling, in addition to what we have from
124 # crossdev.
125 MANUAL_PKGS = {
Manoj Guptaf0a602e2017-08-02 10:25:45 -0700126 'clang': 'sys-devel',
Han Shene23782f2016-02-18 12:20:00 -0800127 'llvm': 'sys-devel',
Manoj Gupta20cfc6c2017-07-19 15:49:55 -0700128 'libcxxabi': 'sys-libs',
129 'libcxx': 'sys-libs',
Han Shene23782f2016-02-18 12:20:00 -0800130 }
David James66a09c42012-11-05 13:31:38 -0800131
132 @classmethod
133 def Load(cls, reconfig):
Mike Frysinger3ed47722017-08-08 14:59:08 -0400134 """Load crossdev cache from disk.
135
136 We invalidate the cache when crossdev updates or this script changes.
137 """
David James90239b92012-11-05 15:31:34 -0800138 crossdev_version = GetStablePackageVersion('sys-devel/crossdev', True)
Mike Frysinger3ed47722017-08-08 14:59:08 -0400139 # If we run the compiled/cached .pyc file, we'll read/hash that when we
140 # really always want to track the source .py file.
141 script = os.path.abspath(__file__)
142 if script.endswith('.pyc'):
143 script = script[:-1]
144 setup_toolchains_hash = hashlib.md5(osutils.ReadFile(script)).hexdigest()
145
146 cls._CACHE = {
147 'crossdev_version': crossdev_version,
148 'setup_toolchains_hash': setup_toolchains_hash,
149 }
150
151 logging.debug('cache: checking file: %s', cls._CACHE_FILE)
152 if reconfig:
153 logging.debug('cache: forcing regen due to reconfig')
154 return
155
156 try:
157 file_data = osutils.ReadFile(cls._CACHE_FILE)
158 except IOError as e:
159 if e.errno != errno.ENOENT:
160 logging.warning('cache: reading failed: %s', e)
161 osutils.SafeUnlink(cls._CACHE_FILE)
162 return
163
164 try:
165 data = json.loads(file_data)
166 except ValueError as e:
167 logging.warning('cache: ignoring invalid content: %s', e)
168 return
169
170 if crossdev_version != data.get('crossdev_version'):
171 logging.debug('cache: rebuilding after crossdev upgrade')
172 elif setup_toolchains_hash != data.get('setup_toolchains_hash'):
173 logging.debug('cache: rebuilding after cros_setup_toolchains change')
174 else:
175 logging.debug('cache: content is up-to-date!')
176 cls._CACHE = data
David James66a09c42012-11-05 13:31:38 -0800177
178 @classmethod
179 def Save(cls):
180 """Store crossdev cache on disk."""
181 # Save the cache from the successful run.
182 with open(cls._CACHE_FILE, 'w') as f:
183 json.dump(cls._CACHE, f)
184
185 @classmethod
186 def GetConfig(cls, target):
187 """Returns a map of crossdev provided variables about a tuple."""
188 CACHE_ATTR = '_target_tuple_map'
189
190 val = cls._CACHE.setdefault(CACHE_ATTR, {})
191 if not target in val:
Mike Frysinger785b0c32017-09-13 01:35:59 -0400192 if target.startswith('host'):
Mike Frysinger66bfde52017-09-12 16:42:57 -0400193 conf = {
194 'crosspkgs': [],
195 'target': toolchain.GetHostTuple(),
196 }
Mike Frysinger785b0c32017-09-13 01:35:59 -0400197 if target == 'host':
198 packages_list = HOST_PACKAGES
199 else:
200 packages_list = HOST_POST_CROSS_PACKAGES
Mike Frysinger66bfde52017-09-12 16:42:57 -0400201 manual_pkgs = dict((pkg, cat) for cat, pkg in
Mike Frysinger785b0c32017-09-13 01:35:59 -0400202 [x.split('/') for x in packages_list])
Mike Frysinger66bfde52017-09-12 16:42:57 -0400203 else:
204 # Build the crossdev command.
205 cmd = ['crossdev', '--show-target-cfg', '--ex-gdb']
206 if target in TARGET_COMPILER_RT_ENABLED:
207 cmd.extend(CROSSDEV_COMPILER_RT_ARGS)
208 if target in TARGET_GO_ENABLED:
209 cmd.extend(CROSSDEV_GO_ARGS)
210 if target in TARGET_LLVM_PKGS_ENABLED:
211 for pkg in LLVM_PKGS_TABLE:
212 cmd.extend(LLVM_PKGS_TABLE[pkg])
213 cmd.extend(['-t', target])
214 # Catch output of crossdev.
215 out = cros_build_lib.RunCommand(
216 cmd, print_cmd=False, redirect_stdout=True).output.splitlines()
217 # List of tuples split at the first '=', converted into dict.
218 conf = dict((k, cros_build_lib.ShellUnquote(v))
219 for k, v in (x.split('=', 1) for x in out))
220 conf['crosspkgs'] = conf['crosspkgs'].split()
Han Shene23782f2016-02-18 12:20:00 -0800221
Mike Frysinger66bfde52017-09-12 16:42:57 -0400222 manual_pkgs = cls.MANUAL_PKGS
223
224 for pkg, cat in manual_pkgs.items():
Mike Frysinger3bba5032016-09-20 14:15:04 -0400225 conf[pkg + '_pn'] = pkg
226 conf[pkg + '_category'] = cat
227 if pkg not in conf['crosspkgs']:
228 conf['crosspkgs'].append(pkg)
Han Shene23782f2016-02-18 12:20:00 -0800229
230 val[target] = conf
231
David James66a09c42012-11-05 13:31:38 -0800232 return val[target]
233
234 @classmethod
235 def UpdateTargets(cls, targets, usepkg, config_only=False):
236 """Calls crossdev to initialize a cross target.
237
238 Args:
Don Garrett25f309a2014-03-19 14:02:12 -0700239 targets: The list of targets to initialize using crossdev.
240 usepkg: Copies the commandline opts.
241 config_only: Just update.
David James66a09c42012-11-05 13:31:38 -0800242 """
243 configured_targets = cls._CACHE.setdefault('configured_targets', [])
244
245 cmdbase = ['crossdev', '--show-fail-log']
246 cmdbase.extend(['--env', 'FEATURES=splitdebug'])
247 # Pick stable by default, and override as necessary.
248 cmdbase.extend(['-P', '--oneshot'])
249 if usepkg:
250 cmdbase.extend(['-P', '--getbinpkg',
251 '-P', '--usepkgonly',
252 '--without-headers'])
253
Christopher Wileyb22c0712015-06-02 10:37:03 -0700254 overlays = ' '.join((CHROMIUMOS_OVERLAY, ECLASS_OVERLAY, STABLE_OVERLAY))
David James66a09c42012-11-05 13:31:38 -0800255 cmdbase.extend(['--overlays', overlays])
256 cmdbase.extend(['--ov-output', CROSSDEV_OVERLAY])
257
258 for target in targets:
259 if config_only and target in configured_targets:
260 continue
261
262 cmd = cmdbase + ['-t', target]
263
264 for pkg in GetTargetPackages(target):
265 if pkg == 'gdb':
266 # Gdb does not have selectable versions.
267 cmd.append('--ex-gdb')
Manoj Guptab8181562017-05-21 10:18:59 -0700268 elif pkg == 'ex_compiler-rt':
269 cmd.extend(CROSSDEV_COMPILER_RT_ARGS)
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700270 elif pkg == 'ex_go':
271 # Go does not have selectable versions.
272 cmd.extend(CROSSDEV_GO_ARGS)
Manoj Gupta946abb42017-04-12 14:27:19 -0700273 elif pkg in LLVM_PKGS_TABLE:
274 cmd.extend(LLVM_PKGS_TABLE[pkg])
Han Shene23782f2016-02-18 12:20:00 -0800275 elif pkg in cls.MANUAL_PKGS:
276 pass
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700277 else:
278 # The first of the desired versions is the "primary" one.
279 version = GetDesiredPackageVersions(target, pkg)[0]
280 cmd.extend(['--%s' % pkg, version])
David James66a09c42012-11-05 13:31:38 -0800281
282 cmd.extend(targets[target]['crossdev'].split())
283 if config_only:
284 # In this case we want to just quietly reinit
285 cmd.append('--init-target')
286 cros_build_lib.RunCommand(cmd, print_cmd=False, redirect_stdout=True)
287 else:
288 cros_build_lib.RunCommand(cmd)
289
290 configured_targets.append(target)
291
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100292
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100293def GetTargetPackages(target):
294 """Returns a list of packages for a given target."""
David James66a09c42012-11-05 13:31:38 -0800295 conf = Crossdev.GetConfig(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100296 # Undesired packages are denoted by empty ${pkg}_pn variable.
Han Shene23782f2016-02-18 12:20:00 -0800297 return [x for x in conf['crosspkgs'] if conf.get(x+'_pn')]
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100298
299
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100300# Portage helper functions:
301def GetPortagePackage(target, package):
302 """Returns a package name for the given target."""
David James66a09c42012-11-05 13:31:38 -0800303 conf = Crossdev.GetConfig(target)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100304 # Portage category:
Mike Frysinger785b0c32017-09-13 01:35:59 -0400305 if target.startswith('host') or package in Crossdev.MANUAL_PKGS:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100306 category = conf[package + '_category']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100307 else:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100308 category = conf['category']
309 # Portage package:
310 pn = conf[package + '_pn']
311 # Final package name:
Mike Frysinger422faf42014-11-12 23:16:48 -0500312 assert category
313 assert pn
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100314 return '%s/%s' % (category, pn)
315
316
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700317def PortageTrees(root):
318 """Return the portage trees for a given root."""
319 if root == '/':
320 return portage.db['/']
321 # The portage logic requires the path always end in a slash.
322 root = root.rstrip('/') + '/'
323 return portage.create_trees(target_root=root, config_root=root)[root]
324
325
326def GetInstalledPackageVersions(atom, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100327 """Extracts the list of current versions of a target, package pair.
328
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500329 Args:
330 atom: The atom to operate on (e.g. sys-devel/gcc)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700331 root: The root to check for installed packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100332
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500333 Returns:
334 The list of versions of the package currently installed.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100335 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100336 versions = []
Mike Frysinger506e75f2012-12-17 14:21:13 -0500337 # pylint: disable=E1101
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700338 for pkg in PortageTrees(root)['vartree'].dbapi.match(atom, use_cache=0):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100339 version = portage.versions.cpv_getversion(pkg)
340 versions.append(version)
341 return versions
342
343
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700344def GetStablePackageVersion(atom, installed, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100345 """Extracts the current stable version for a given package.
346
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500347 Args:
348 atom: The target/package to operate on eg. i686-pc-linux-gnu,gcc
349 installed: Whether we want installed packages or ebuilds
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700350 root: The root to use when querying packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100351
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500352 Returns:
353 A string containing the latest version.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100354 """
David James90239b92012-11-05 15:31:34 -0800355 pkgtype = 'vartree' if installed else 'porttree'
Mike Frysinger506e75f2012-12-17 14:21:13 -0500356 # pylint: disable=E1101
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700357 cpv = portage.best(PortageTrees(root)[pkgtype].dbapi.match(atom, use_cache=0))
David James90239b92012-11-05 15:31:34 -0800358 return portage.versions.cpv_getversion(cpv) if cpv else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100359
360
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700361def VersionListToNumeric(target, package, versions, installed, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100362 """Resolves keywords in a given version list for a particular package.
363
364 Resolving means replacing PACKAGE_STABLE with the actual number.
365
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500366 Args:
367 target: The target to operate on (e.g. i686-pc-linux-gnu)
368 package: The target/package to operate on (e.g. gcc)
369 versions: List of versions to resolve
370 installed: Query installed packages
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700371 root: The install root to use; ignored if |installed| is False.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100372
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500373 Returns:
374 List of purely numeric versions equivalent to argument
Zdenek Behan508dcce2011-12-05 15:39:32 +0100375 """
376 resolved = []
David James90239b92012-11-05 15:31:34 -0800377 atom = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700378 if not installed:
379 root = '/'
Zdenek Behan508dcce2011-12-05 15:39:32 +0100380 for version in versions:
381 if version == PACKAGE_STABLE:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700382 resolved.append(GetStablePackageVersion(atom, installed, root=root))
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400383 else:
Zdenek Behan508dcce2011-12-05 15:39:32 +0100384 resolved.append(version)
385 return resolved
386
387
388def GetDesiredPackageVersions(target, package):
389 """Produces the list of desired versions for each target, package pair.
390
391 The first version in the list is implicitly treated as primary, ie.
392 the version that will be initialized by crossdev and selected.
393
394 If the version is PACKAGE_STABLE, it really means the current version which
395 is emerged by using the package atom with no particular version key.
396 Since crossdev unmasks all packages by default, this will actually
397 mean 'unstable' in most cases.
398
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500399 Args:
400 target: The target to operate on (e.g. i686-pc-linux-gnu)
401 package: The target/package to operate on (e.g. gcc)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100402
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500403 Returns:
404 A list composed of either a version string, PACKAGE_STABLE
Zdenek Behan508dcce2011-12-05 15:39:32 +0100405 """
Mike Frysingerd23be272017-09-12 17:18:44 -0400406 if package in GetTargetPackages(target):
407 return [PACKAGE_STABLE]
408 else:
409 return []
Zdenek Behan508dcce2011-12-05 15:39:32 +0100410
411
412def TargetIsInitialized(target):
413 """Verifies if the given list of targets has been correctly initialized.
414
415 This determines whether we have to call crossdev while emerging
416 toolchain packages or can do it using emerge. Emerge is naturally
417 preferred, because all packages can be updated in a single pass.
418
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500419 Args:
420 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100421
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500422 Returns:
423 True if |target| is completely initialized, else False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100424 """
425 # Check if packages for the given target all have a proper version.
426 try:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100427 for package in GetTargetPackages(target):
David James66a09c42012-11-05 13:31:38 -0800428 atom = GetPortagePackage(target, package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100429 # Do we even want this package && is it initialized?
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400430 if not (GetStablePackageVersion(atom, True) and
431 GetStablePackageVersion(atom, False)):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100432 return False
433 return True
434 except cros_build_lib.RunCommandError:
435 # Fails - The target has likely never been initialized before.
436 return False
437
438
439def RemovePackageMask(target):
440 """Removes a package.mask file for the given platform.
441
442 The pre-existing package.mask files can mess with the keywords.
443
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500444 Args:
445 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100446 """
447 maskfile = os.path.join('/etc/portage/package.mask', 'cross-' + target)
Brian Harringaf019fb2012-05-10 15:06:13 -0700448 osutils.SafeUnlink(maskfile)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100449
450
Zdenek Behan508dcce2011-12-05 15:39:32 +0100451# Main functions performing the actual update steps.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700452def RebuildLibtool(root='/'):
Mike Frysingerc880a962013-11-08 13:59:06 -0500453 """Rebuild libtool as needed
454
455 Libtool hardcodes full paths to internal gcc files, so whenever we upgrade
456 gcc, libtool will break. We can't use binary packages either as those will
457 most likely be compiled against the previous version of gcc.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700458
459 Args:
460 root: The install root where we want libtool rebuilt.
Mike Frysingerc880a962013-11-08 13:59:06 -0500461 """
462 needs_update = False
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700463 with open(os.path.join(root, 'usr/bin/libtool')) as f:
Mike Frysingerc880a962013-11-08 13:59:06 -0500464 for line in f:
465 # Look for a line like:
466 # sys_lib_search_path_spec="..."
467 # It'll be a list of paths and gcc will be one of them.
468 if line.startswith('sys_lib_search_path_spec='):
469 line = line.rstrip()
470 for path in line.split('=', 1)[1].strip('"').split():
Mike Frysinger3bba5032016-09-20 14:15:04 -0400471 root_path = os.path.join(root, path.lstrip(os.path.sep))
472 logging.debug('Libtool: checking %s', root_path)
473 if not os.path.exists(root_path):
474 logging.info('Rebuilding libtool after gcc upgrade')
475 logging.info(' %s', line)
476 logging.info(' missing path: %s', path)
Mike Frysingerc880a962013-11-08 13:59:06 -0500477 needs_update = True
478 break
479
480 if needs_update:
481 break
482
483 if needs_update:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700484 cmd = [EMERGE_CMD, '--oneshot']
485 if root != '/':
486 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
487 cmd.append('sys-devel/libtool')
Mike Frysingerc880a962013-11-08 13:59:06 -0500488 cros_build_lib.RunCommand(cmd)
Mike Frysinger3bba5032016-09-20 14:15:04 -0400489 else:
490 logging.debug('Libtool is up-to-date; no need to rebuild')
Mike Frysingerc880a962013-11-08 13:59:06 -0500491
492
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700493def UpdateTargets(targets, usepkg, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100494 """Determines which packages need update/unmerge and defers to portage.
495
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500496 Args:
497 targets: The list of targets to update
498 usepkg: Copies the commandline option
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700499 root: The install root in which we want packages updated.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100500 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100501 # For each target, we do two things. Figure out the list of updates,
502 # and figure out the appropriate keywords/masks. Crossdev will initialize
503 # these, but they need to be regenerated on every update.
Mike Frysinger3bba5032016-09-20 14:15:04 -0400504 logging.info('Determining required toolchain updates...')
David James90239b92012-11-05 15:31:34 -0800505 mergemap = {}
Zdenek Behan508dcce2011-12-05 15:39:32 +0100506 for target in targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400507 logging.debug('Updating target %s', target)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100508 # Record the highest needed version for each target, for masking purposes.
509 RemovePackageMask(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100510 for package in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100511 # Portage name for the package
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400512 logging.debug(' Checking package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100513 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700514 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100515 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200516 desired_num = VersionListToNumeric(target, package, desired, False)
Mike Frysinger785b0c32017-09-13 01:35:59 -0400517 if pkg in NEW_PACKAGES and usepkg:
518 # Skip this binary package (for now).
519 continue
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100520 mergemap[pkg] = set(desired_num).difference(current)
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400521 logging.debug(' %s -> %s', current, desired_num)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100522
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400523 packages = [pkg for pkg, vers in mergemap.items() if vers]
Zdenek Behan508dcce2011-12-05 15:39:32 +0100524 if not packages:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400525 logging.info('Nothing to update!')
David Jamesf8c672f2012-11-06 13:38:11 -0800526 return False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100527
Mike Frysinger3bba5032016-09-20 14:15:04 -0400528 logging.info('Updating packages:')
529 logging.info('%s', packages)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100530
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100531 cmd = [EMERGE_CMD, '--oneshot', '--update']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100532 if usepkg:
533 cmd.extend(['--getbinpkg', '--usepkgonly'])
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700534 if root != '/':
535 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100536
537 cmd.extend(packages)
538 cros_build_lib.RunCommand(cmd)
David Jamesf8c672f2012-11-06 13:38:11 -0800539 return True
Zdenek Behan508dcce2011-12-05 15:39:32 +0100540
541
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700542def CleanTargets(targets, root='/'):
543 """Unmerges old packages that are assumed unnecessary.
544
545 Args:
546 targets: The list of targets to clean up.
547 root: The install root in which we want packages cleaned up.
548 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100549 unmergemap = {}
550 for target in targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400551 logging.debug('Cleaning target %s', target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100552 for package in GetTargetPackages(target):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400553 logging.debug(' Cleaning package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100554 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700555 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100556 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2fcb0aa2015-05-21 14:51:41 -0700557 # NOTE: This refers to installed packages (vartree) rather than the
558 # Portage version (porttree and/or bintree) when determining the current
559 # version. While this isn't the most accurate thing to do, it is probably
560 # a good simple compromise, which should have the desired result of
561 # uninstalling everything but the latest installed version. In
562 # particular, using the bintree (--usebinpkg) requires a non-trivial
563 # binhost sync and is probably more complex than useful.
Zdenek Behan699ddd32012-04-13 07:14:08 +0200564 desired_num = VersionListToNumeric(target, package, desired, True)
565 if not set(desired_num).issubset(current):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400566 logging.warning('Error detecting stable version for %s, '
567 'skipping clean!', pkg)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200568 return
Zdenek Behan508dcce2011-12-05 15:39:32 +0100569 unmergemap[pkg] = set(current).difference(desired_num)
570
571 # Cleaning doesn't care about consistency and rebuilding package.* files.
572 packages = []
573 for pkg, vers in unmergemap.iteritems():
574 packages.extend('=%s-%s' % (pkg, ver) for ver in vers if ver != '9999')
575
576 if packages:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400577 logging.info('Cleaning packages:')
578 logging.info('%s', packages)
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100579 cmd = [EMERGE_CMD, '--unmerge']
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700580 if root != '/':
581 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100582 cmd.extend(packages)
583 cros_build_lib.RunCommand(cmd)
584 else:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400585 logging.info('Nothing to clean!')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100586
587
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700588def SelectActiveToolchains(targets, suffixes, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100589 """Runs gcc-config and binutils-config to select the desired.
590
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500591 Args:
592 targets: The targets to select
593 suffixes: Optional target-specific hacks
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700594 root: The root where we want to select toolchain versions.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100595 """
596 for package in ['gcc', 'binutils']:
597 for target in targets:
Mike Frysinger785b0c32017-09-13 01:35:59 -0400598 # See if this package is part of this target.
599 if package not in GetTargetPackages(target):
600 logging.debug('%s: %s is not used', target, package)
601 continue
602
Zdenek Behan508dcce2011-12-05 15:39:32 +0100603 # Pick the first version in the numbered list as the selected one.
604 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700605 desired_num = VersionListToNumeric(target, package, desired, True,
606 root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100607 desired = desired_num[0]
608 # *-config does not play revisions, strip them, keep just PV.
609 desired = portage.versions.pkgsplit('%s-%s' % (package, desired))[1]
610
Mike Frysinger785b0c32017-09-13 01:35:59 -0400611 if target.startswith('host'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100612 # *-config is the only tool treating host identically (by tuple).
David James27ac4ae2012-12-03 23:16:15 -0800613 target = toolchain.GetHostTuple()
Zdenek Behan508dcce2011-12-05 15:39:32 +0100614
615 # And finally, attach target to it.
616 desired = '%s-%s' % (target, desired)
617
618 # Target specific hacks
619 if package in suffixes:
620 if target in suffixes[package]:
621 desired += suffixes[package][target]
622
David James7ec5efc2012-11-06 09:39:49 -0800623 extra_env = {'CHOST': target}
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700624 if root != '/':
625 extra_env['ROOT'] = root
David James7ec5efc2012-11-06 09:39:49 -0800626 cmd = ['%s-config' % package, '-c', target]
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500627 result = cros_build_lib.RunCommand(
628 cmd, print_cmd=False, redirect_stdout=True, extra_env=extra_env)
629 current = result.output.splitlines()[0]
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700630
631 # Do not reconfig when the current is live or nothing needs to be done.
632 extra_env = {'ROOT': root} if root != '/' else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100633 if current != desired and current != '9999':
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500634 cmd = [package + '-config', desired]
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700635 cros_build_lib.RunCommand(cmd, print_cmd=False, extra_env=extra_env)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100636
637
Mike Frysinger35247af2012-11-16 18:58:06 -0500638def ExpandTargets(targets_wanted):
639 """Expand any possible toolchain aliases into full targets
640
641 This will expand 'all' and 'sdk' into the respective toolchain tuples.
642
643 Args:
644 targets_wanted: The targets specified by the user.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500645
Mike Frysinger35247af2012-11-16 18:58:06 -0500646 Returns:
Gilad Arnold8195b532015-04-07 10:56:30 +0300647 Dictionary of concrete targets and their toolchain tuples.
Mike Frysinger35247af2012-11-16 18:58:06 -0500648 """
Mike Frysinger35247af2012-11-16 18:58:06 -0500649 targets_wanted = set(targets_wanted)
Don Garrettc0c74002015-10-09 12:58:19 -0700650 if targets_wanted == set(['boards']):
651 # Only pull targets from the included boards.
Gilad Arnold8195b532015-04-07 10:56:30 +0300652 return {}
653
654 all_targets = toolchain.GetAllTargets()
Mike Frysinger35247af2012-11-16 18:58:06 -0500655 if targets_wanted == set(['all']):
Gilad Arnold8195b532015-04-07 10:56:30 +0300656 return all_targets
657 if targets_wanted == set(['sdk']):
Mike Frysinger35247af2012-11-16 18:58:06 -0500658 # Filter out all the non-sdk toolchains as we don't want to mess
659 # with those in all of our builds.
Gilad Arnold8195b532015-04-07 10:56:30 +0300660 return toolchain.FilterToolchains(all_targets, 'sdk', True)
661
662 # Verify user input.
663 nonexistent = targets_wanted.difference(all_targets)
664 if nonexistent:
665 raise ValueError('Invalid targets: %s', ','.join(nonexistent))
666 return {t: all_targets[t] for t in targets_wanted}
Mike Frysinger35247af2012-11-16 18:58:06 -0500667
668
David Jamesf8c672f2012-11-06 13:38:11 -0800669def UpdateToolchains(usepkg, deleteold, hostonly, reconfig,
Don Garrettc0c74002015-10-09 12:58:19 -0700670 targets_wanted, boards_wanted, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100671 """Performs all steps to create a synchronized toolchain enviroment.
672
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500673 Args:
674 usepkg: Use prebuilt packages
675 deleteold: Unmerge deprecated packages
676 hostonly: Only setup the host toolchain
677 reconfig: Reload crossdev config and reselect toolchains
678 targets_wanted: All the targets to update
679 boards_wanted: Load targets from these boards
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700680 root: The root in which to install the toolchains.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100681 """
David Jamesf8c672f2012-11-06 13:38:11 -0800682 targets, crossdev_targets, reconfig_targets = {}, {}, {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100683 if not hostonly:
684 # For hostonly, we can skip most of the below logic, much of which won't
685 # work on bare systems where this is useful.
Mike Frysinger35247af2012-11-16 18:58:06 -0500686 targets = ExpandTargets(targets_wanted)
Mike Frysinger7ccee992012-06-01 21:27:59 -0400687
Don Garrettc0c74002015-10-09 12:58:19 -0700688 # Now re-add any targets that might be from this board. This is to
Gilad Arnold8195b532015-04-07 10:56:30 +0300689 # allow unofficial boards to declare their own toolchains.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400690 for board in boards_wanted:
David James27ac4ae2012-12-03 23:16:15 -0800691 targets.update(toolchain.GetToolchainsForBoard(board))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100692
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100693 # First check and initialize all cross targets that need to be.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400694 for target in targets:
695 if TargetIsInitialized(target):
696 reconfig_targets[target] = targets[target]
697 else:
698 crossdev_targets[target] = targets[target]
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100699 if crossdev_targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400700 logging.info('The following targets need to be re-initialized:')
701 logging.info('%s', crossdev_targets)
David James66a09c42012-11-05 13:31:38 -0800702 Crossdev.UpdateTargets(crossdev_targets, usepkg)
Zdenek Behan8be29ba2012-05-29 23:10:34 +0200703 # Those that were not initialized may need a config update.
David James66a09c42012-11-05 13:31:38 -0800704 Crossdev.UpdateTargets(reconfig_targets, usepkg, config_only=True)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100705
Mike Frysinger66814c32017-10-09 18:11:46 -0400706 # If we're building a subset of toolchains for a board, we might not have
707 # all the tuples that the packages expect. We don't define the "full" set
708 # of tuples currently other than "whatever the full sdk has normally".
709 if usepkg or set(('all', 'sdk')) & targets_wanted:
710 # Since we have cross-compilers now, we can update these packages.
711 targets['host-post-cross'] = {}
Mike Frysinger785b0c32017-09-13 01:35:59 -0400712
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100713 # We want host updated.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400714 targets['host'] = {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100715
716 # Now update all packages.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700717 if UpdateTargets(targets, usepkg, root=root) or crossdev_targets or reconfig:
718 SelectActiveToolchains(targets, CONFIG_TARGET_SUFFIXES, root=root)
David James7ec5efc2012-11-06 09:39:49 -0800719
720 if deleteold:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700721 CleanTargets(targets, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100722
Mike Frysingerc880a962013-11-08 13:59:06 -0500723 # Now that we've cleared out old versions, see if we need to rebuild
724 # anything. Can't do this earlier as it might not be broken.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700725 RebuildLibtool(root=root)
Mike Frysingerc880a962013-11-08 13:59:06 -0500726
Zdenek Behan508dcce2011-12-05 15:39:32 +0100727
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -0700728def ShowConfig(name):
729 """Show the toolchain tuples used by |name|
Mike Frysinger35247af2012-11-16 18:58:06 -0500730
731 Args:
Don Garrettc0c74002015-10-09 12:58:19 -0700732 name: The board name to query.
Mike Frysinger35247af2012-11-16 18:58:06 -0500733 """
Don Garrettc0c74002015-10-09 12:58:19 -0700734 toolchains = toolchain.GetToolchainsForBoard(name)
Mike Frysinger35247af2012-11-16 18:58:06 -0500735 # Make sure we display the default toolchain first.
Mike Frysinger3bba5032016-09-20 14:15:04 -0400736 # Note: Do not use logging here as this is meant to be used by other tools.
Mike Frysinger383367e2014-09-16 15:06:17 -0400737 print(','.join(
David James27ac4ae2012-12-03 23:16:15 -0800738 toolchain.FilterToolchains(toolchains, 'default', True).keys() +
Mike Frysinger383367e2014-09-16 15:06:17 -0400739 toolchain.FilterToolchains(toolchains, 'default', False).keys()))
Mike Frysinger35247af2012-11-16 18:58:06 -0500740
741
Mike Frysinger35247af2012-11-16 18:58:06 -0500742def GeneratePathWrapper(root, wrappath, path):
743 """Generate a shell script to execute another shell script
744
745 Since we can't symlink a wrapped ELF (see GenerateLdsoWrapper) because the
746 argv[0] won't be pointing to the correct path, generate a shell script that
747 just executes another program with its full path.
748
749 Args:
750 root: The root tree to generate scripts inside of
751 wrappath: The full path (inside |root|) to create the wrapper
752 path: The target program which this wrapper will execute
753 """
754 replacements = {
755 'path': path,
756 'relroot': os.path.relpath('/', os.path.dirname(wrappath)),
757 }
758 wrapper = """#!/bin/sh
759base=$(realpath "$0")
760basedir=${base%%/*}
761exec "${basedir}/%(relroot)s%(path)s" "$@"
762""" % replacements
763 root_wrapper = root + wrappath
764 if os.path.islink(root_wrapper):
765 os.unlink(root_wrapper)
766 else:
767 osutils.SafeMakedirs(os.path.dirname(root_wrapper))
768 osutils.WriteFile(root_wrapper, wrapper)
Mike Frysinger60ec1012013-10-21 00:11:10 -0400769 os.chmod(root_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -0500770
771
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -0700772def FixClangXXWrapper(root, path):
773 """Fix wrapper shell scripts and symlinks for invoking clang++
774
775 In a typical installation, clang++ symlinks to clang, which symlinks to the
776 elf executable. The executable distinguishes between clang and clang++ based
777 on argv[0].
778
779 When invoked through the LdsoWrapper, argv[0] always contains the path to the
780 executable elf file, making clang/clang++ invocations indistinguishable.
781
782 This function detects if the elf executable being wrapped is clang-X.Y, and
783 fixes wrappers/symlinks as necessary so that clang++ will work correctly.
784
785 The calling sequence now becomes:
786 -) clang++ invocation turns into clang++-3.9 (which is a copy of clang-3.9,
787 the Ldsowrapper).
788 -) clang++-3.9 uses the Ldso to invoke clang++-3.9.elf, which is a symlink
789 to the original clang-3.9 elf.
790 -) The difference this time is that inside the elf file execution, $0 is
791 set as .../usr/bin/clang++-3.9.elf, which contains 'clang++' in the name.
792
793 Args:
794 root: The root tree to generate scripts / symlinks inside of
795 path: The target elf for which LdsoWrapper was created
796 """
797 if re.match(r'/usr/bin/clang-\d+\.\d+$', path):
798 logging.info('fixing clang++ invocation for %s', path)
799 clangdir = os.path.dirname(root + path)
800 clang = os.path.basename(path)
801 clangxx = clang.replace('clang', 'clang++')
802
803 # Create a symlink clang++-X.Y.elf to point to clang-X.Y.elf
804 os.symlink(clang + '.elf', os.path.join(clangdir, clangxx + '.elf'))
805
806 # Create a hardlink clang++-X.Y pointing to clang-X.Y
807 os.link(os.path.join(clangdir, clang), os.path.join(clangdir, clangxx))
808
809 # Adjust the clang++ symlink to point to clang++-X.Y
810 os.unlink(os.path.join(clangdir, 'clang++'))
811 os.symlink(clangxx, os.path.join(clangdir, 'clang++'))
812
813
Mike Frysinger35247af2012-11-16 18:58:06 -0500814def FileIsCrosSdkElf(elf):
815 """Determine if |elf| is an ELF that we execute in the cros_sdk
816
817 We don't need this to be perfect, just quick. It makes sure the ELF
818 is a 64bit LSB x86_64 ELF. That is the native type of cros_sdk.
819
820 Args:
821 elf: The file to check
Mike Frysinger1a736a82013-12-12 01:50:59 -0500822
Mike Frysinger35247af2012-11-16 18:58:06 -0500823 Returns:
824 True if we think |elf| is a native ELF
825 """
826 with open(elf) as f:
827 data = f.read(20)
828 # Check the magic number, EI_CLASS, EI_DATA, and e_machine.
829 return (data[0:4] == '\x7fELF' and
830 data[4] == '\x02' and
831 data[5] == '\x01' and
832 data[18] == '\x3e')
833
834
835def IsPathPackagable(ptype, path):
836 """Should the specified file be included in a toolchain package?
837
838 We only need to handle files as we'll create dirs as we need them.
839
840 Further, trim files that won't be useful:
841 - non-english translations (.mo) since it'd require env vars
842 - debug files since these are for the host compiler itself
843 - info/man pages as they're big, and docs are online, and the
844 native docs should work fine for the most part (`man gcc`)
845
846 Args:
847 ptype: A string describing the path type (i.e. 'file' or 'dir' or 'sym')
848 path: The full path to inspect
Mike Frysinger1a736a82013-12-12 01:50:59 -0500849
Mike Frysinger35247af2012-11-16 18:58:06 -0500850 Returns:
851 True if we want to include this path in the package
852 """
853 return not (ptype in ('dir',) or
854 path.startswith('/usr/lib/debug/') or
855 os.path.splitext(path)[1] == '.mo' or
856 ('/man/' in path or '/info/' in path))
857
858
859def ReadlinkRoot(path, root):
860 """Like os.readlink(), but relative to a |root|
861
862 Args:
863 path: The symlink to read
864 root: The path to use for resolving absolute symlinks
Mike Frysinger1a736a82013-12-12 01:50:59 -0500865
Mike Frysinger35247af2012-11-16 18:58:06 -0500866 Returns:
867 A fully resolved symlink path
868 """
869 while os.path.islink(root + path):
870 path = os.path.join(os.path.dirname(path), os.readlink(root + path))
871 return path
872
873
874def _GetFilesForTarget(target, root='/'):
875 """Locate all the files to package for |target|
876
877 This does not cover ELF dependencies.
878
879 Args:
880 target: The toolchain target name
881 root: The root path to pull all packages from
Mike Frysinger1a736a82013-12-12 01:50:59 -0500882
Mike Frysinger35247af2012-11-16 18:58:06 -0500883 Returns:
884 A tuple of a set of all packable paths, and a set of all paths which
885 are also native ELFs
886 """
887 paths = set()
888 elfs = set()
889
890 # Find all the files owned by the packages for this target.
891 for pkg in GetTargetPackages(target):
Mike Frysinger35247af2012-11-16 18:58:06 -0500892
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700893 # Skip Go compiler from redistributable packages.
894 # The "go" executable has GOROOT=/usr/lib/go/${CTARGET} hardcoded
895 # into it. Due to this, the toolchain cannot be unpacked anywhere
896 # else and be readily useful. To enable packaging Go, we need to:
897 # -) Tweak the wrappers/environment to override GOROOT
898 # automatically based on the unpack location.
899 # -) Make sure the ELF dependency checking and wrapping logic
900 # below skips the Go toolchain executables and libraries.
901 # -) Make sure the packaging process maintains the relative
902 # timestamps of precompiled standard library packages.
903 # (see dev-lang/go ebuild for details).
904 if pkg == 'ex_go':
905 continue
906
Mike Frysinger35247af2012-11-16 18:58:06 -0500907 atom = GetPortagePackage(target, pkg)
908 cat, pn = atom.split('/')
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700909 ver = GetInstalledPackageVersions(atom, root=root)[0]
Ralph Nathan03047282015-03-23 11:09:32 -0700910 logging.info('packaging %s-%s', atom, ver)
Mike Frysinger35247af2012-11-16 18:58:06 -0500911
912 # pylint: disable=E1101
913 dblink = portage.dblink(cat, pn + '-' + ver, myroot=root,
914 settings=portage.settings)
915 contents = dblink.getcontents()
916 for obj in contents:
917 ptype = contents[obj][0]
918 if not IsPathPackagable(ptype, obj):
919 continue
920
921 if ptype == 'obj':
922 # For native ELFs, we need to pull in their dependencies too.
923 if FileIsCrosSdkElf(obj):
924 elfs.add(obj)
925 paths.add(obj)
926
927 return paths, elfs
928
929
930def _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500931 path_rewrite_func=lambda x: x, root='/'):
Mike Frysinger35247af2012-11-16 18:58:06 -0500932 """Link in all packable files and their runtime dependencies
933
934 This also wraps up executable ELFs with helper scripts.
935
936 Args:
937 output_dir: The output directory to store files
938 paths: All the files to include
939 elfs: All the files which are ELFs (a subset of |paths|)
940 ldpaths: A dict of static ldpath information
941 path_rewrite_func: User callback to rewrite paths in output_dir
942 root: The root path to pull all packages/files from
943 """
944 # Link in all the files.
Mike Frysinger221bd822017-09-29 02:51:47 -0400945 sym_paths = {}
Mike Frysinger35247af2012-11-16 18:58:06 -0500946 for path in paths:
947 new_path = path_rewrite_func(path)
948 dst = output_dir + new_path
949 osutils.SafeMakedirs(os.path.dirname(dst))
950
951 # Is this a symlink which we have to rewrite or wrap?
952 # Delay wrap check until after we have created all paths.
953 src = root + path
954 if os.path.islink(src):
955 tgt = os.readlink(src)
956 if os.path.sep in tgt:
Mike Frysinger221bd822017-09-29 02:51:47 -0400957 sym_paths[lddtree.normpath(ReadlinkRoot(src, root))] = new_path
Mike Frysinger35247af2012-11-16 18:58:06 -0500958
959 # Rewrite absolute links to relative and then generate the symlink
960 # ourselves. All other symlinks can be hardlinked below.
961 if tgt[0] == '/':
962 tgt = os.path.relpath(tgt, os.path.dirname(new_path))
963 os.symlink(tgt, dst)
964 continue
965
966 os.link(src, dst)
967
Mike Frysinger35247af2012-11-16 18:58:06 -0500968 # Locate all the dependencies for all the ELFs. Stick them all in the
969 # top level "lib" dir to make the wrapper simpler. This exact path does
970 # not matter since we execute ldso directly, and we tell the ldso the
971 # exact path to search for its libraries.
972 libdir = os.path.join(output_dir, 'lib')
973 osutils.SafeMakedirs(libdir)
974 donelibs = set()
Mike Frysinger4331fc62017-09-28 14:03:25 -0400975 glibc_re = re.compile(r'/lib(c|pthread)-[0-9.]+\.so$')
Mike Frysinger35247af2012-11-16 18:58:06 -0500976 for elf in elfs:
Mike Frysingerea7688e2014-07-31 22:40:33 -0400977 e = lddtree.ParseELF(elf, root=root, ldpaths=ldpaths)
Mike Frysinger35247af2012-11-16 18:58:06 -0500978 interp = e['interp']
Yunlian Jiang196e8f42017-09-20 12:29:47 -0700979 # Do not create wrapper for libc. crbug.com/766827
980 if interp and not glibc_re.search(elf):
Mike Frysinger35247af2012-11-16 18:58:06 -0500981 # Generate a wrapper if it is executable.
Mike Frysingerc2ec0902013-03-26 01:28:45 -0400982 interp = os.path.join('/lib', os.path.basename(interp))
983 lddtree.GenerateLdsoWrapper(output_dir, path_rewrite_func(elf), interp,
984 libpaths=e['rpath'] + e['runpath'])
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -0700985 FixClangXXWrapper(output_dir, path_rewrite_func(elf))
Mike Frysinger35247af2012-11-16 18:58:06 -0500986
Mike Frysinger221bd822017-09-29 02:51:47 -0400987 # Wrap any symlinks to the wrapper.
988 if elf in sym_paths:
989 link = sym_paths[elf]
990 GeneratePathWrapper(output_dir, link, elf)
991
Mike Frysinger35247af2012-11-16 18:58:06 -0500992 for lib, lib_data in e['libs'].iteritems():
993 if lib in donelibs:
994 continue
995
996 src = path = lib_data['path']
997 if path is None:
Ralph Nathan446aee92015-03-23 14:44:56 -0700998 logging.warning('%s: could not locate %s', elf, lib)
Mike Frysinger35247af2012-11-16 18:58:06 -0500999 continue
1000 donelibs.add(lib)
1001
1002 # Needed libs are the SONAME, but that is usually a symlink, not a
1003 # real file. So link in the target rather than the symlink itself.
1004 # We have to walk all the possible symlinks (SONAME could point to a
1005 # symlink which points to a symlink), and we have to handle absolute
1006 # ourselves (since we have a "root" argument).
1007 dst = os.path.join(libdir, os.path.basename(path))
1008 src = ReadlinkRoot(src, root)
1009
1010 os.link(root + src, dst)
1011
1012
1013def _EnvdGetVar(envd, var):
1014 """Given a Gentoo env.d file, extract a var from it
1015
1016 Args:
1017 envd: The env.d file to load (may be a glob path)
1018 var: The var to extract
Mike Frysinger1a736a82013-12-12 01:50:59 -05001019
Mike Frysinger35247af2012-11-16 18:58:06 -05001020 Returns:
1021 The value of |var|
1022 """
1023 envds = glob.glob(envd)
1024 assert len(envds) == 1, '%s: should have exactly 1 env.d file' % envd
1025 envd = envds[0]
1026 return cros_build_lib.LoadKeyValueFile(envd)[var]
1027
1028
1029def _ProcessBinutilsConfig(target, output_dir):
1030 """Do what binutils-config would have done"""
1031 binpath = os.path.join('/bin', target + '-')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001032
1033 # Locate the bin dir holding the gold linker.
1034 binutils_bin_path = os.path.join(output_dir, 'usr', toolchain.GetHostTuple(),
1035 target, 'binutils-bin')
1036 globpath = os.path.join(binutils_bin_path, '*-gold')
Mike Frysinger35247af2012-11-16 18:58:06 -05001037 srcpath = glob.glob(globpath)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001038 if not srcpath:
1039 # Maybe this target doesn't support gold.
1040 globpath = os.path.join(binutils_bin_path, '*')
1041 srcpath = glob.glob(globpath)
1042 assert len(srcpath) == 1, ('%s: matched more than one path (but not *-gold)'
1043 % globpath)
1044 srcpath = srcpath[0]
1045 ld_path = os.path.join(srcpath, 'ld')
1046 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1047 ld_path = os.path.join(srcpath, 'ld.bfd')
1048 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1049 ld_path = os.path.join(srcpath, 'ld.gold')
1050 assert not os.path.exists(ld_path), ('%s: exists, but gold dir does not!'
1051 % ld_path)
1052
1053 # Nope, no gold support to be found.
1054 gold_supported = False
Ralph Nathan446aee92015-03-23 14:44:56 -07001055 logging.warning('%s: binutils lacks support for the gold linker', target)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001056 else:
1057 assert len(srcpath) == 1, '%s: did not match exactly 1 path' % globpath
Mike Frysinger78b7a812014-11-26 19:45:23 -05001058 srcpath = srcpath[0]
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001059
Rahul Chaudhry4891b4d2017-03-08 10:31:27 -08001060 # Package the binutils-bin directory without the '-gold' suffix
1061 # if gold is not enabled as the default linker for this target.
1062 gold_supported = CONFIG_TARGET_SUFFIXES['binutils'].get(target) == '-gold'
1063 if not gold_supported:
1064 srcpath = srcpath[:-len('-gold')]
1065 ld_path = os.path.join(srcpath, 'ld')
1066 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1067
Mike Frysinger78b7a812014-11-26 19:45:23 -05001068 srcpath = srcpath[len(output_dir):]
Mike Frysinger35247af2012-11-16 18:58:06 -05001069 gccpath = os.path.join('/usr', 'libexec', 'gcc')
1070 for prog in os.listdir(output_dir + srcpath):
1071 # Skip binaries already wrapped.
1072 if not prog.endswith('.real'):
1073 GeneratePathWrapper(output_dir, binpath + prog,
1074 os.path.join(srcpath, prog))
1075 GeneratePathWrapper(output_dir, os.path.join(gccpath, prog),
1076 os.path.join(srcpath, prog))
1077
David James27ac4ae2012-12-03 23:16:15 -08001078 libpath = os.path.join('/usr', toolchain.GetHostTuple(), target, 'lib')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001079 envd = os.path.join(output_dir, 'etc', 'env.d', 'binutils', '*')
1080 if gold_supported:
1081 envd += '-gold'
Rahul Chaudhry4891b4d2017-03-08 10:31:27 -08001082 else:
1083 # If gold is not enabled as the default linker and 2 env.d
1084 # files exist, pick the one without the '-gold' suffix.
1085 envds = sorted(glob.glob(envd))
1086 if len(envds) == 2 and envds[1] == envds[0] + '-gold':
1087 envd = envds[0]
Mike Frysinger35247af2012-11-16 18:58:06 -05001088 srcpath = _EnvdGetVar(envd, 'LIBPATH')
1089 os.symlink(os.path.relpath(srcpath, os.path.dirname(libpath)),
1090 output_dir + libpath)
1091
1092
1093def _ProcessGccConfig(target, output_dir):
1094 """Do what gcc-config would have done"""
1095 binpath = '/bin'
1096 envd = os.path.join(output_dir, 'etc', 'env.d', 'gcc', '*')
1097 srcpath = _EnvdGetVar(envd, 'GCC_PATH')
1098 for prog in os.listdir(output_dir + srcpath):
1099 # Skip binaries already wrapped.
1100 if (not prog.endswith('.real') and
1101 not prog.endswith('.elf') and
1102 prog.startswith(target)):
1103 GeneratePathWrapper(output_dir, os.path.join(binpath, prog),
1104 os.path.join(srcpath, prog))
1105 return srcpath
1106
1107
Frank Henigman179ec7c2015-02-06 03:01:09 -05001108def _ProcessSysrootWrappers(_target, output_dir, srcpath):
1109 """Remove chroot-specific things from our sysroot wrappers"""
Mike Frysinger35247af2012-11-16 18:58:06 -05001110 # Disable ccache since we know it won't work outside of chroot.
Frank Henigman179ec7c2015-02-06 03:01:09 -05001111 for sysroot_wrapper in glob.glob(os.path.join(
1112 output_dir + srcpath, 'sysroot_wrapper*')):
1113 contents = osutils.ReadFile(sysroot_wrapper).splitlines()
1114 for num in xrange(len(contents)):
1115 if '@CCACHE_DEFAULT@' in contents[num]:
Caroline Ticece9e9232017-06-02 09:38:42 -07001116 assert 'True' in contents[num]
1117 contents[num] = contents[num].replace('True', 'False')
Frank Henigman179ec7c2015-02-06 03:01:09 -05001118 break
1119 # Can't update the wrapper in place since it's a hardlink to a file in /.
1120 os.unlink(sysroot_wrapper)
1121 osutils.WriteFile(sysroot_wrapper, '\n'.join(contents))
1122 os.chmod(sysroot_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -05001123
1124
Yunlian Jiang5ad6b512017-09-20 09:27:45 -07001125def _CreateMainLibDir(target, output_dir):
1126 """Create some lib dirs so that compiler can get the right Gcc paths"""
1127 osutils.SafeMakedirs(os.path.join(output_dir, 'usr', target, 'lib'))
1128 osutils.SafeMakedirs(os.path.join(output_dir, 'usr', target, 'usr/lib'))
1129
1130
Mike Frysinger35247af2012-11-16 18:58:06 -05001131def _ProcessDistroCleanups(target, output_dir):
1132 """Clean up the tree and remove all distro-specific requirements
1133
1134 Args:
1135 target: The toolchain target name
1136 output_dir: The output directory to clean up
1137 """
1138 _ProcessBinutilsConfig(target, output_dir)
1139 gcc_path = _ProcessGccConfig(target, output_dir)
Frank Henigman179ec7c2015-02-06 03:01:09 -05001140 _ProcessSysrootWrappers(target, output_dir, gcc_path)
Yunlian Jiang5ad6b512017-09-20 09:27:45 -07001141 _CreateMainLibDir(target, output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001142
1143 osutils.RmDir(os.path.join(output_dir, 'etc'))
1144
1145
1146def CreatePackagableRoot(target, output_dir, ldpaths, root='/'):
1147 """Setup a tree from the packages for the specified target
1148
1149 This populates a path with all the files from toolchain packages so that
1150 a tarball can easily be generated from the result.
1151
1152 Args:
1153 target: The target to create a packagable root from
1154 output_dir: The output directory to place all the files
1155 ldpaths: A dict of static ldpath information
1156 root: The root path to pull all packages/files from
1157 """
1158 # Find all the files owned by the packages for this target.
1159 paths, elfs = _GetFilesForTarget(target, root=root)
1160
1161 # Link in all the package's files, any ELF dependencies, and wrap any
1162 # executable ELFs with helper scripts.
1163 def MoveUsrBinToBin(path):
Han Shen699ea192016-03-02 10:42:47 -08001164 """Move /usr/bin to /bin so people can just use that toplevel dir
1165
1166 Note we do not apply this to clang - there is correlation between clang's
1167 search path for libraries / inclusion and its installation path.
1168 """
1169 if path.startswith('/usr/bin/') and path.find('clang') == -1:
1170 return path[4:]
1171 return path
Mike Frysinger35247af2012-11-16 18:58:06 -05001172 _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
1173 path_rewrite_func=MoveUsrBinToBin, root=root)
1174
1175 # The packages, when part of the normal distro, have helper scripts
1176 # that setup paths and such. Since we are making this standalone, we
1177 # need to preprocess all that ourselves.
1178 _ProcessDistroCleanups(target, output_dir)
1179
1180
1181def CreatePackages(targets_wanted, output_dir, root='/'):
1182 """Create redistributable cross-compiler packages for the specified targets
1183
1184 This creates toolchain packages that should be usable in conjunction with
1185 a downloaded sysroot (created elsewhere).
1186
1187 Tarballs (one per target) will be created in $PWD.
1188
1189 Args:
Don Garrett25f309a2014-03-19 14:02:12 -07001190 targets_wanted: The targets to package up.
1191 output_dir: The directory to put the packages in.
1192 root: The root path to pull all packages/files from.
Mike Frysinger35247af2012-11-16 18:58:06 -05001193 """
Ralph Nathan03047282015-03-23 11:09:32 -07001194 logging.info('Writing tarballs to %s', output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001195 osutils.SafeMakedirs(output_dir)
1196 ldpaths = lddtree.LoadLdpaths(root)
1197 targets = ExpandTargets(targets_wanted)
1198
Mike Frysinger221bd822017-09-29 02:51:47 -04001199 with osutils.TempDir(prefix='create-packages') as tempdir:
1200 logging.debug('Using tempdir: %s', tempdir)
1201
Mike Frysinger35247af2012-11-16 18:58:06 -05001202 # We have to split the root generation from the compression stages. This is
1203 # because we hardlink in all the files (to avoid overhead of reading/writing
1204 # the copies multiple times). But tar gets angry if a file's hardlink count
1205 # changes from when it starts reading a file to when it finishes.
1206 with parallel.BackgroundTaskRunner(CreatePackagableRoot) as queue:
1207 for target in targets:
1208 output_target_dir = os.path.join(tempdir, target)
1209 queue.put([target, output_target_dir, ldpaths, root])
1210
1211 # Build the tarball.
1212 with parallel.BackgroundTaskRunner(cros_build_lib.CreateTarball) as queue:
1213 for target in targets:
1214 tar_file = os.path.join(output_dir, target + '.tar.xz')
1215 queue.put([tar_file, os.path.join(tempdir, target)])
1216
1217
Mike Frysinger07534cf2017-09-12 17:40:21 -04001218def GetParser():
1219 """Return a command line parser."""
Mike Frysinger0c808452014-11-06 17:30:23 -05001220 parser = commandline.ArgumentParser(description=__doc__)
1221 parser.add_argument('-u', '--nousepkg',
1222 action='store_false', dest='usepkg', default=True,
1223 help='Use prebuilt packages if possible')
1224 parser.add_argument('-d', '--deleteold',
1225 action='store_true', dest='deleteold', default=False,
1226 help='Unmerge deprecated packages')
1227 parser.add_argument('-t', '--targets',
1228 dest='targets', default='sdk',
Gilad Arnold8195b532015-04-07 10:56:30 +03001229 help="Comma separated list of tuples. Special keywords "
Don Garrettc0c74002015-10-09 12:58:19 -07001230 "'host', 'sdk', 'boards', and 'all' are "
Gilad Arnold8195b532015-04-07 10:56:30 +03001231 "allowed. Defaults to 'sdk'.")
1232 parser.add_argument('--include-boards', default='', metavar='BOARDS',
1233 help='Comma separated list of boards whose toolchains we '
1234 'will always include. Default: none')
Mike Frysinger0c808452014-11-06 17:30:23 -05001235 parser.add_argument('--hostonly',
1236 dest='hostonly', default=False, action='store_true',
1237 help='Only setup the host toolchain. '
1238 'Useful for bootstrapping chroot')
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001239 parser.add_argument('--show-board-cfg', '--show-cfg',
1240 dest='cfg_name', default=None,
Don Garrettc0c74002015-10-09 12:58:19 -07001241 help='Board to list toolchains tuples for')
Mike Frysinger91f52882017-09-13 00:16:58 -04001242 parser.add_argument('--show-packages', default=None,
1243 help='List all packages the specified target uses')
Mike Frysinger0c808452014-11-06 17:30:23 -05001244 parser.add_argument('--create-packages',
1245 action='store_true', default=False,
1246 help='Build redistributable packages')
1247 parser.add_argument('--output-dir', default=os.getcwd(), type='path',
1248 help='Output directory')
1249 parser.add_argument('--reconfig', default=False, action='store_true',
1250 help='Reload crossdev config and reselect toolchains')
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001251 parser.add_argument('--sysroot', type='path',
1252 help='The sysroot in which to install the toolchains')
Mike Frysinger07534cf2017-09-12 17:40:21 -04001253 return parser
Zdenek Behan508dcce2011-12-05 15:39:32 +01001254
Mike Frysinger07534cf2017-09-12 17:40:21 -04001255
1256def main(argv):
1257 parser = GetParser()
Mike Frysinger0c808452014-11-06 17:30:23 -05001258 options = parser.parse_args(argv)
1259 options.Freeze()
Zdenek Behan508dcce2011-12-05 15:39:32 +01001260
Mike Frysinger35247af2012-11-16 18:58:06 -05001261 # Figure out what we're supposed to do and reject conflicting options.
Mike Frysinger91f52882017-09-13 00:16:58 -04001262 conflicting_options = (
1263 options.cfg_name,
1264 options.show_packages,
1265 options.create_packages,
1266 )
1267 if sum(bool(x) for x in conflicting_options) > 1:
1268 parser.error('conflicting options: create-packages & show-packages & '
1269 'show-board-cfg')
Mike Frysinger984d0622012-06-01 16:08:44 -04001270
Gilad Arnold8195b532015-04-07 10:56:30 +03001271 targets_wanted = set(options.targets.split(','))
1272 boards_wanted = (set(options.include_boards.split(','))
1273 if options.include_boards else set())
Mike Frysinger35247af2012-11-16 18:58:06 -05001274
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001275 if options.cfg_name:
1276 ShowConfig(options.cfg_name)
Mike Frysinger91f52882017-09-13 00:16:58 -04001277 elif options.show_packages is not None:
1278 cros_build_lib.AssertInsideChroot()
1279 target = options.show_packages
1280 Crossdev.Load(False)
1281 for package in GetTargetPackages(target):
1282 print(GetPortagePackage(target, package))
Mike Frysinger35247af2012-11-16 18:58:06 -05001283 elif options.create_packages:
1284 cros_build_lib.AssertInsideChroot()
1285 Crossdev.Load(False)
Gilad Arnold8195b532015-04-07 10:56:30 +03001286 CreatePackages(targets_wanted, options.output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001287 else:
1288 cros_build_lib.AssertInsideChroot()
1289 # This has to be always run as root.
1290 if os.geteuid() != 0:
1291 cros_build_lib.Die('this script must be run as root')
1292
1293 Crossdev.Load(options.reconfig)
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001294 root = options.sysroot or '/'
Mike Frysinger35247af2012-11-16 18:58:06 -05001295 UpdateToolchains(options.usepkg, options.deleteold, options.hostonly,
Gilad Arnold8195b532015-04-07 10:56:30 +03001296 options.reconfig, targets_wanted, boards_wanted,
Don Garrettc0c74002015-10-09 12:58:19 -07001297 root=root)
Mike Frysinger35247af2012-11-16 18:58:06 -05001298 Crossdev.Save()
1299
1300 return 0