blob: 27708dd4713cfaf987d58b83ad44a90e953ae0c4 [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
Yunlian Jiang85c606a2017-10-10 20:58:53 -0700258 # Build target by the alphabetical order to make sure
259 # armv7a-cros-linux-gnueabihf builds after armv7a-cros-linux-gnueabi
260 # because some dependency issue. This can be reverted once we
261 # migrated to armv7a-cros-linux-gnueabihf. crbug.com/711369
262 for target in sorted(targets):
David James66a09c42012-11-05 13:31:38 -0800263 if config_only and target in configured_targets:
264 continue
265
266 cmd = cmdbase + ['-t', target]
267
268 for pkg in GetTargetPackages(target):
269 if pkg == 'gdb':
270 # Gdb does not have selectable versions.
271 cmd.append('--ex-gdb')
Manoj Guptab8181562017-05-21 10:18:59 -0700272 elif pkg == 'ex_compiler-rt':
273 cmd.extend(CROSSDEV_COMPILER_RT_ARGS)
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700274 elif pkg == 'ex_go':
275 # Go does not have selectable versions.
276 cmd.extend(CROSSDEV_GO_ARGS)
Manoj Gupta946abb42017-04-12 14:27:19 -0700277 elif pkg in LLVM_PKGS_TABLE:
278 cmd.extend(LLVM_PKGS_TABLE[pkg])
Han Shene23782f2016-02-18 12:20:00 -0800279 elif pkg in cls.MANUAL_PKGS:
280 pass
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700281 else:
282 # The first of the desired versions is the "primary" one.
283 version = GetDesiredPackageVersions(target, pkg)[0]
284 cmd.extend(['--%s' % pkg, version])
David James66a09c42012-11-05 13:31:38 -0800285
286 cmd.extend(targets[target]['crossdev'].split())
287 if config_only:
288 # In this case we want to just quietly reinit
289 cmd.append('--init-target')
290 cros_build_lib.RunCommand(cmd, print_cmd=False, redirect_stdout=True)
291 else:
292 cros_build_lib.RunCommand(cmd)
293
294 configured_targets.append(target)
295
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100296
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100297def GetTargetPackages(target):
298 """Returns a list of packages for a given target."""
David James66a09c42012-11-05 13:31:38 -0800299 conf = Crossdev.GetConfig(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100300 # Undesired packages are denoted by empty ${pkg}_pn variable.
Han Shene23782f2016-02-18 12:20:00 -0800301 return [x for x in conf['crosspkgs'] if conf.get(x+'_pn')]
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100302
303
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100304# Portage helper functions:
305def GetPortagePackage(target, package):
306 """Returns a package name for the given target."""
David James66a09c42012-11-05 13:31:38 -0800307 conf = Crossdev.GetConfig(target)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100308 # Portage category:
Mike Frysinger785b0c32017-09-13 01:35:59 -0400309 if target.startswith('host') or package in Crossdev.MANUAL_PKGS:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100310 category = conf[package + '_category']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100311 else:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100312 category = conf['category']
313 # Portage package:
314 pn = conf[package + '_pn']
315 # Final package name:
Mike Frysinger422faf42014-11-12 23:16:48 -0500316 assert category
317 assert pn
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100318 return '%s/%s' % (category, pn)
319
320
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700321def PortageTrees(root):
322 """Return the portage trees for a given root."""
323 if root == '/':
324 return portage.db['/']
325 # The portage logic requires the path always end in a slash.
326 root = root.rstrip('/') + '/'
327 return portage.create_trees(target_root=root, config_root=root)[root]
328
329
330def GetInstalledPackageVersions(atom, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100331 """Extracts the list of current versions of a target, package pair.
332
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500333 Args:
334 atom: The atom to operate on (e.g. sys-devel/gcc)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700335 root: The root to check for installed packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100336
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500337 Returns:
338 The list of versions of the package currently installed.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100339 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100340 versions = []
Mike Frysinger506e75f2012-12-17 14:21:13 -0500341 # pylint: disable=E1101
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700342 for pkg in PortageTrees(root)['vartree'].dbapi.match(atom, use_cache=0):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100343 version = portage.versions.cpv_getversion(pkg)
344 versions.append(version)
345 return versions
346
347
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700348def GetStablePackageVersion(atom, installed, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100349 """Extracts the current stable version for a given package.
350
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500351 Args:
352 atom: The target/package to operate on eg. i686-pc-linux-gnu,gcc
353 installed: Whether we want installed packages or ebuilds
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700354 root: The root to use when querying packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100355
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500356 Returns:
357 A string containing the latest version.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100358 """
David James90239b92012-11-05 15:31:34 -0800359 pkgtype = 'vartree' if installed else 'porttree'
Mike Frysinger506e75f2012-12-17 14:21:13 -0500360 # pylint: disable=E1101
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700361 cpv = portage.best(PortageTrees(root)[pkgtype].dbapi.match(atom, use_cache=0))
David James90239b92012-11-05 15:31:34 -0800362 return portage.versions.cpv_getversion(cpv) if cpv else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100363
364
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700365def VersionListToNumeric(target, package, versions, installed, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100366 """Resolves keywords in a given version list for a particular package.
367
368 Resolving means replacing PACKAGE_STABLE with the actual number.
369
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500370 Args:
371 target: The target to operate on (e.g. i686-pc-linux-gnu)
372 package: The target/package to operate on (e.g. gcc)
373 versions: List of versions to resolve
374 installed: Query installed packages
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700375 root: The install root to use; ignored if |installed| is False.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100376
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500377 Returns:
378 List of purely numeric versions equivalent to argument
Zdenek Behan508dcce2011-12-05 15:39:32 +0100379 """
380 resolved = []
David James90239b92012-11-05 15:31:34 -0800381 atom = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700382 if not installed:
383 root = '/'
Zdenek Behan508dcce2011-12-05 15:39:32 +0100384 for version in versions:
385 if version == PACKAGE_STABLE:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700386 resolved.append(GetStablePackageVersion(atom, installed, root=root))
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400387 else:
Zdenek Behan508dcce2011-12-05 15:39:32 +0100388 resolved.append(version)
389 return resolved
390
391
392def GetDesiredPackageVersions(target, package):
393 """Produces the list of desired versions for each target, package pair.
394
395 The first version in the list is implicitly treated as primary, ie.
396 the version that will be initialized by crossdev and selected.
397
398 If the version is PACKAGE_STABLE, it really means the current version which
399 is emerged by using the package atom with no particular version key.
400 Since crossdev unmasks all packages by default, this will actually
401 mean 'unstable' in most cases.
402
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500403 Args:
404 target: The target to operate on (e.g. i686-pc-linux-gnu)
405 package: The target/package to operate on (e.g. gcc)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100406
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500407 Returns:
408 A list composed of either a version string, PACKAGE_STABLE
Zdenek Behan508dcce2011-12-05 15:39:32 +0100409 """
Mike Frysingerd23be272017-09-12 17:18:44 -0400410 if package in GetTargetPackages(target):
411 return [PACKAGE_STABLE]
412 else:
413 return []
Zdenek Behan508dcce2011-12-05 15:39:32 +0100414
415
416def TargetIsInitialized(target):
417 """Verifies if the given list of targets has been correctly initialized.
418
419 This determines whether we have to call crossdev while emerging
420 toolchain packages or can do it using emerge. Emerge is naturally
421 preferred, because all packages can be updated in a single pass.
422
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500423 Args:
424 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100425
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500426 Returns:
427 True if |target| is completely initialized, else False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100428 """
429 # Check if packages for the given target all have a proper version.
430 try:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100431 for package in GetTargetPackages(target):
David James66a09c42012-11-05 13:31:38 -0800432 atom = GetPortagePackage(target, package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100433 # Do we even want this package && is it initialized?
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400434 if not (GetStablePackageVersion(atom, True) and
435 GetStablePackageVersion(atom, False)):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100436 return False
437 return True
438 except cros_build_lib.RunCommandError:
439 # Fails - The target has likely never been initialized before.
440 return False
441
442
443def RemovePackageMask(target):
444 """Removes a package.mask file for the given platform.
445
446 The pre-existing package.mask files can mess with the keywords.
447
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500448 Args:
449 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100450 """
451 maskfile = os.path.join('/etc/portage/package.mask', 'cross-' + target)
Brian Harringaf019fb2012-05-10 15:06:13 -0700452 osutils.SafeUnlink(maskfile)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100453
454
Zdenek Behan508dcce2011-12-05 15:39:32 +0100455# Main functions performing the actual update steps.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700456def RebuildLibtool(root='/'):
Mike Frysingerc880a962013-11-08 13:59:06 -0500457 """Rebuild libtool as needed
458
459 Libtool hardcodes full paths to internal gcc files, so whenever we upgrade
460 gcc, libtool will break. We can't use binary packages either as those will
461 most likely be compiled against the previous version of gcc.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700462
463 Args:
464 root: The install root where we want libtool rebuilt.
Mike Frysingerc880a962013-11-08 13:59:06 -0500465 """
466 needs_update = False
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700467 with open(os.path.join(root, 'usr/bin/libtool')) as f:
Mike Frysingerc880a962013-11-08 13:59:06 -0500468 for line in f:
469 # Look for a line like:
470 # sys_lib_search_path_spec="..."
471 # It'll be a list of paths and gcc will be one of them.
472 if line.startswith('sys_lib_search_path_spec='):
473 line = line.rstrip()
474 for path in line.split('=', 1)[1].strip('"').split():
Mike Frysinger3bba5032016-09-20 14:15:04 -0400475 root_path = os.path.join(root, path.lstrip(os.path.sep))
476 logging.debug('Libtool: checking %s', root_path)
477 if not os.path.exists(root_path):
478 logging.info('Rebuilding libtool after gcc upgrade')
479 logging.info(' %s', line)
480 logging.info(' missing path: %s', path)
Mike Frysingerc880a962013-11-08 13:59:06 -0500481 needs_update = True
482 break
483
484 if needs_update:
485 break
486
487 if needs_update:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700488 cmd = [EMERGE_CMD, '--oneshot']
489 if root != '/':
490 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
491 cmd.append('sys-devel/libtool')
Mike Frysingerc880a962013-11-08 13:59:06 -0500492 cros_build_lib.RunCommand(cmd)
Mike Frysinger3bba5032016-09-20 14:15:04 -0400493 else:
494 logging.debug('Libtool is up-to-date; no need to rebuild')
Mike Frysingerc880a962013-11-08 13:59:06 -0500495
496
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700497def UpdateTargets(targets, usepkg, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100498 """Determines which packages need update/unmerge and defers to portage.
499
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500500 Args:
501 targets: The list of targets to update
502 usepkg: Copies the commandline option
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700503 root: The install root in which we want packages updated.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100504 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100505 # For each target, we do two things. Figure out the list of updates,
506 # and figure out the appropriate keywords/masks. Crossdev will initialize
507 # these, but they need to be regenerated on every update.
Mike Frysinger3bba5032016-09-20 14:15:04 -0400508 logging.info('Determining required toolchain updates...')
David James90239b92012-11-05 15:31:34 -0800509 mergemap = {}
Zdenek Behan508dcce2011-12-05 15:39:32 +0100510 for target in targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400511 logging.debug('Updating target %s', target)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100512 # Record the highest needed version for each target, for masking purposes.
513 RemovePackageMask(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100514 for package in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100515 # Portage name for the package
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400516 logging.debug(' Checking package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100517 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700518 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100519 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200520 desired_num = VersionListToNumeric(target, package, desired, False)
Mike Frysinger785b0c32017-09-13 01:35:59 -0400521 if pkg in NEW_PACKAGES and usepkg:
522 # Skip this binary package (for now).
523 continue
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100524 mergemap[pkg] = set(desired_num).difference(current)
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400525 logging.debug(' %s -> %s', current, desired_num)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100526
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400527 packages = [pkg for pkg, vers in mergemap.items() if vers]
Zdenek Behan508dcce2011-12-05 15:39:32 +0100528 if not packages:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400529 logging.info('Nothing to update!')
David Jamesf8c672f2012-11-06 13:38:11 -0800530 return False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100531
Mike Frysinger3bba5032016-09-20 14:15:04 -0400532 logging.info('Updating packages:')
533 logging.info('%s', packages)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100534
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100535 cmd = [EMERGE_CMD, '--oneshot', '--update']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100536 if usepkg:
537 cmd.extend(['--getbinpkg', '--usepkgonly'])
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700538 if root != '/':
539 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100540
541 cmd.extend(packages)
542 cros_build_lib.RunCommand(cmd)
David Jamesf8c672f2012-11-06 13:38:11 -0800543 return True
Zdenek Behan508dcce2011-12-05 15:39:32 +0100544
545
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700546def CleanTargets(targets, root='/'):
547 """Unmerges old packages that are assumed unnecessary.
548
549 Args:
550 targets: The list of targets to clean up.
551 root: The install root in which we want packages cleaned up.
552 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100553 unmergemap = {}
554 for target in targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400555 logging.debug('Cleaning target %s', target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100556 for package in GetTargetPackages(target):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400557 logging.debug(' Cleaning package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100558 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700559 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100560 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2fcb0aa2015-05-21 14:51:41 -0700561 # NOTE: This refers to installed packages (vartree) rather than the
562 # Portage version (porttree and/or bintree) when determining the current
563 # version. While this isn't the most accurate thing to do, it is probably
564 # a good simple compromise, which should have the desired result of
565 # uninstalling everything but the latest installed version. In
566 # particular, using the bintree (--usebinpkg) requires a non-trivial
567 # binhost sync and is probably more complex than useful.
Zdenek Behan699ddd32012-04-13 07:14:08 +0200568 desired_num = VersionListToNumeric(target, package, desired, True)
569 if not set(desired_num).issubset(current):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400570 logging.warning('Error detecting stable version for %s, '
571 'skipping clean!', pkg)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200572 return
Zdenek Behan508dcce2011-12-05 15:39:32 +0100573 unmergemap[pkg] = set(current).difference(desired_num)
574
575 # Cleaning doesn't care about consistency and rebuilding package.* files.
576 packages = []
577 for pkg, vers in unmergemap.iteritems():
578 packages.extend('=%s-%s' % (pkg, ver) for ver in vers if ver != '9999')
579
580 if packages:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400581 logging.info('Cleaning packages:')
582 logging.info('%s', packages)
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100583 cmd = [EMERGE_CMD, '--unmerge']
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700584 if root != '/':
585 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100586 cmd.extend(packages)
587 cros_build_lib.RunCommand(cmd)
588 else:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400589 logging.info('Nothing to clean!')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100590
591
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700592def SelectActiveToolchains(targets, suffixes, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100593 """Runs gcc-config and binutils-config to select the desired.
594
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500595 Args:
596 targets: The targets to select
597 suffixes: Optional target-specific hacks
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700598 root: The root where we want to select toolchain versions.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100599 """
600 for package in ['gcc', 'binutils']:
601 for target in targets:
Mike Frysinger785b0c32017-09-13 01:35:59 -0400602 # See if this package is part of this target.
603 if package not in GetTargetPackages(target):
604 logging.debug('%s: %s is not used', target, package)
605 continue
606
Zdenek Behan508dcce2011-12-05 15:39:32 +0100607 # Pick the first version in the numbered list as the selected one.
608 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700609 desired_num = VersionListToNumeric(target, package, desired, True,
610 root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100611 desired = desired_num[0]
612 # *-config does not play revisions, strip them, keep just PV.
613 desired = portage.versions.pkgsplit('%s-%s' % (package, desired))[1]
614
Mike Frysinger785b0c32017-09-13 01:35:59 -0400615 if target.startswith('host'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100616 # *-config is the only tool treating host identically (by tuple).
David James27ac4ae2012-12-03 23:16:15 -0800617 target = toolchain.GetHostTuple()
Zdenek Behan508dcce2011-12-05 15:39:32 +0100618
619 # And finally, attach target to it.
620 desired = '%s-%s' % (target, desired)
621
622 # Target specific hacks
623 if package in suffixes:
624 if target in suffixes[package]:
625 desired += suffixes[package][target]
626
David James7ec5efc2012-11-06 09:39:49 -0800627 extra_env = {'CHOST': target}
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700628 if root != '/':
629 extra_env['ROOT'] = root
David James7ec5efc2012-11-06 09:39:49 -0800630 cmd = ['%s-config' % package, '-c', target]
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500631 result = cros_build_lib.RunCommand(
632 cmd, print_cmd=False, redirect_stdout=True, extra_env=extra_env)
633 current = result.output.splitlines()[0]
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700634
635 # Do not reconfig when the current is live or nothing needs to be done.
636 extra_env = {'ROOT': root} if root != '/' else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100637 if current != desired and current != '9999':
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500638 cmd = [package + '-config', desired]
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700639 cros_build_lib.RunCommand(cmd, print_cmd=False, extra_env=extra_env)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100640
641
Mike Frysinger35247af2012-11-16 18:58:06 -0500642def ExpandTargets(targets_wanted):
643 """Expand any possible toolchain aliases into full targets
644
645 This will expand 'all' and 'sdk' into the respective toolchain tuples.
646
647 Args:
648 targets_wanted: The targets specified by the user.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500649
Mike Frysinger35247af2012-11-16 18:58:06 -0500650 Returns:
Gilad Arnold8195b532015-04-07 10:56:30 +0300651 Dictionary of concrete targets and their toolchain tuples.
Mike Frysinger35247af2012-11-16 18:58:06 -0500652 """
Mike Frysinger35247af2012-11-16 18:58:06 -0500653 targets_wanted = set(targets_wanted)
Don Garrettc0c74002015-10-09 12:58:19 -0700654 if targets_wanted == set(['boards']):
655 # Only pull targets from the included boards.
Gilad Arnold8195b532015-04-07 10:56:30 +0300656 return {}
657
658 all_targets = toolchain.GetAllTargets()
Mike Frysinger35247af2012-11-16 18:58:06 -0500659 if targets_wanted == set(['all']):
Gilad Arnold8195b532015-04-07 10:56:30 +0300660 return all_targets
661 if targets_wanted == set(['sdk']):
Mike Frysinger35247af2012-11-16 18:58:06 -0500662 # Filter out all the non-sdk toolchains as we don't want to mess
663 # with those in all of our builds.
Gilad Arnold8195b532015-04-07 10:56:30 +0300664 return toolchain.FilterToolchains(all_targets, 'sdk', True)
665
666 # Verify user input.
667 nonexistent = targets_wanted.difference(all_targets)
668 if nonexistent:
669 raise ValueError('Invalid targets: %s', ','.join(nonexistent))
670 return {t: all_targets[t] for t in targets_wanted}
Mike Frysinger35247af2012-11-16 18:58:06 -0500671
672
David Jamesf8c672f2012-11-06 13:38:11 -0800673def UpdateToolchains(usepkg, deleteold, hostonly, reconfig,
Don Garrettc0c74002015-10-09 12:58:19 -0700674 targets_wanted, boards_wanted, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100675 """Performs all steps to create a synchronized toolchain enviroment.
676
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500677 Args:
678 usepkg: Use prebuilt packages
679 deleteold: Unmerge deprecated packages
680 hostonly: Only setup the host toolchain
681 reconfig: Reload crossdev config and reselect toolchains
682 targets_wanted: All the targets to update
683 boards_wanted: Load targets from these boards
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700684 root: The root in which to install the toolchains.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100685 """
David Jamesf8c672f2012-11-06 13:38:11 -0800686 targets, crossdev_targets, reconfig_targets = {}, {}, {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100687 if not hostonly:
688 # For hostonly, we can skip most of the below logic, much of which won't
689 # work on bare systems where this is useful.
Mike Frysinger35247af2012-11-16 18:58:06 -0500690 targets = ExpandTargets(targets_wanted)
Mike Frysinger7ccee992012-06-01 21:27:59 -0400691
Don Garrettc0c74002015-10-09 12:58:19 -0700692 # Now re-add any targets that might be from this board. This is to
Gilad Arnold8195b532015-04-07 10:56:30 +0300693 # allow unofficial boards to declare their own toolchains.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400694 for board in boards_wanted:
David James27ac4ae2012-12-03 23:16:15 -0800695 targets.update(toolchain.GetToolchainsForBoard(board))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100696
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100697 # First check and initialize all cross targets that need to be.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400698 for target in targets:
699 if TargetIsInitialized(target):
700 reconfig_targets[target] = targets[target]
701 else:
702 crossdev_targets[target] = targets[target]
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100703 if crossdev_targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400704 logging.info('The following targets need to be re-initialized:')
705 logging.info('%s', crossdev_targets)
David James66a09c42012-11-05 13:31:38 -0800706 Crossdev.UpdateTargets(crossdev_targets, usepkg)
Zdenek Behan8be29ba2012-05-29 23:10:34 +0200707 # Those that were not initialized may need a config update.
David James66a09c42012-11-05 13:31:38 -0800708 Crossdev.UpdateTargets(reconfig_targets, usepkg, config_only=True)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100709
Mike Frysinger66814c32017-10-09 18:11:46 -0400710 # If we're building a subset of toolchains for a board, we might not have
711 # all the tuples that the packages expect. We don't define the "full" set
712 # of tuples currently other than "whatever the full sdk has normally".
713 if usepkg or set(('all', 'sdk')) & targets_wanted:
714 # Since we have cross-compilers now, we can update these packages.
715 targets['host-post-cross'] = {}
Mike Frysinger785b0c32017-09-13 01:35:59 -0400716
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100717 # We want host updated.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400718 targets['host'] = {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100719
720 # Now update all packages.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700721 if UpdateTargets(targets, usepkg, root=root) or crossdev_targets or reconfig:
722 SelectActiveToolchains(targets, CONFIG_TARGET_SUFFIXES, root=root)
David James7ec5efc2012-11-06 09:39:49 -0800723
724 if deleteold:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700725 CleanTargets(targets, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100726
Mike Frysingerc880a962013-11-08 13:59:06 -0500727 # Now that we've cleared out old versions, see if we need to rebuild
728 # anything. Can't do this earlier as it might not be broken.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700729 RebuildLibtool(root=root)
Mike Frysingerc880a962013-11-08 13:59:06 -0500730
Zdenek Behan508dcce2011-12-05 15:39:32 +0100731
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -0700732def ShowConfig(name):
733 """Show the toolchain tuples used by |name|
Mike Frysinger35247af2012-11-16 18:58:06 -0500734
735 Args:
Don Garrettc0c74002015-10-09 12:58:19 -0700736 name: The board name to query.
Mike Frysinger35247af2012-11-16 18:58:06 -0500737 """
Don Garrettc0c74002015-10-09 12:58:19 -0700738 toolchains = toolchain.GetToolchainsForBoard(name)
Mike Frysinger35247af2012-11-16 18:58:06 -0500739 # Make sure we display the default toolchain first.
Mike Frysinger3bba5032016-09-20 14:15:04 -0400740 # Note: Do not use logging here as this is meant to be used by other tools.
Mike Frysinger383367e2014-09-16 15:06:17 -0400741 print(','.join(
David James27ac4ae2012-12-03 23:16:15 -0800742 toolchain.FilterToolchains(toolchains, 'default', True).keys() +
Mike Frysinger383367e2014-09-16 15:06:17 -0400743 toolchain.FilterToolchains(toolchains, 'default', False).keys()))
Mike Frysinger35247af2012-11-16 18:58:06 -0500744
745
Mike Frysinger35247af2012-11-16 18:58:06 -0500746def GeneratePathWrapper(root, wrappath, path):
747 """Generate a shell script to execute another shell script
748
749 Since we can't symlink a wrapped ELF (see GenerateLdsoWrapper) because the
750 argv[0] won't be pointing to the correct path, generate a shell script that
751 just executes another program with its full path.
752
753 Args:
754 root: The root tree to generate scripts inside of
755 wrappath: The full path (inside |root|) to create the wrapper
756 path: The target program which this wrapper will execute
757 """
758 replacements = {
759 'path': path,
760 'relroot': os.path.relpath('/', os.path.dirname(wrappath)),
761 }
762 wrapper = """#!/bin/sh
763base=$(realpath "$0")
764basedir=${base%%/*}
765exec "${basedir}/%(relroot)s%(path)s" "$@"
766""" % replacements
767 root_wrapper = root + wrappath
768 if os.path.islink(root_wrapper):
769 os.unlink(root_wrapper)
770 else:
771 osutils.SafeMakedirs(os.path.dirname(root_wrapper))
772 osutils.WriteFile(root_wrapper, wrapper)
Mike Frysinger60ec1012013-10-21 00:11:10 -0400773 os.chmod(root_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -0500774
775
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -0700776def FixClangXXWrapper(root, path):
777 """Fix wrapper shell scripts and symlinks for invoking clang++
778
779 In a typical installation, clang++ symlinks to clang, which symlinks to the
780 elf executable. The executable distinguishes between clang and clang++ based
781 on argv[0].
782
783 When invoked through the LdsoWrapper, argv[0] always contains the path to the
784 executable elf file, making clang/clang++ invocations indistinguishable.
785
786 This function detects if the elf executable being wrapped is clang-X.Y, and
787 fixes wrappers/symlinks as necessary so that clang++ will work correctly.
788
789 The calling sequence now becomes:
790 -) clang++ invocation turns into clang++-3.9 (which is a copy of clang-3.9,
791 the Ldsowrapper).
792 -) clang++-3.9 uses the Ldso to invoke clang++-3.9.elf, which is a symlink
793 to the original clang-3.9 elf.
794 -) The difference this time is that inside the elf file execution, $0 is
795 set as .../usr/bin/clang++-3.9.elf, which contains 'clang++' in the name.
796
797 Args:
798 root: The root tree to generate scripts / symlinks inside of
799 path: The target elf for which LdsoWrapper was created
800 """
801 if re.match(r'/usr/bin/clang-\d+\.\d+$', path):
802 logging.info('fixing clang++ invocation for %s', path)
803 clangdir = os.path.dirname(root + path)
804 clang = os.path.basename(path)
805 clangxx = clang.replace('clang', 'clang++')
806
807 # Create a symlink clang++-X.Y.elf to point to clang-X.Y.elf
808 os.symlink(clang + '.elf', os.path.join(clangdir, clangxx + '.elf'))
809
810 # Create a hardlink clang++-X.Y pointing to clang-X.Y
811 os.link(os.path.join(clangdir, clang), os.path.join(clangdir, clangxx))
812
813 # Adjust the clang++ symlink to point to clang++-X.Y
814 os.unlink(os.path.join(clangdir, 'clang++'))
815 os.symlink(clangxx, os.path.join(clangdir, 'clang++'))
816
817
Mike Frysinger35247af2012-11-16 18:58:06 -0500818def FileIsCrosSdkElf(elf):
819 """Determine if |elf| is an ELF that we execute in the cros_sdk
820
821 We don't need this to be perfect, just quick. It makes sure the ELF
822 is a 64bit LSB x86_64 ELF. That is the native type of cros_sdk.
823
824 Args:
825 elf: The file to check
Mike Frysinger1a736a82013-12-12 01:50:59 -0500826
Mike Frysinger35247af2012-11-16 18:58:06 -0500827 Returns:
828 True if we think |elf| is a native ELF
829 """
830 with open(elf) as f:
831 data = f.read(20)
832 # Check the magic number, EI_CLASS, EI_DATA, and e_machine.
833 return (data[0:4] == '\x7fELF' and
834 data[4] == '\x02' and
835 data[5] == '\x01' and
836 data[18] == '\x3e')
837
838
839def IsPathPackagable(ptype, path):
840 """Should the specified file be included in a toolchain package?
841
842 We only need to handle files as we'll create dirs as we need them.
843
844 Further, trim files that won't be useful:
845 - non-english translations (.mo) since it'd require env vars
846 - debug files since these are for the host compiler itself
847 - info/man pages as they're big, and docs are online, and the
848 native docs should work fine for the most part (`man gcc`)
849
850 Args:
851 ptype: A string describing the path type (i.e. 'file' or 'dir' or 'sym')
852 path: The full path to inspect
Mike Frysinger1a736a82013-12-12 01:50:59 -0500853
Mike Frysinger35247af2012-11-16 18:58:06 -0500854 Returns:
855 True if we want to include this path in the package
856 """
857 return not (ptype in ('dir',) or
858 path.startswith('/usr/lib/debug/') or
859 os.path.splitext(path)[1] == '.mo' or
860 ('/man/' in path or '/info/' in path))
861
862
863def ReadlinkRoot(path, root):
864 """Like os.readlink(), but relative to a |root|
865
866 Args:
867 path: The symlink to read
868 root: The path to use for resolving absolute symlinks
Mike Frysinger1a736a82013-12-12 01:50:59 -0500869
Mike Frysinger35247af2012-11-16 18:58:06 -0500870 Returns:
871 A fully resolved symlink path
872 """
873 while os.path.islink(root + path):
874 path = os.path.join(os.path.dirname(path), os.readlink(root + path))
875 return path
876
877
878def _GetFilesForTarget(target, root='/'):
879 """Locate all the files to package for |target|
880
881 This does not cover ELF dependencies.
882
883 Args:
884 target: The toolchain target name
885 root: The root path to pull all packages from
Mike Frysinger1a736a82013-12-12 01:50:59 -0500886
Mike Frysinger35247af2012-11-16 18:58:06 -0500887 Returns:
888 A tuple of a set of all packable paths, and a set of all paths which
889 are also native ELFs
890 """
891 paths = set()
892 elfs = set()
893
894 # Find all the files owned by the packages for this target.
895 for pkg in GetTargetPackages(target):
Mike Frysinger35247af2012-11-16 18:58:06 -0500896
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700897 # Skip Go compiler from redistributable packages.
898 # The "go" executable has GOROOT=/usr/lib/go/${CTARGET} hardcoded
899 # into it. Due to this, the toolchain cannot be unpacked anywhere
900 # else and be readily useful. To enable packaging Go, we need to:
901 # -) Tweak the wrappers/environment to override GOROOT
902 # automatically based on the unpack location.
903 # -) Make sure the ELF dependency checking and wrapping logic
904 # below skips the Go toolchain executables and libraries.
905 # -) Make sure the packaging process maintains the relative
906 # timestamps of precompiled standard library packages.
907 # (see dev-lang/go ebuild for details).
908 if pkg == 'ex_go':
909 continue
910
Mike Frysinger35247af2012-11-16 18:58:06 -0500911 atom = GetPortagePackage(target, pkg)
912 cat, pn = atom.split('/')
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700913 ver = GetInstalledPackageVersions(atom, root=root)[0]
Ralph Nathan03047282015-03-23 11:09:32 -0700914 logging.info('packaging %s-%s', atom, ver)
Mike Frysinger35247af2012-11-16 18:58:06 -0500915
916 # pylint: disable=E1101
917 dblink = portage.dblink(cat, pn + '-' + ver, myroot=root,
918 settings=portage.settings)
919 contents = dblink.getcontents()
920 for obj in contents:
921 ptype = contents[obj][0]
922 if not IsPathPackagable(ptype, obj):
923 continue
924
925 if ptype == 'obj':
926 # For native ELFs, we need to pull in their dependencies too.
927 if FileIsCrosSdkElf(obj):
928 elfs.add(obj)
929 paths.add(obj)
930
931 return paths, elfs
932
933
934def _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500935 path_rewrite_func=lambda x: x, root='/'):
Mike Frysinger35247af2012-11-16 18:58:06 -0500936 """Link in all packable files and their runtime dependencies
937
938 This also wraps up executable ELFs with helper scripts.
939
940 Args:
941 output_dir: The output directory to store files
942 paths: All the files to include
943 elfs: All the files which are ELFs (a subset of |paths|)
944 ldpaths: A dict of static ldpath information
945 path_rewrite_func: User callback to rewrite paths in output_dir
946 root: The root path to pull all packages/files from
947 """
948 # Link in all the files.
Mike Frysinger221bd822017-09-29 02:51:47 -0400949 sym_paths = {}
Mike Frysinger35247af2012-11-16 18:58:06 -0500950 for path in paths:
951 new_path = path_rewrite_func(path)
952 dst = output_dir + new_path
953 osutils.SafeMakedirs(os.path.dirname(dst))
954
955 # Is this a symlink which we have to rewrite or wrap?
956 # Delay wrap check until after we have created all paths.
957 src = root + path
958 if os.path.islink(src):
959 tgt = os.readlink(src)
960 if os.path.sep in tgt:
Mike Frysinger221bd822017-09-29 02:51:47 -0400961 sym_paths[lddtree.normpath(ReadlinkRoot(src, root))] = new_path
Mike Frysinger35247af2012-11-16 18:58:06 -0500962
963 # Rewrite absolute links to relative and then generate the symlink
964 # ourselves. All other symlinks can be hardlinked below.
965 if tgt[0] == '/':
966 tgt = os.path.relpath(tgt, os.path.dirname(new_path))
967 os.symlink(tgt, dst)
968 continue
969
970 os.link(src, dst)
971
Mike Frysinger35247af2012-11-16 18:58:06 -0500972 # Locate all the dependencies for all the ELFs. Stick them all in the
973 # top level "lib" dir to make the wrapper simpler. This exact path does
974 # not matter since we execute ldso directly, and we tell the ldso the
975 # exact path to search for its libraries.
976 libdir = os.path.join(output_dir, 'lib')
977 osutils.SafeMakedirs(libdir)
978 donelibs = set()
Mike Frysinger4331fc62017-09-28 14:03:25 -0400979 glibc_re = re.compile(r'/lib(c|pthread)-[0-9.]+\.so$')
Mike Frysinger35247af2012-11-16 18:58:06 -0500980 for elf in elfs:
Mike Frysingerea7688e2014-07-31 22:40:33 -0400981 e = lddtree.ParseELF(elf, root=root, ldpaths=ldpaths)
Mike Frysinger35247af2012-11-16 18:58:06 -0500982 interp = e['interp']
Yunlian Jiang196e8f42017-09-20 12:29:47 -0700983 # Do not create wrapper for libc. crbug.com/766827
984 if interp and not glibc_re.search(elf):
Mike Frysinger35247af2012-11-16 18:58:06 -0500985 # Generate a wrapper if it is executable.
Mike Frysingerc2ec0902013-03-26 01:28:45 -0400986 interp = os.path.join('/lib', os.path.basename(interp))
987 lddtree.GenerateLdsoWrapper(output_dir, path_rewrite_func(elf), interp,
988 libpaths=e['rpath'] + e['runpath'])
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -0700989 FixClangXXWrapper(output_dir, path_rewrite_func(elf))
Mike Frysinger35247af2012-11-16 18:58:06 -0500990
Mike Frysinger221bd822017-09-29 02:51:47 -0400991 # Wrap any symlinks to the wrapper.
992 if elf in sym_paths:
993 link = sym_paths[elf]
994 GeneratePathWrapper(output_dir, link, elf)
995
Mike Frysinger35247af2012-11-16 18:58:06 -0500996 for lib, lib_data in e['libs'].iteritems():
997 if lib in donelibs:
998 continue
999
1000 src = path = lib_data['path']
1001 if path is None:
Ralph Nathan446aee92015-03-23 14:44:56 -07001002 logging.warning('%s: could not locate %s', elf, lib)
Mike Frysinger35247af2012-11-16 18:58:06 -05001003 continue
1004 donelibs.add(lib)
1005
1006 # Needed libs are the SONAME, but that is usually a symlink, not a
1007 # real file. So link in the target rather than the symlink itself.
1008 # We have to walk all the possible symlinks (SONAME could point to a
1009 # symlink which points to a symlink), and we have to handle absolute
1010 # ourselves (since we have a "root" argument).
1011 dst = os.path.join(libdir, os.path.basename(path))
1012 src = ReadlinkRoot(src, root)
1013
1014 os.link(root + src, dst)
1015
1016
1017def _EnvdGetVar(envd, var):
1018 """Given a Gentoo env.d file, extract a var from it
1019
1020 Args:
1021 envd: The env.d file to load (may be a glob path)
1022 var: The var to extract
Mike Frysinger1a736a82013-12-12 01:50:59 -05001023
Mike Frysinger35247af2012-11-16 18:58:06 -05001024 Returns:
1025 The value of |var|
1026 """
1027 envds = glob.glob(envd)
1028 assert len(envds) == 1, '%s: should have exactly 1 env.d file' % envd
1029 envd = envds[0]
1030 return cros_build_lib.LoadKeyValueFile(envd)[var]
1031
1032
1033def _ProcessBinutilsConfig(target, output_dir):
1034 """Do what binutils-config would have done"""
1035 binpath = os.path.join('/bin', target + '-')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001036
1037 # Locate the bin dir holding the gold linker.
1038 binutils_bin_path = os.path.join(output_dir, 'usr', toolchain.GetHostTuple(),
1039 target, 'binutils-bin')
1040 globpath = os.path.join(binutils_bin_path, '*-gold')
Mike Frysinger35247af2012-11-16 18:58:06 -05001041 srcpath = glob.glob(globpath)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001042 if not srcpath:
1043 # Maybe this target doesn't support gold.
1044 globpath = os.path.join(binutils_bin_path, '*')
1045 srcpath = glob.glob(globpath)
1046 assert len(srcpath) == 1, ('%s: matched more than one path (but not *-gold)'
1047 % globpath)
1048 srcpath = srcpath[0]
1049 ld_path = os.path.join(srcpath, 'ld')
1050 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1051 ld_path = os.path.join(srcpath, 'ld.bfd')
1052 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1053 ld_path = os.path.join(srcpath, 'ld.gold')
1054 assert not os.path.exists(ld_path), ('%s: exists, but gold dir does not!'
1055 % ld_path)
1056
1057 # Nope, no gold support to be found.
1058 gold_supported = False
Ralph Nathan446aee92015-03-23 14:44:56 -07001059 logging.warning('%s: binutils lacks support for the gold linker', target)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001060 else:
1061 assert len(srcpath) == 1, '%s: did not match exactly 1 path' % globpath
Mike Frysinger78b7a812014-11-26 19:45:23 -05001062 srcpath = srcpath[0]
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001063
Rahul Chaudhry4891b4d2017-03-08 10:31:27 -08001064 # Package the binutils-bin directory without the '-gold' suffix
1065 # if gold is not enabled as the default linker for this target.
1066 gold_supported = CONFIG_TARGET_SUFFIXES['binutils'].get(target) == '-gold'
1067 if not gold_supported:
1068 srcpath = srcpath[:-len('-gold')]
1069 ld_path = os.path.join(srcpath, 'ld')
1070 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1071
Mike Frysinger78b7a812014-11-26 19:45:23 -05001072 srcpath = srcpath[len(output_dir):]
Mike Frysinger35247af2012-11-16 18:58:06 -05001073 gccpath = os.path.join('/usr', 'libexec', 'gcc')
1074 for prog in os.listdir(output_dir + srcpath):
1075 # Skip binaries already wrapped.
1076 if not prog.endswith('.real'):
1077 GeneratePathWrapper(output_dir, binpath + prog,
1078 os.path.join(srcpath, prog))
1079 GeneratePathWrapper(output_dir, os.path.join(gccpath, prog),
1080 os.path.join(srcpath, prog))
1081
David James27ac4ae2012-12-03 23:16:15 -08001082 libpath = os.path.join('/usr', toolchain.GetHostTuple(), target, 'lib')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001083 envd = os.path.join(output_dir, 'etc', 'env.d', 'binutils', '*')
1084 if gold_supported:
1085 envd += '-gold'
Rahul Chaudhry4891b4d2017-03-08 10:31:27 -08001086 else:
1087 # If gold is not enabled as the default linker and 2 env.d
1088 # files exist, pick the one without the '-gold' suffix.
1089 envds = sorted(glob.glob(envd))
1090 if len(envds) == 2 and envds[1] == envds[0] + '-gold':
1091 envd = envds[0]
Mike Frysinger35247af2012-11-16 18:58:06 -05001092 srcpath = _EnvdGetVar(envd, 'LIBPATH')
1093 os.symlink(os.path.relpath(srcpath, os.path.dirname(libpath)),
1094 output_dir + libpath)
1095
1096
1097def _ProcessGccConfig(target, output_dir):
1098 """Do what gcc-config would have done"""
1099 binpath = '/bin'
1100 envd = os.path.join(output_dir, 'etc', 'env.d', 'gcc', '*')
1101 srcpath = _EnvdGetVar(envd, 'GCC_PATH')
1102 for prog in os.listdir(output_dir + srcpath):
1103 # Skip binaries already wrapped.
1104 if (not prog.endswith('.real') and
1105 not prog.endswith('.elf') and
1106 prog.startswith(target)):
1107 GeneratePathWrapper(output_dir, os.path.join(binpath, prog),
1108 os.path.join(srcpath, prog))
1109 return srcpath
1110
1111
Frank Henigman179ec7c2015-02-06 03:01:09 -05001112def _ProcessSysrootWrappers(_target, output_dir, srcpath):
1113 """Remove chroot-specific things from our sysroot wrappers"""
Mike Frysinger35247af2012-11-16 18:58:06 -05001114 # Disable ccache since we know it won't work outside of chroot.
Frank Henigman179ec7c2015-02-06 03:01:09 -05001115 for sysroot_wrapper in glob.glob(os.path.join(
1116 output_dir + srcpath, 'sysroot_wrapper*')):
1117 contents = osutils.ReadFile(sysroot_wrapper).splitlines()
Douglas Andersoncc828a52017-10-13 13:07:25 -07001118
1119 # In order to optimize startup time in the chroot we run python a little
1120 # differently there. Put it back to the more portable way here.
1121 # See http://crbug.com/773138 for some details.
1122 if contents[0] == '#!/usr/bin/python2 -S':
1123 contents[0] = '#!/usr/bin/env python2'
1124
Frank Henigman179ec7c2015-02-06 03:01:09 -05001125 for num in xrange(len(contents)):
1126 if '@CCACHE_DEFAULT@' in contents[num]:
Caroline Ticece9e9232017-06-02 09:38:42 -07001127 assert 'True' in contents[num]
1128 contents[num] = contents[num].replace('True', 'False')
Frank Henigman179ec7c2015-02-06 03:01:09 -05001129 break
1130 # Can't update the wrapper in place since it's a hardlink to a file in /.
1131 os.unlink(sysroot_wrapper)
1132 osutils.WriteFile(sysroot_wrapper, '\n'.join(contents))
1133 os.chmod(sysroot_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -05001134
1135
Yunlian Jiang5ad6b512017-09-20 09:27:45 -07001136def _CreateMainLibDir(target, output_dir):
1137 """Create some lib dirs so that compiler can get the right Gcc paths"""
1138 osutils.SafeMakedirs(os.path.join(output_dir, 'usr', target, 'lib'))
1139 osutils.SafeMakedirs(os.path.join(output_dir, 'usr', target, 'usr/lib'))
1140
1141
Mike Frysinger35247af2012-11-16 18:58:06 -05001142def _ProcessDistroCleanups(target, output_dir):
1143 """Clean up the tree and remove all distro-specific requirements
1144
1145 Args:
1146 target: The toolchain target name
1147 output_dir: The output directory to clean up
1148 """
1149 _ProcessBinutilsConfig(target, output_dir)
1150 gcc_path = _ProcessGccConfig(target, output_dir)
Frank Henigman179ec7c2015-02-06 03:01:09 -05001151 _ProcessSysrootWrappers(target, output_dir, gcc_path)
Yunlian Jiang5ad6b512017-09-20 09:27:45 -07001152 _CreateMainLibDir(target, output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001153
1154 osutils.RmDir(os.path.join(output_dir, 'etc'))
1155
1156
1157def CreatePackagableRoot(target, output_dir, ldpaths, root='/'):
1158 """Setup a tree from the packages for the specified target
1159
1160 This populates a path with all the files from toolchain packages so that
1161 a tarball can easily be generated from the result.
1162
1163 Args:
1164 target: The target to create a packagable root from
1165 output_dir: The output directory to place all the files
1166 ldpaths: A dict of static ldpath information
1167 root: The root path to pull all packages/files from
1168 """
1169 # Find all the files owned by the packages for this target.
1170 paths, elfs = _GetFilesForTarget(target, root=root)
1171
1172 # Link in all the package's files, any ELF dependencies, and wrap any
1173 # executable ELFs with helper scripts.
1174 def MoveUsrBinToBin(path):
Han Shen699ea192016-03-02 10:42:47 -08001175 """Move /usr/bin to /bin so people can just use that toplevel dir
1176
1177 Note we do not apply this to clang - there is correlation between clang's
1178 search path for libraries / inclusion and its installation path.
1179 """
1180 if path.startswith('/usr/bin/') and path.find('clang') == -1:
1181 return path[4:]
1182 return path
Mike Frysinger35247af2012-11-16 18:58:06 -05001183 _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
1184 path_rewrite_func=MoveUsrBinToBin, root=root)
1185
1186 # The packages, when part of the normal distro, have helper scripts
1187 # that setup paths and such. Since we are making this standalone, we
1188 # need to preprocess all that ourselves.
1189 _ProcessDistroCleanups(target, output_dir)
1190
1191
1192def CreatePackages(targets_wanted, output_dir, root='/'):
1193 """Create redistributable cross-compiler packages for the specified targets
1194
1195 This creates toolchain packages that should be usable in conjunction with
1196 a downloaded sysroot (created elsewhere).
1197
1198 Tarballs (one per target) will be created in $PWD.
1199
1200 Args:
Don Garrett25f309a2014-03-19 14:02:12 -07001201 targets_wanted: The targets to package up.
1202 output_dir: The directory to put the packages in.
1203 root: The root path to pull all packages/files from.
Mike Frysinger35247af2012-11-16 18:58:06 -05001204 """
Ralph Nathan03047282015-03-23 11:09:32 -07001205 logging.info('Writing tarballs to %s', output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001206 osutils.SafeMakedirs(output_dir)
1207 ldpaths = lddtree.LoadLdpaths(root)
1208 targets = ExpandTargets(targets_wanted)
1209
Mike Frysinger221bd822017-09-29 02:51:47 -04001210 with osutils.TempDir(prefix='create-packages') as tempdir:
1211 logging.debug('Using tempdir: %s', tempdir)
1212
Mike Frysinger35247af2012-11-16 18:58:06 -05001213 # We have to split the root generation from the compression stages. This is
1214 # because we hardlink in all the files (to avoid overhead of reading/writing
1215 # the copies multiple times). But tar gets angry if a file's hardlink count
1216 # changes from when it starts reading a file to when it finishes.
1217 with parallel.BackgroundTaskRunner(CreatePackagableRoot) as queue:
1218 for target in targets:
1219 output_target_dir = os.path.join(tempdir, target)
1220 queue.put([target, output_target_dir, ldpaths, root])
1221
1222 # Build the tarball.
1223 with parallel.BackgroundTaskRunner(cros_build_lib.CreateTarball) as queue:
1224 for target in targets:
1225 tar_file = os.path.join(output_dir, target + '.tar.xz')
1226 queue.put([tar_file, os.path.join(tempdir, target)])
1227
1228
Mike Frysinger07534cf2017-09-12 17:40:21 -04001229def GetParser():
1230 """Return a command line parser."""
Mike Frysinger0c808452014-11-06 17:30:23 -05001231 parser = commandline.ArgumentParser(description=__doc__)
1232 parser.add_argument('-u', '--nousepkg',
1233 action='store_false', dest='usepkg', default=True,
1234 help='Use prebuilt packages if possible')
1235 parser.add_argument('-d', '--deleteold',
1236 action='store_true', dest='deleteold', default=False,
1237 help='Unmerge deprecated packages')
1238 parser.add_argument('-t', '--targets',
1239 dest='targets', default='sdk',
Gilad Arnold8195b532015-04-07 10:56:30 +03001240 help="Comma separated list of tuples. Special keywords "
Don Garrettc0c74002015-10-09 12:58:19 -07001241 "'host', 'sdk', 'boards', and 'all' are "
Gilad Arnold8195b532015-04-07 10:56:30 +03001242 "allowed. Defaults to 'sdk'.")
1243 parser.add_argument('--include-boards', default='', metavar='BOARDS',
1244 help='Comma separated list of boards whose toolchains we '
1245 'will always include. Default: none')
Mike Frysinger0c808452014-11-06 17:30:23 -05001246 parser.add_argument('--hostonly',
1247 dest='hostonly', default=False, action='store_true',
1248 help='Only setup the host toolchain. '
1249 'Useful for bootstrapping chroot')
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001250 parser.add_argument('--show-board-cfg', '--show-cfg',
1251 dest='cfg_name', default=None,
Don Garrettc0c74002015-10-09 12:58:19 -07001252 help='Board to list toolchains tuples for')
Mike Frysinger91f52882017-09-13 00:16:58 -04001253 parser.add_argument('--show-packages', default=None,
1254 help='List all packages the specified target uses')
Mike Frysinger0c808452014-11-06 17:30:23 -05001255 parser.add_argument('--create-packages',
1256 action='store_true', default=False,
1257 help='Build redistributable packages')
1258 parser.add_argument('--output-dir', default=os.getcwd(), type='path',
1259 help='Output directory')
1260 parser.add_argument('--reconfig', default=False, action='store_true',
1261 help='Reload crossdev config and reselect toolchains')
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001262 parser.add_argument('--sysroot', type='path',
1263 help='The sysroot in which to install the toolchains')
Mike Frysinger07534cf2017-09-12 17:40:21 -04001264 return parser
Zdenek Behan508dcce2011-12-05 15:39:32 +01001265
Mike Frysinger07534cf2017-09-12 17:40:21 -04001266
1267def main(argv):
1268 parser = GetParser()
Mike Frysinger0c808452014-11-06 17:30:23 -05001269 options = parser.parse_args(argv)
1270 options.Freeze()
Zdenek Behan508dcce2011-12-05 15:39:32 +01001271
Mike Frysinger35247af2012-11-16 18:58:06 -05001272 # Figure out what we're supposed to do and reject conflicting options.
Mike Frysinger91f52882017-09-13 00:16:58 -04001273 conflicting_options = (
1274 options.cfg_name,
1275 options.show_packages,
1276 options.create_packages,
1277 )
1278 if sum(bool(x) for x in conflicting_options) > 1:
1279 parser.error('conflicting options: create-packages & show-packages & '
1280 'show-board-cfg')
Mike Frysinger984d0622012-06-01 16:08:44 -04001281
Gilad Arnold8195b532015-04-07 10:56:30 +03001282 targets_wanted = set(options.targets.split(','))
1283 boards_wanted = (set(options.include_boards.split(','))
1284 if options.include_boards else set())
Mike Frysinger35247af2012-11-16 18:58:06 -05001285
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001286 if options.cfg_name:
1287 ShowConfig(options.cfg_name)
Mike Frysinger91f52882017-09-13 00:16:58 -04001288 elif options.show_packages is not None:
1289 cros_build_lib.AssertInsideChroot()
1290 target = options.show_packages
1291 Crossdev.Load(False)
1292 for package in GetTargetPackages(target):
1293 print(GetPortagePackage(target, package))
Mike Frysinger35247af2012-11-16 18:58:06 -05001294 elif options.create_packages:
1295 cros_build_lib.AssertInsideChroot()
1296 Crossdev.Load(False)
Gilad Arnold8195b532015-04-07 10:56:30 +03001297 CreatePackages(targets_wanted, options.output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001298 else:
1299 cros_build_lib.AssertInsideChroot()
1300 # This has to be always run as root.
1301 if os.geteuid() != 0:
1302 cros_build_lib.Die('this script must be run as root')
1303
1304 Crossdev.Load(options.reconfig)
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001305 root = options.sysroot or '/'
Mike Frysinger35247af2012-11-16 18:58:06 -05001306 UpdateToolchains(options.usepkg, options.deleteold, options.hostonly,
Gilad Arnold8195b532015-04-07 10:56:30 +03001307 options.reconfig, targets_wanted, boards_wanted,
Don Garrettc0c74002015-10-09 12:58:19 -07001308 root=root)
Mike Frysinger35247af2012-11-16 18:58:06 -05001309 Crossdev.Save()
1310
1311 return 0