blob: fe0c280774f7e732a377129e4fd559ca12db2f4f [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
Tobias Boschddd16492019-08-14 09:29:54 -070016import shutil
Zdenek Behan508dcce2011-12-05 15:39:32 +010017
Aviv Keshetb7519e12016-10-04 00:50:00 -070018from chromite.lib import constants
Mike Frysinger506e75f2012-12-17 14:21:13 -050019from chromite.lib import commandline
Brian Harring503f3ab2012-03-09 21:39:41 -080020from chromite.lib import cros_build_lib
Ralph Nathan03047282015-03-23 11:09:32 -070021from chromite.lib import cros_logging as logging
Brian Harringaf019fb2012-05-10 15:06:13 -070022from chromite.lib import osutils
Mike Frysinger35247af2012-11-16 18:58:06 -050023from chromite.lib import parallel
David James27ac4ae2012-12-03 23:16:15 -080024from chromite.lib import toolchain
Mike Frysingere652ba12019-09-08 00:57:43 -040025from chromite.utils import key_value_store
Mike Frysinger35247af2012-11-16 18:58:06 -050026
27# Needs to be after chromite imports.
28import lddtree
Zdenek Behan508dcce2011-12-05 15:39:32 +010029
Mike Frysinger31596002012-12-03 23:54:24 -050030if cros_build_lib.IsInsideChroot():
31 # Only import portage after we've checked that we're inside the chroot.
32 # Outside may not have portage, in which case the above may not happen.
33 # We'll check in main() if the operation needs portage.
Mike Frysinger27e21b72018-07-12 14:20:21 -040034 # pylint: disable=import-error
Mike Frysinger31596002012-12-03 23:54:24 -050035 import portage
Zdenek Behan508dcce2011-12-05 15:39:32 +010036
37
Matt Tennantf1e30972012-03-02 16:30:07 -080038EMERGE_CMD = os.path.join(constants.CHROMITE_BIN_DIR, 'parallel_emerge')
Zdenek Behan508dcce2011-12-05 15:39:32 +010039PACKAGE_STABLE = '[stable]'
Zdenek Behan4eb6fd22012-03-12 17:00:56 +010040
41CHROMIUMOS_OVERLAY = '/usr/local/portage/chromiumos'
Christopher Wileyb22c0712015-06-02 10:37:03 -070042ECLASS_OVERLAY = '/usr/local/portage/eclass-overlay'
Zdenek Behan4eb6fd22012-03-12 17:00:56 +010043STABLE_OVERLAY = '/usr/local/portage/stable'
44CROSSDEV_OVERLAY = '/usr/local/portage/crossdev'
Zdenek Behan508dcce2011-12-05 15:39:32 +010045
46
Mike Frysinger66bfde52017-09-12 16:42:57 -040047# The exact list of host toolchain packages we care about. These are the
48# packages that bots/devs install only from binpkgs and rely on the SDK bot
49# (chromiumos-sdk) to validate+uprev.
50#
Mike Frysinger66bfde52017-09-12 16:42:57 -040051# We don't use crossdev to manage the host toolchain for us, especially since
52# we diverge significantly now (with llvm/clang/etc...), and we don't need or
53# want crossdev managing /etc/portage config files for the sdk
54HOST_PACKAGES = (
55 'dev-lang/go',
Yunlian Jiang2cb91dc2018-03-08 10:56:27 -080056 'dev-libs/elfutils',
Mike Frysinger66bfde52017-09-12 16:42:57 -040057 'sys-devel/binutils',
Mike Frysinger66bfde52017-09-12 16:42:57 -040058 'sys-devel/gcc',
59 'sys-devel/llvm',
60 'sys-kernel/linux-headers',
61 'sys-libs/glibc',
62 'sys-libs/libcxx',
63 'sys-libs/libcxxabi',
Manoj Guptade64cb22019-03-31 18:48:58 -070064 'sys-libs/llvm-libunwind',
Mike Frysinger66bfde52017-09-12 16:42:57 -040065)
66
Mike Frysinger785b0c32017-09-13 01:35:59 -040067# These packages are also installed into the host SDK. However, they require
68# the cross-compilers to be installed first (because they need them to actually
69# build), so we have to delay their installation.
70HOST_POST_CROSS_PACKAGES = (
Manoj Gupta65f88442018-04-12 22:42:19 -070071 'dev-lang/rust',
Mike Frysinger61a24392017-10-17 17:14:27 -040072 'virtual/target-sdk-post-cross',
Patrick Georgi043ce6e2019-02-20 22:27:09 +010073 'dev-embedded/coreboot-sdk',
Mike Frysinger785b0c32017-09-13 01:35:59 -040074)
75
76# New packages that we're in the process of adding to the SDK. Since the SDK
77# bot hasn't had a chance to run yet, there are no binary packages available,
78# so we have to list them here and wait. Once it completes, entries here can
79# be removed so they'll end up on bots & dev's systems.
80NEW_PACKAGES = (
Mike Frysinger785b0c32017-09-13 01:35:59 -040081)
82
Rahul Chaudhry4b803052015-05-13 15:25:56 -070083# Enable the Go compiler for these targets.
84TARGET_GO_ENABLED = (
85 'x86_64-cros-linux-gnu',
Rahul Chaudhry4b803052015-05-13 15:25:56 -070086 'armv7a-cros-linux-gnueabi',
Yunlian Jiang16c1a422017-10-04 10:33:22 -070087 'armv7a-cros-linux-gnueabihf',
Rahul Chaudhry4d416582017-10-25 12:31:58 -070088 'aarch64-cros-linux-gnu',
Rahul Chaudhry4b803052015-05-13 15:25:56 -070089)
90CROSSDEV_GO_ARGS = ['--ex-pkg', 'dev-lang/go']
91
Manoj Gupta1b5642e2017-03-08 16:44:12 -080092# Enable llvm's compiler-rt for these targets.
93TARGET_COMPILER_RT_ENABLED = (
94 'armv7a-cros-linux-gnueabi',
Yunlian Jiang1b77ee42017-10-06 13:44:29 -070095 'armv7a-cros-linux-gnueabihf',
Manoj Gupta946abb42017-04-12 14:27:19 -070096 'aarch64-cros-linux-gnu',
Manoj Gupta21f3a082018-03-06 21:25:39 -080097 'armv7m-cros-eabi',
Manoj Gupta1b5642e2017-03-08 16:44:12 -080098)
99CROSSDEV_COMPILER_RT_ARGS = ['--ex-pkg', 'sys-libs/compiler-rt']
100
Manoj Gupta946abb42017-04-12 14:27:19 -0700101TARGET_LLVM_PKGS_ENABLED = (
102 'armv7a-cros-linux-gnueabi',
Yunlian Jiang16c1a422017-10-04 10:33:22 -0700103 'armv7a-cros-linux-gnueabihf',
Manoj Gupta946abb42017-04-12 14:27:19 -0700104 'aarch64-cros-linux-gnu',
105 'x86_64-cros-linux-gnu',
106)
107
108LLVM_PKGS_TABLE = {
Yunlian Jiangbb2a3d32017-04-26 14:44:09 -0700109 'ex_libcxxabi' : ['--ex-pkg', 'sys-libs/libcxxabi'],
110 'ex_libcxx' : ['--ex-pkg', 'sys-libs/libcxx'],
Chirantan Ekbotee694cad2018-07-12 15:07:24 -0700111 'ex_llvm-libunwind' : ['--ex-pkg', 'sys-libs/llvm-libunwind'],
Manoj Gupta946abb42017-04-12 14:27:19 -0700112}
113
Zdenek Behan508dcce2011-12-05 15:39:32 +0100114# Overrides for {gcc,binutils}-config, pick a package with particular suffix.
115CONFIG_TARGET_SUFFIXES = {
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500116 'binutils' : {
Manoj Guptaa91e38e2018-11-15 11:07:48 -0800117 'aarch64-cros-linux-gnu' : '-gold',
Mike Frysinger8a83c622015-05-28 00:35:05 -0400118 'armv6j-cros-linux-gnueabi': '-gold',
Han Shen43b84422015-02-19 11:38:13 -0800119 'armv7a-cros-linux-gnueabi': '-gold',
Yunlian Jiang16c1a422017-10-04 10:33:22 -0700120 'armv7a-cros-linux-gnueabihf': '-gold',
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500121 'i686-pc-linux-gnu' : '-gold',
122 'x86_64-cros-linux-gnu' : '-gold',
123 },
Zdenek Behan508dcce2011-12-05 15:39:32 +0100124}
Zdenek Behan508dcce2011-12-05 15:39:32 +0100125
126
David James66a09c42012-11-05 13:31:38 -0800127class Crossdev(object):
128 """Class for interacting with crossdev and caching its output."""
129
130 _CACHE_FILE = os.path.join(CROSSDEV_OVERLAY, '.configured.json')
131 _CACHE = {}
Han Shene23782f2016-02-18 12:20:00 -0800132 # Packages that needs separate handling, in addition to what we have from
133 # crossdev.
134 MANUAL_PKGS = {
135 'llvm': 'sys-devel',
Manoj Gupta20cfc6c2017-07-19 15:49:55 -0700136 'libcxxabi': 'sys-libs',
137 'libcxx': 'sys-libs',
Yunlian Jiangda3ce5f2018-04-25 14:10:01 -0700138 'elfutils': 'dev-libs',
Chirantan Ekbotee694cad2018-07-12 15:07:24 -0700139 'llvm-libunwind': 'sys-libs',
Han Shene23782f2016-02-18 12:20:00 -0800140 }
David James66a09c42012-11-05 13:31:38 -0800141
142 @classmethod
143 def Load(cls, reconfig):
Mike Frysinger3ed47722017-08-08 14:59:08 -0400144 """Load crossdev cache from disk.
145
146 We invalidate the cache when crossdev updates or this script changes.
147 """
David James90239b92012-11-05 15:31:34 -0800148 crossdev_version = GetStablePackageVersion('sys-devel/crossdev', True)
Mike Frysinger3ed47722017-08-08 14:59:08 -0400149 # If we run the compiled/cached .pyc file, we'll read/hash that when we
150 # really always want to track the source .py file.
151 script = os.path.abspath(__file__)
152 if script.endswith('.pyc'):
153 script = script[:-1]
Mike Frysingerb3202be2019-11-15 22:25:59 -0500154 setup_toolchains_hash = hashlib.md5(
155 osutils.ReadFile(script, mode='rb')).hexdigest()
Mike Frysinger3ed47722017-08-08 14:59:08 -0400156
157 cls._CACHE = {
158 'crossdev_version': crossdev_version,
159 'setup_toolchains_hash': setup_toolchains_hash,
160 }
161
162 logging.debug('cache: checking file: %s', cls._CACHE_FILE)
163 if reconfig:
164 logging.debug('cache: forcing regen due to reconfig')
165 return
166
167 try:
168 file_data = osutils.ReadFile(cls._CACHE_FILE)
169 except IOError as e:
170 if e.errno != errno.ENOENT:
171 logging.warning('cache: reading failed: %s', e)
172 osutils.SafeUnlink(cls._CACHE_FILE)
173 return
174
175 try:
176 data = json.loads(file_data)
177 except ValueError as e:
178 logging.warning('cache: ignoring invalid content: %s', e)
179 return
180
181 if crossdev_version != data.get('crossdev_version'):
182 logging.debug('cache: rebuilding after crossdev upgrade')
183 elif setup_toolchains_hash != data.get('setup_toolchains_hash'):
184 logging.debug('cache: rebuilding after cros_setup_toolchains change')
185 else:
186 logging.debug('cache: content is up-to-date!')
187 cls._CACHE = data
David James66a09c42012-11-05 13:31:38 -0800188
189 @classmethod
190 def Save(cls):
191 """Store crossdev cache on disk."""
192 # Save the cache from the successful run.
193 with open(cls._CACHE_FILE, 'w') as f:
194 json.dump(cls._CACHE, f)
195
196 @classmethod
197 def GetConfig(cls, target):
198 """Returns a map of crossdev provided variables about a tuple."""
199 CACHE_ATTR = '_target_tuple_map'
200
201 val = cls._CACHE.setdefault(CACHE_ATTR, {})
202 if not target in val:
Mike Frysinger785b0c32017-09-13 01:35:59 -0400203 if target.startswith('host'):
Mike Frysinger66bfde52017-09-12 16:42:57 -0400204 conf = {
205 'crosspkgs': [],
206 'target': toolchain.GetHostTuple(),
207 }
Mike Frysinger785b0c32017-09-13 01:35:59 -0400208 if target == 'host':
209 packages_list = HOST_PACKAGES
210 else:
211 packages_list = HOST_POST_CROSS_PACKAGES
Mike Frysinger66bfde52017-09-12 16:42:57 -0400212 manual_pkgs = dict((pkg, cat) for cat, pkg in
Mike Frysinger785b0c32017-09-13 01:35:59 -0400213 [x.split('/') for x in packages_list])
Mike Frysinger66bfde52017-09-12 16:42:57 -0400214 else:
215 # Build the crossdev command.
216 cmd = ['crossdev', '--show-target-cfg', '--ex-gdb']
217 if target in TARGET_COMPILER_RT_ENABLED:
218 cmd.extend(CROSSDEV_COMPILER_RT_ARGS)
219 if target in TARGET_GO_ENABLED:
220 cmd.extend(CROSSDEV_GO_ARGS)
221 if target in TARGET_LLVM_PKGS_ENABLED:
222 for pkg in LLVM_PKGS_TABLE:
223 cmd.extend(LLVM_PKGS_TABLE[pkg])
224 cmd.extend(['-t', target])
225 # Catch output of crossdev.
Mike Frysinger45602c72019-09-22 02:15:11 -0400226 out = cros_build_lib.run(
Mike Frysinger0282d222019-12-17 17:15:48 -0500227 cmd, print_cmd=False, stdout=True,
Mike Frysingerb3202be2019-11-15 22:25:59 -0500228 encoding='utf-8').stdout.splitlines()
Mike Frysinger66bfde52017-09-12 16:42:57 -0400229 # List of tuples split at the first '=', converted into dict.
230 conf = dict((k, cros_build_lib.ShellUnquote(v))
231 for k, v in (x.split('=', 1) for x in out))
232 conf['crosspkgs'] = conf['crosspkgs'].split()
Han Shene23782f2016-02-18 12:20:00 -0800233
Mike Frysinger66bfde52017-09-12 16:42:57 -0400234 manual_pkgs = cls.MANUAL_PKGS
235
236 for pkg, cat in manual_pkgs.items():
Mike Frysinger3bba5032016-09-20 14:15:04 -0400237 conf[pkg + '_pn'] = pkg
238 conf[pkg + '_category'] = cat
239 if pkg not in conf['crosspkgs']:
240 conf['crosspkgs'].append(pkg)
Han Shene23782f2016-02-18 12:20:00 -0800241
242 val[target] = conf
243
David James66a09c42012-11-05 13:31:38 -0800244 return val[target]
245
246 @classmethod
247 def UpdateTargets(cls, targets, usepkg, config_only=False):
248 """Calls crossdev to initialize a cross target.
249
250 Args:
Nicolas Boichat3fecf392019-11-25 02:58:28 +0000251 targets: The list of targets to initialize using crossdev.
Don Garrett25f309a2014-03-19 14:02:12 -0700252 usepkg: Copies the commandline opts.
253 config_only: Just update.
David James66a09c42012-11-05 13:31:38 -0800254 """
255 configured_targets = cls._CACHE.setdefault('configured_targets', [])
256
257 cmdbase = ['crossdev', '--show-fail-log']
258 cmdbase.extend(['--env', 'FEATURES=splitdebug'])
259 # Pick stable by default, and override as necessary.
260 cmdbase.extend(['-P', '--oneshot'])
261 if usepkg:
262 cmdbase.extend(['-P', '--getbinpkg',
263 '-P', '--usepkgonly',
264 '--without-headers'])
265
Christopher Wileyb22c0712015-06-02 10:37:03 -0700266 overlays = ' '.join((CHROMIUMOS_OVERLAY, ECLASS_OVERLAY, STABLE_OVERLAY))
David James66a09c42012-11-05 13:31:38 -0800267 cmdbase.extend(['--overlays', overlays])
268 cmdbase.extend(['--ov-output', CROSSDEV_OVERLAY])
269
Nicolas Boichat3fecf392019-11-25 02:58:28 +0000270 # Build target by the reversed alphabetical order to make sure
271 # armv7a-cros-linux-gnueabihf builds before armv7a-cros-linux-gnueabi
272 # because some dependency issue. This can be reverted once we
273 # migrated to armv7a-cros-linux-gnueabihf. crbug.com/711369
274 for target in sorted(targets, reverse=True):
275 if config_only and target in configured_targets:
276 continue
David James66a09c42012-11-05 13:31:38 -0800277
Nicolas Boichat3fecf392019-11-25 02:58:28 +0000278 cmd = cmdbase + ['-t', target]
279
280 for pkg in GetTargetPackages(target):
281 if pkg == 'gdb':
282 # Gdb does not have selectable versions.
283 cmd.append('--ex-gdb')
284 elif pkg == 'ex_compiler-rt':
285 cmd.extend(CROSSDEV_COMPILER_RT_ARGS)
286 elif pkg == 'ex_go':
287 # Go does not have selectable versions.
288 cmd.extend(CROSSDEV_GO_ARGS)
289 elif pkg in LLVM_PKGS_TABLE:
290 cmd.extend(LLVM_PKGS_TABLE[pkg])
291 elif pkg in cls.MANUAL_PKGS:
292 pass
293 else:
294 # The first of the desired versions is the "primary" one.
295 version = GetDesiredPackageVersions(target, pkg)[0]
296 cmd.extend(['--%s' % pkg, version])
297
298 cmd.extend(targets[target]['crossdev'].split())
299 if config_only:
300 # In this case we want to just quietly reinit
301 cmd.append('--init-target')
Mike Frysinger0282d222019-12-17 17:15:48 -0500302 cros_build_lib.run(cmd, print_cmd=False, stdout=True)
David James66a09c42012-11-05 13:31:38 -0800303 else:
Nicolas Boichat3fecf392019-11-25 02:58:28 +0000304 cros_build_lib.run(cmd)
David James66a09c42012-11-05 13:31:38 -0800305
Nicolas Boichat3fecf392019-11-25 02:58:28 +0000306 configured_targets.append(target)
David James66a09c42012-11-05 13:31:38 -0800307
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100308
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100309def GetTargetPackages(target):
310 """Returns a list of packages for a given target."""
David James66a09c42012-11-05 13:31:38 -0800311 conf = Crossdev.GetConfig(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100312 # Undesired packages are denoted by empty ${pkg}_pn variable.
Han Shene23782f2016-02-18 12:20:00 -0800313 return [x for x in conf['crosspkgs'] if conf.get(x+'_pn')]
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100314
315
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100316# Portage helper functions:
317def GetPortagePackage(target, package):
318 """Returns a package name for the given target."""
David James66a09c42012-11-05 13:31:38 -0800319 conf = Crossdev.GetConfig(target)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100320 # Portage category:
Mike Frysinger785b0c32017-09-13 01:35:59 -0400321 if target.startswith('host') or package in Crossdev.MANUAL_PKGS:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100322 category = conf[package + '_category']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100323 else:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100324 category = conf['category']
325 # Portage package:
326 pn = conf[package + '_pn']
327 # Final package name:
Mike Frysinger422faf42014-11-12 23:16:48 -0500328 assert category
329 assert pn
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100330 return '%s/%s' % (category, pn)
331
332
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700333def PortageTrees(root):
334 """Return the portage trees for a given root."""
335 if root == '/':
336 return portage.db['/']
337 # The portage logic requires the path always end in a slash.
338 root = root.rstrip('/') + '/'
339 return portage.create_trees(target_root=root, config_root=root)[root]
340
341
342def GetInstalledPackageVersions(atom, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100343 """Extracts the list of current versions of a target, package pair.
344
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500345 Args:
346 atom: The atom to operate on (e.g. sys-devel/gcc)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700347 root: The root to check for installed packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100348
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500349 Returns:
350 The list of versions of the package currently installed.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100351 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100352 versions = []
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700353 for pkg in PortageTrees(root)['vartree'].dbapi.match(atom, use_cache=0):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100354 version = portage.versions.cpv_getversion(pkg)
355 versions.append(version)
356 return versions
357
358
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700359def GetStablePackageVersion(atom, installed, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100360 """Extracts the current stable version for a given package.
361
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500362 Args:
363 atom: The target/package to operate on eg. i686-pc-linux-gnu,gcc
364 installed: Whether we want installed packages or ebuilds
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700365 root: The root to use when querying packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100366
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500367 Returns:
368 A string containing the latest version.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100369 """
David James90239b92012-11-05 15:31:34 -0800370 pkgtype = 'vartree' if installed else 'porttree'
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700371 cpv = portage.best(PortageTrees(root)[pkgtype].dbapi.match(atom, use_cache=0))
David James90239b92012-11-05 15:31:34 -0800372 return portage.versions.cpv_getversion(cpv) if cpv else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100373
374
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700375def VersionListToNumeric(target, package, versions, installed, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100376 """Resolves keywords in a given version list for a particular package.
377
378 Resolving means replacing PACKAGE_STABLE with the actual number.
379
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500380 Args:
381 target: The target to operate on (e.g. i686-pc-linux-gnu)
382 package: The target/package to operate on (e.g. gcc)
383 versions: List of versions to resolve
384 installed: Query installed packages
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700385 root: The install root to use; ignored if |installed| is False.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100386
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500387 Returns:
388 List of purely numeric versions equivalent to argument
Zdenek Behan508dcce2011-12-05 15:39:32 +0100389 """
390 resolved = []
David James90239b92012-11-05 15:31:34 -0800391 atom = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700392 if not installed:
393 root = '/'
Zdenek Behan508dcce2011-12-05 15:39:32 +0100394 for version in versions:
395 if version == PACKAGE_STABLE:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700396 resolved.append(GetStablePackageVersion(atom, installed, root=root))
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400397 else:
Zdenek Behan508dcce2011-12-05 15:39:32 +0100398 resolved.append(version)
399 return resolved
400
401
402def GetDesiredPackageVersions(target, package):
403 """Produces the list of desired versions for each target, package pair.
404
405 The first version in the list is implicitly treated as primary, ie.
406 the version that will be initialized by crossdev and selected.
407
408 If the version is PACKAGE_STABLE, it really means the current version which
409 is emerged by using the package atom with no particular version key.
410 Since crossdev unmasks all packages by default, this will actually
411 mean 'unstable' in most cases.
412
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500413 Args:
414 target: The target to operate on (e.g. i686-pc-linux-gnu)
415 package: The target/package to operate on (e.g. gcc)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100416
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500417 Returns:
418 A list composed of either a version string, PACKAGE_STABLE
Zdenek Behan508dcce2011-12-05 15:39:32 +0100419 """
Mike Frysingerd23be272017-09-12 17:18:44 -0400420 if package in GetTargetPackages(target):
421 return [PACKAGE_STABLE]
422 else:
423 return []
Zdenek Behan508dcce2011-12-05 15:39:32 +0100424
425
426def TargetIsInitialized(target):
427 """Verifies if the given list of targets has been correctly initialized.
428
429 This determines whether we have to call crossdev while emerging
430 toolchain packages or can do it using emerge. Emerge is naturally
431 preferred, because all packages can be updated in a single pass.
432
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500433 Args:
434 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100435
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500436 Returns:
437 True if |target| is completely initialized, else False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100438 """
439 # Check if packages for the given target all have a proper version.
440 try:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100441 for package in GetTargetPackages(target):
David James66a09c42012-11-05 13:31:38 -0800442 atom = GetPortagePackage(target, package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100443 # Do we even want this package && is it initialized?
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400444 if not (GetStablePackageVersion(atom, True) and
445 GetStablePackageVersion(atom, False)):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100446 return False
447 return True
448 except cros_build_lib.RunCommandError:
449 # Fails - The target has likely never been initialized before.
450 return False
451
452
453def RemovePackageMask(target):
454 """Removes a package.mask file for the given platform.
455
456 The pre-existing package.mask files can mess with the keywords.
457
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500458 Args:
459 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100460 """
461 maskfile = os.path.join('/etc/portage/package.mask', 'cross-' + target)
Brian Harringaf019fb2012-05-10 15:06:13 -0700462 osutils.SafeUnlink(maskfile)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100463
464
Zdenek Behan508dcce2011-12-05 15:39:32 +0100465# Main functions performing the actual update steps.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700466def RebuildLibtool(root='/'):
Mike Frysingerc880a962013-11-08 13:59:06 -0500467 """Rebuild libtool as needed
468
469 Libtool hardcodes full paths to internal gcc files, so whenever we upgrade
470 gcc, libtool will break. We can't use binary packages either as those will
471 most likely be compiled against the previous version of gcc.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700472
473 Args:
474 root: The install root where we want libtool rebuilt.
Mike Frysingerc880a962013-11-08 13:59:06 -0500475 """
476 needs_update = False
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700477 with open(os.path.join(root, 'usr/bin/libtool')) as f:
Mike Frysingerc880a962013-11-08 13:59:06 -0500478 for line in f:
479 # Look for a line like:
480 # sys_lib_search_path_spec="..."
481 # It'll be a list of paths and gcc will be one of them.
482 if line.startswith('sys_lib_search_path_spec='):
483 line = line.rstrip()
484 for path in line.split('=', 1)[1].strip('"').split():
Mike Frysinger3bba5032016-09-20 14:15:04 -0400485 root_path = os.path.join(root, path.lstrip(os.path.sep))
486 logging.debug('Libtool: checking %s', root_path)
487 if not os.path.exists(root_path):
488 logging.info('Rebuilding libtool after gcc upgrade')
489 logging.info(' %s', line)
490 logging.info(' missing path: %s', path)
Mike Frysingerc880a962013-11-08 13:59:06 -0500491 needs_update = True
492 break
493
494 if needs_update:
495 break
496
497 if needs_update:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700498 cmd = [EMERGE_CMD, '--oneshot']
499 if root != '/':
500 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
501 cmd.append('sys-devel/libtool')
Mike Frysinger45602c72019-09-22 02:15:11 -0400502 cros_build_lib.run(cmd)
Mike Frysinger3bba5032016-09-20 14:15:04 -0400503 else:
504 logging.debug('Libtool is up-to-date; no need to rebuild')
Mike Frysingerc880a962013-11-08 13:59:06 -0500505
506
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700507def UpdateTargets(targets, usepkg, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100508 """Determines which packages need update/unmerge and defers to portage.
509
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500510 Args:
511 targets: The list of targets to update
512 usepkg: Copies the commandline option
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700513 root: The install root in which we want packages updated.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100514 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100515 # For each target, we do two things. Figure out the list of updates,
516 # and figure out the appropriate keywords/masks. Crossdev will initialize
517 # these, but they need to be regenerated on every update.
Mike Frysinger3bba5032016-09-20 14:15:04 -0400518 logging.info('Determining required toolchain updates...')
David James90239b92012-11-05 15:31:34 -0800519 mergemap = {}
Zdenek Behan508dcce2011-12-05 15:39:32 +0100520 for target in targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400521 logging.debug('Updating target %s', target)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100522 # Record the highest needed version for each target, for masking purposes.
523 RemovePackageMask(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100524 for package in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100525 # Portage name for the package
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400526 logging.debug(' Checking package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100527 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700528 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100529 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200530 desired_num = VersionListToNumeric(target, package, desired, False)
Mike Frysinger785b0c32017-09-13 01:35:59 -0400531 if pkg in NEW_PACKAGES and usepkg:
532 # Skip this binary package (for now).
533 continue
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100534 mergemap[pkg] = set(desired_num).difference(current)
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400535 logging.debug(' %s -> %s', current, desired_num)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100536
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400537 packages = [pkg for pkg, vers in mergemap.items() if vers]
Zdenek Behan508dcce2011-12-05 15:39:32 +0100538 if not packages:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400539 logging.info('Nothing to update!')
David Jamesf8c672f2012-11-06 13:38:11 -0800540 return False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100541
Mike Frysinger3bba5032016-09-20 14:15:04 -0400542 logging.info('Updating packages:')
543 logging.info('%s', packages)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100544
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100545 cmd = [EMERGE_CMD, '--oneshot', '--update']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100546 if usepkg:
547 cmd.extend(['--getbinpkg', '--usepkgonly'])
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700548 if root != '/':
549 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100550
551 cmd.extend(packages)
Mike Frysinger45602c72019-09-22 02:15:11 -0400552 cros_build_lib.run(cmd)
David Jamesf8c672f2012-11-06 13:38:11 -0800553 return True
Zdenek Behan508dcce2011-12-05 15:39:32 +0100554
555
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700556def CleanTargets(targets, root='/'):
557 """Unmerges old packages that are assumed unnecessary.
558
559 Args:
560 targets: The list of targets to clean up.
561 root: The install root in which we want packages cleaned up.
562 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100563 unmergemap = {}
564 for target in targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400565 logging.debug('Cleaning target %s', target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100566 for package in GetTargetPackages(target):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400567 logging.debug(' Cleaning package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100568 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700569 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100570 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2fcb0aa2015-05-21 14:51:41 -0700571 # NOTE: This refers to installed packages (vartree) rather than the
572 # Portage version (porttree and/or bintree) when determining the current
573 # version. While this isn't the most accurate thing to do, it is probably
574 # a good simple compromise, which should have the desired result of
575 # uninstalling everything but the latest installed version. In
576 # particular, using the bintree (--usebinpkg) requires a non-trivial
577 # binhost sync and is probably more complex than useful.
Zdenek Behan699ddd32012-04-13 07:14:08 +0200578 desired_num = VersionListToNumeric(target, package, desired, True)
579 if not set(desired_num).issubset(current):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400580 logging.warning('Error detecting stable version for %s, '
581 'skipping clean!', pkg)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200582 return
Zdenek Behan508dcce2011-12-05 15:39:32 +0100583 unmergemap[pkg] = set(current).difference(desired_num)
584
585 # Cleaning doesn't care about consistency and rebuilding package.* files.
586 packages = []
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400587 for pkg, vers in unmergemap.items():
Zdenek Behan508dcce2011-12-05 15:39:32 +0100588 packages.extend('=%s-%s' % (pkg, ver) for ver in vers if ver != '9999')
589
590 if packages:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400591 logging.info('Cleaning packages:')
592 logging.info('%s', packages)
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100593 cmd = [EMERGE_CMD, '--unmerge']
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700594 if root != '/':
595 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100596 cmd.extend(packages)
Mike Frysinger45602c72019-09-22 02:15:11 -0400597 cros_build_lib.run(cmd)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100598 else:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400599 logging.info('Nothing to clean!')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100600
601
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700602def SelectActiveToolchains(targets, suffixes, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100603 """Runs gcc-config and binutils-config to select the desired.
604
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500605 Args:
606 targets: The targets to select
607 suffixes: Optional target-specific hacks
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700608 root: The root where we want to select toolchain versions.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100609 """
610 for package in ['gcc', 'binutils']:
611 for target in targets:
Mike Frysinger785b0c32017-09-13 01:35:59 -0400612 # See if this package is part of this target.
613 if package not in GetTargetPackages(target):
614 logging.debug('%s: %s is not used', target, package)
615 continue
616
Zdenek Behan508dcce2011-12-05 15:39:32 +0100617 # Pick the first version in the numbered list as the selected one.
618 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700619 desired_num = VersionListToNumeric(target, package, desired, True,
620 root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100621 desired = desired_num[0]
622 # *-config does not play revisions, strip them, keep just PV.
623 desired = portage.versions.pkgsplit('%s-%s' % (package, desired))[1]
624
Mike Frysinger785b0c32017-09-13 01:35:59 -0400625 if target.startswith('host'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100626 # *-config is the only tool treating host identically (by tuple).
David James27ac4ae2012-12-03 23:16:15 -0800627 target = toolchain.GetHostTuple()
Zdenek Behan508dcce2011-12-05 15:39:32 +0100628
629 # And finally, attach target to it.
630 desired = '%s-%s' % (target, desired)
631
632 # Target specific hacks
633 if package in suffixes:
634 if target in suffixes[package]:
635 desired += suffixes[package][target]
636
David James7ec5efc2012-11-06 09:39:49 -0800637 extra_env = {'CHOST': target}
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700638 if root != '/':
639 extra_env['ROOT'] = root
David James7ec5efc2012-11-06 09:39:49 -0800640 cmd = ['%s-config' % package, '-c', target]
Mike Frysinger45602c72019-09-22 02:15:11 -0400641 result = cros_build_lib.run(
Mike Frysinger0282d222019-12-17 17:15:48 -0500642 cmd, print_cmd=False, stdout=True, encoding='utf-8',
Mike Frysingerb3202be2019-11-15 22:25:59 -0500643 extra_env=extra_env)
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500644 current = result.output.splitlines()[0]
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700645
646 # Do not reconfig when the current is live or nothing needs to be done.
647 extra_env = {'ROOT': root} if root != '/' else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100648 if current != desired and current != '9999':
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500649 cmd = [package + '-config', desired]
Mike Frysinger45602c72019-09-22 02:15:11 -0400650 cros_build_lib.run(cmd, print_cmd=False, extra_env=extra_env)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100651
652
Mike Frysinger35247af2012-11-16 18:58:06 -0500653def ExpandTargets(targets_wanted):
654 """Expand any possible toolchain aliases into full targets
655
656 This will expand 'all' and 'sdk' into the respective toolchain tuples.
657
658 Args:
659 targets_wanted: The targets specified by the user.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500660
Mike Frysinger35247af2012-11-16 18:58:06 -0500661 Returns:
Gilad Arnold8195b532015-04-07 10:56:30 +0300662 Dictionary of concrete targets and their toolchain tuples.
Mike Frysinger35247af2012-11-16 18:58:06 -0500663 """
Mike Frysinger35247af2012-11-16 18:58:06 -0500664 targets_wanted = set(targets_wanted)
Don Garrettc0c74002015-10-09 12:58:19 -0700665 if targets_wanted == set(['boards']):
666 # Only pull targets from the included boards.
Gilad Arnold8195b532015-04-07 10:56:30 +0300667 return {}
668
669 all_targets = toolchain.GetAllTargets()
Mike Frysinger35247af2012-11-16 18:58:06 -0500670 if targets_wanted == set(['all']):
Gilad Arnold8195b532015-04-07 10:56:30 +0300671 return all_targets
672 if targets_wanted == set(['sdk']):
Mike Frysinger35247af2012-11-16 18:58:06 -0500673 # Filter out all the non-sdk toolchains as we don't want to mess
674 # with those in all of our builds.
Gilad Arnold8195b532015-04-07 10:56:30 +0300675 return toolchain.FilterToolchains(all_targets, 'sdk', True)
676
677 # Verify user input.
678 nonexistent = targets_wanted.difference(all_targets)
679 if nonexistent:
Mike Frysingercd790662019-10-17 00:23:13 -0400680 raise ValueError('Invalid targets: %s' % (','.join(nonexistent),))
Gilad Arnold8195b532015-04-07 10:56:30 +0300681 return {t: all_targets[t] for t in targets_wanted}
Mike Frysinger35247af2012-11-16 18:58:06 -0500682
683
David Jamesf8c672f2012-11-06 13:38:11 -0800684def UpdateToolchains(usepkg, deleteold, hostonly, reconfig,
Don Garrettc0c74002015-10-09 12:58:19 -0700685 targets_wanted, boards_wanted, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100686 """Performs all steps to create a synchronized toolchain enviroment.
687
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500688 Args:
689 usepkg: Use prebuilt packages
690 deleteold: Unmerge deprecated packages
691 hostonly: Only setup the host toolchain
692 reconfig: Reload crossdev config and reselect toolchains
693 targets_wanted: All the targets to update
694 boards_wanted: Load targets from these boards
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700695 root: The root in which to install the toolchains.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100696 """
David Jamesf8c672f2012-11-06 13:38:11 -0800697 targets, crossdev_targets, reconfig_targets = {}, {}, {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100698 if not hostonly:
699 # For hostonly, we can skip most of the below logic, much of which won't
700 # work on bare systems where this is useful.
Mike Frysinger35247af2012-11-16 18:58:06 -0500701 targets = ExpandTargets(targets_wanted)
Mike Frysinger7ccee992012-06-01 21:27:59 -0400702
Don Garrettc0c74002015-10-09 12:58:19 -0700703 # Now re-add any targets that might be from this board. This is to
Gilad Arnold8195b532015-04-07 10:56:30 +0300704 # allow unofficial boards to declare their own toolchains.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400705 for board in boards_wanted:
David James27ac4ae2012-12-03 23:16:15 -0800706 targets.update(toolchain.GetToolchainsForBoard(board))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100707
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100708 # First check and initialize all cross targets that need to be.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400709 for target in targets:
710 if TargetIsInitialized(target):
711 reconfig_targets[target] = targets[target]
712 else:
713 crossdev_targets[target] = targets[target]
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100714 if crossdev_targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400715 logging.info('The following targets need to be re-initialized:')
716 logging.info('%s', crossdev_targets)
David James66a09c42012-11-05 13:31:38 -0800717 Crossdev.UpdateTargets(crossdev_targets, usepkg)
Zdenek Behan8be29ba2012-05-29 23:10:34 +0200718 # Those that were not initialized may need a config update.
David James66a09c42012-11-05 13:31:38 -0800719 Crossdev.UpdateTargets(reconfig_targets, usepkg, config_only=True)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100720
Mike Frysinger66814c32017-10-09 18:11:46 -0400721 # If we're building a subset of toolchains for a board, we might not have
722 # all the tuples that the packages expect. We don't define the "full" set
723 # of tuples currently other than "whatever the full sdk has normally".
724 if usepkg or set(('all', 'sdk')) & targets_wanted:
725 # Since we have cross-compilers now, we can update these packages.
726 targets['host-post-cross'] = {}
Mike Frysinger785b0c32017-09-13 01:35:59 -0400727
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100728 # We want host updated.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400729 targets['host'] = {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100730
731 # Now update all packages.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700732 if UpdateTargets(targets, usepkg, root=root) or crossdev_targets or reconfig:
733 SelectActiveToolchains(targets, CONFIG_TARGET_SUFFIXES, root=root)
David James7ec5efc2012-11-06 09:39:49 -0800734
735 if deleteold:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700736 CleanTargets(targets, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100737
Mike Frysingerc880a962013-11-08 13:59:06 -0500738 # Now that we've cleared out old versions, see if we need to rebuild
739 # anything. Can't do this earlier as it might not be broken.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700740 RebuildLibtool(root=root)
Mike Frysingerc880a962013-11-08 13:59:06 -0500741
Zdenek Behan508dcce2011-12-05 15:39:32 +0100742
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -0700743def ShowConfig(name):
744 """Show the toolchain tuples used by |name|
Mike Frysinger35247af2012-11-16 18:58:06 -0500745
746 Args:
Don Garrettc0c74002015-10-09 12:58:19 -0700747 name: The board name to query.
Mike Frysinger35247af2012-11-16 18:58:06 -0500748 """
Don Garrettc0c74002015-10-09 12:58:19 -0700749 toolchains = toolchain.GetToolchainsForBoard(name)
Mike Frysinger35247af2012-11-16 18:58:06 -0500750 # Make sure we display the default toolchain first.
Mike Frysinger3bba5032016-09-20 14:15:04 -0400751 # Note: Do not use logging here as this is meant to be used by other tools.
Mike Frysinger383367e2014-09-16 15:06:17 -0400752 print(','.join(
Mike Frysinger818d9632019-08-24 14:43:05 -0400753 list(toolchain.FilterToolchains(toolchains, 'default', True)) +
754 list(toolchain.FilterToolchains(toolchains, 'default', False))))
Mike Frysinger35247af2012-11-16 18:58:06 -0500755
756
Mike Frysinger35247af2012-11-16 18:58:06 -0500757def GeneratePathWrapper(root, wrappath, path):
758 """Generate a shell script to execute another shell script
759
760 Since we can't symlink a wrapped ELF (see GenerateLdsoWrapper) because the
761 argv[0] won't be pointing to the correct path, generate a shell script that
762 just executes another program with its full path.
763
764 Args:
765 root: The root tree to generate scripts inside of
766 wrappath: The full path (inside |root|) to create the wrapper
767 path: The target program which this wrapper will execute
768 """
769 replacements = {
770 'path': path,
771 'relroot': os.path.relpath('/', os.path.dirname(wrappath)),
772 }
Takuto Ikuta58403972018-08-16 18:52:51 +0900773
774 # Do not use exec here, because exec invokes script with absolute path in
775 # argv0. Keeping relativeness allows us to remove abs path from compile result
776 # and leads directory independent build cache sharing in some distributed
777 # build system.
Mike Frysinger35247af2012-11-16 18:58:06 -0500778 wrapper = """#!/bin/sh
Takuto Ikuta58403972018-08-16 18:52:51 +0900779basedir=$(dirname "$0")
780"${basedir}/%(relroot)s%(path)s" "$@"
781exit "$?"
Mike Frysinger35247af2012-11-16 18:58:06 -0500782""" % replacements
783 root_wrapper = root + wrappath
784 if os.path.islink(root_wrapper):
785 os.unlink(root_wrapper)
786 else:
787 osutils.SafeMakedirs(os.path.dirname(root_wrapper))
788 osutils.WriteFile(root_wrapper, wrapper)
Mike Frysinger60ec1012013-10-21 00:11:10 -0400789 os.chmod(root_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -0500790
791
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -0700792def FixClangXXWrapper(root, path):
793 """Fix wrapper shell scripts and symlinks for invoking clang++
794
795 In a typical installation, clang++ symlinks to clang, which symlinks to the
796 elf executable. The executable distinguishes between clang and clang++ based
797 on argv[0].
798
799 When invoked through the LdsoWrapper, argv[0] always contains the path to the
800 executable elf file, making clang/clang++ invocations indistinguishable.
801
802 This function detects if the elf executable being wrapped is clang-X.Y, and
803 fixes wrappers/symlinks as necessary so that clang++ will work correctly.
804
805 The calling sequence now becomes:
806 -) clang++ invocation turns into clang++-3.9 (which is a copy of clang-3.9,
807 the Ldsowrapper).
808 -) clang++-3.9 uses the Ldso to invoke clang++-3.9.elf, which is a symlink
809 to the original clang-3.9 elf.
810 -) The difference this time is that inside the elf file execution, $0 is
811 set as .../usr/bin/clang++-3.9.elf, which contains 'clang++' in the name.
812
Manoj Guptaae268142018-04-27 23:28:36 -0700813 Update: Starting since clang 7, the clang and clang++ are symlinks to
814 clang-7 binary, not clang-7.0. The pattern match is extended to handle
815 both clang-7 and clang-7.0 cases for now. (https://crbug.com/837889)
816
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -0700817 Args:
818 root: The root tree to generate scripts / symlinks inside of
819 path: The target elf for which LdsoWrapper was created
820 """
Manoj Guptaae268142018-04-27 23:28:36 -0700821 if re.match(r'/usr/bin/clang-\d+(\.\d+)*$', path):
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -0700822 logging.info('fixing clang++ invocation for %s', path)
823 clangdir = os.path.dirname(root + path)
824 clang = os.path.basename(path)
825 clangxx = clang.replace('clang', 'clang++')
826
827 # Create a symlink clang++-X.Y.elf to point to clang-X.Y.elf
828 os.symlink(clang + '.elf', os.path.join(clangdir, clangxx + '.elf'))
829
830 # Create a hardlink clang++-X.Y pointing to clang-X.Y
831 os.link(os.path.join(clangdir, clang), os.path.join(clangdir, clangxx))
832
833 # Adjust the clang++ symlink to point to clang++-X.Y
834 os.unlink(os.path.join(clangdir, 'clang++'))
835 os.symlink(clangxx, os.path.join(clangdir, 'clang++'))
836
837
Mike Frysinger35247af2012-11-16 18:58:06 -0500838def FileIsCrosSdkElf(elf):
839 """Determine if |elf| is an ELF that we execute in the cros_sdk
840
841 We don't need this to be perfect, just quick. It makes sure the ELF
842 is a 64bit LSB x86_64 ELF. That is the native type of cros_sdk.
843
844 Args:
845 elf: The file to check
Mike Frysinger1a736a82013-12-12 01:50:59 -0500846
Mike Frysinger35247af2012-11-16 18:58:06 -0500847 Returns:
848 True if we think |elf| is a native ELF
849 """
Mike Frysinger4a12bf12019-12-04 04:20:10 -0500850 with open(elf, 'rb') as f:
Mike Frysinger35247af2012-11-16 18:58:06 -0500851 data = f.read(20)
852 # Check the magic number, EI_CLASS, EI_DATA, and e_machine.
Mike Frysinger4a12bf12019-12-04 04:20:10 -0500853 return (data[0:4] == b'\x7fELF' and
Mike Frysingerdd34dfe2019-12-10 16:25:47 -0500854 data[4:5] == b'\x02' and
855 data[5:6] == b'\x01' and
856 data[18:19] == b'\x3e')
Mike Frysinger35247af2012-11-16 18:58:06 -0500857
858
859def IsPathPackagable(ptype, path):
860 """Should the specified file be included in a toolchain package?
861
862 We only need to handle files as we'll create dirs as we need them.
863
864 Further, trim files that won't be useful:
865 - non-english translations (.mo) since it'd require env vars
866 - debug files since these are for the host compiler itself
867 - info/man pages as they're big, and docs are online, and the
868 native docs should work fine for the most part (`man gcc`)
869
870 Args:
871 ptype: A string describing the path type (i.e. 'file' or 'dir' or 'sym')
872 path: The full path to inspect
Mike Frysinger1a736a82013-12-12 01:50:59 -0500873
Mike Frysinger35247af2012-11-16 18:58:06 -0500874 Returns:
875 True if we want to include this path in the package
876 """
877 return not (ptype in ('dir',) or
878 path.startswith('/usr/lib/debug/') or
879 os.path.splitext(path)[1] == '.mo' or
880 ('/man/' in path or '/info/' in path))
881
882
883def ReadlinkRoot(path, root):
884 """Like os.readlink(), but relative to a |root|
885
886 Args:
887 path: The symlink to read
888 root: The path to use for resolving absolute symlinks
Mike Frysinger1a736a82013-12-12 01:50:59 -0500889
Mike Frysinger35247af2012-11-16 18:58:06 -0500890 Returns:
891 A fully resolved symlink path
892 """
893 while os.path.islink(root + path):
894 path = os.path.join(os.path.dirname(path), os.readlink(root + path))
895 return path
896
897
898def _GetFilesForTarget(target, root='/'):
899 """Locate all the files to package for |target|
900
901 This does not cover ELF dependencies.
902
903 Args:
904 target: The toolchain target name
905 root: The root path to pull all packages from
Mike Frysinger1a736a82013-12-12 01:50:59 -0500906
Mike Frysinger35247af2012-11-16 18:58:06 -0500907 Returns:
908 A tuple of a set of all packable paths, and a set of all paths which
909 are also native ELFs
910 """
911 paths = set()
912 elfs = set()
913
914 # Find all the files owned by the packages for this target.
915 for pkg in GetTargetPackages(target):
Mike Frysinger35247af2012-11-16 18:58:06 -0500916
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700917 # Skip Go compiler from redistributable packages.
918 # The "go" executable has GOROOT=/usr/lib/go/${CTARGET} hardcoded
919 # into it. Due to this, the toolchain cannot be unpacked anywhere
920 # else and be readily useful. To enable packaging Go, we need to:
921 # -) Tweak the wrappers/environment to override GOROOT
922 # automatically based on the unpack location.
923 # -) Make sure the ELF dependency checking and wrapping logic
924 # below skips the Go toolchain executables and libraries.
925 # -) Make sure the packaging process maintains the relative
926 # timestamps of precompiled standard library packages.
927 # (see dev-lang/go ebuild for details).
928 if pkg == 'ex_go':
929 continue
930
Yunlian Jiang36f35242018-04-27 10:18:40 -0700931 # Use armv7a-cros-linux-gnueabi/compiler-rt for
932 # armv7a-cros-linux-gnueabihf/compiler-rt.
933 # Currently the armv7a-cros-linux-gnueabi is actually
934 # the same as armv7a-cros-linux-gnueabihf with different names.
935 # Because of that, for compiler-rt, it generates the same binary in
936 # the same location. To avoid the installation conflict, we do not
937 # install anything for 'armv7a-cros-linux-gnueabihf'. This would cause
938 # problem if other people try to use standalone armv7a-cros-linux-gnueabihf
939 # toolchain.
940 if 'compiler-rt' in pkg and 'armv7a-cros-linux-gnueabi' in target:
941 atom = GetPortagePackage(target, pkg)
942 cat, pn = atom.split('/')
943 ver = GetInstalledPackageVersions(atom, root=root)[0]
Yunlian Jiang36f35242018-04-27 10:18:40 -0700944 dblink = portage.dblink(cat, pn + '-' + ver, myroot=root,
945 settings=portage.settings)
946 contents = dblink.getcontents()
947 if not contents:
948 if 'hf' in target:
949 new_target = 'armv7a-cros-linux-gnueabi'
950 else:
951 new_target = 'armv7a-cros-linux-gnueabihf'
952 atom = GetPortagePackage(new_target, pkg)
953 else:
954 atom = GetPortagePackage(target, pkg)
955
Mike Frysinger35247af2012-11-16 18:58:06 -0500956 cat, pn = atom.split('/')
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700957 ver = GetInstalledPackageVersions(atom, root=root)[0]
Ralph Nathan03047282015-03-23 11:09:32 -0700958 logging.info('packaging %s-%s', atom, ver)
Mike Frysinger35247af2012-11-16 18:58:06 -0500959
Mike Frysinger35247af2012-11-16 18:58:06 -0500960 dblink = portage.dblink(cat, pn + '-' + ver, myroot=root,
961 settings=portage.settings)
962 contents = dblink.getcontents()
963 for obj in contents:
964 ptype = contents[obj][0]
965 if not IsPathPackagable(ptype, obj):
966 continue
967
968 if ptype == 'obj':
969 # For native ELFs, we need to pull in their dependencies too.
970 if FileIsCrosSdkElf(obj):
Mike Frysinger60a2f6c2019-12-04 04:18:58 -0500971 logging.debug('Adding ELF %s', obj)
Mike Frysinger35247af2012-11-16 18:58:06 -0500972 elfs.add(obj)
Mike Frysinger60a2f6c2019-12-04 04:18:58 -0500973 logging.debug('Adding path %s', obj)
Mike Frysinger35247af2012-11-16 18:58:06 -0500974 paths.add(obj)
975
976 return paths, elfs
977
978
979def _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500980 path_rewrite_func=lambda x: x, root='/'):
Mike Frysinger35247af2012-11-16 18:58:06 -0500981 """Link in all packable files and their runtime dependencies
982
983 This also wraps up executable ELFs with helper scripts.
984
985 Args:
986 output_dir: The output directory to store files
987 paths: All the files to include
988 elfs: All the files which are ELFs (a subset of |paths|)
989 ldpaths: A dict of static ldpath information
990 path_rewrite_func: User callback to rewrite paths in output_dir
991 root: The root path to pull all packages/files from
992 """
993 # Link in all the files.
Mike Frysinger221bd822017-09-29 02:51:47 -0400994 sym_paths = {}
Mike Frysinger35247af2012-11-16 18:58:06 -0500995 for path in paths:
996 new_path = path_rewrite_func(path)
Mike Frysinger60a2f6c2019-12-04 04:18:58 -0500997 logging.debug('Transformed %s to %s', path, new_path)
Mike Frysinger35247af2012-11-16 18:58:06 -0500998 dst = output_dir + new_path
999 osutils.SafeMakedirs(os.path.dirname(dst))
1000
1001 # Is this a symlink which we have to rewrite or wrap?
1002 # Delay wrap check until after we have created all paths.
1003 src = root + path
1004 if os.path.islink(src):
1005 tgt = os.readlink(src)
1006 if os.path.sep in tgt:
Mike Frysinger221bd822017-09-29 02:51:47 -04001007 sym_paths[lddtree.normpath(ReadlinkRoot(src, root))] = new_path
Mike Frysinger35247af2012-11-16 18:58:06 -05001008
1009 # Rewrite absolute links to relative and then generate the symlink
1010 # ourselves. All other symlinks can be hardlinked below.
1011 if tgt[0] == '/':
1012 tgt = os.path.relpath(tgt, os.path.dirname(new_path))
1013 os.symlink(tgt, dst)
1014 continue
1015
Mike Frysinger60a2f6c2019-12-04 04:18:58 -05001016 logging.debug('Linking path %s -> %s', src, dst)
Mike Frysinger35247af2012-11-16 18:58:06 -05001017 os.link(src, dst)
1018
Mike Frysinger35247af2012-11-16 18:58:06 -05001019 # Locate all the dependencies for all the ELFs. Stick them all in the
1020 # top level "lib" dir to make the wrapper simpler. This exact path does
1021 # not matter since we execute ldso directly, and we tell the ldso the
1022 # exact path to search for its libraries.
1023 libdir = os.path.join(output_dir, 'lib')
1024 osutils.SafeMakedirs(libdir)
1025 donelibs = set()
Mike Frysinger9fe02342019-12-12 17:52:53 -05001026 basenamelibs = set()
Mike Frysinger4331fc62017-09-28 14:03:25 -04001027 glibc_re = re.compile(r'/lib(c|pthread)-[0-9.]+\.so$')
Mike Frysinger35247af2012-11-16 18:58:06 -05001028 for elf in elfs:
Mike Frysingerea7688e2014-07-31 22:40:33 -04001029 e = lddtree.ParseELF(elf, root=root, ldpaths=ldpaths)
Mike Frysinger60a2f6c2019-12-04 04:18:58 -05001030 logging.debug('Parsed elf %s data: %s', elf, e)
Mike Frysinger35247af2012-11-16 18:58:06 -05001031 interp = e['interp']
Yunlian Jiang196e8f42017-09-20 12:29:47 -07001032 # Do not create wrapper for libc. crbug.com/766827
1033 if interp and not glibc_re.search(elf):
Mike Frysinger35247af2012-11-16 18:58:06 -05001034 # Generate a wrapper if it is executable.
Mike Frysingerc2ec0902013-03-26 01:28:45 -04001035 interp = os.path.join('/lib', os.path.basename(interp))
1036 lddtree.GenerateLdsoWrapper(output_dir, path_rewrite_func(elf), interp,
1037 libpaths=e['rpath'] + e['runpath'])
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -07001038 FixClangXXWrapper(output_dir, path_rewrite_func(elf))
Mike Frysinger35247af2012-11-16 18:58:06 -05001039
Mike Frysinger221bd822017-09-29 02:51:47 -04001040 # Wrap any symlinks to the wrapper.
1041 if elf in sym_paths:
1042 link = sym_paths[elf]
1043 GeneratePathWrapper(output_dir, link, elf)
1044
Mike Frysinger9fe02342019-12-12 17:52:53 -05001045 # TODO(crbug.com/917193): Drop this hack once libopcodes linkage is fixed.
1046 if os.path.basename(elf).startswith('libopcodes-'):
1047 continue
Mike Frysinger35247af2012-11-16 18:58:06 -05001048
Mike Frysinger9fe02342019-12-12 17:52:53 -05001049 for lib, lib_data in e['libs'].items():
Mike Frysinger35247af2012-11-16 18:58:06 -05001050 src = path = lib_data['path']
1051 if path is None:
Ralph Nathan446aee92015-03-23 14:44:56 -07001052 logging.warning('%s: could not locate %s', elf, lib)
Mike Frysinger35247af2012-11-16 18:58:06 -05001053 continue
Mike Frysinger9fe02342019-12-12 17:52:53 -05001054
1055 # No need to try and copy the same source lib multiple times.
1056 if path in donelibs:
1057 continue
1058 donelibs.add(path)
1059
1060 # Die if we try to normalize different source libs with the same basename.
1061 if lib in basenamelibs:
1062 logging.error('Multiple sources detected for %s:\n new: %s\n old: %s',
1063 os.path.join('/lib', lib), path,
1064 ' '.join(x for x in donelibs
1065 if x != path and os.path.basename(x) == lib))
1066 # TODO(crbug.com/917193): Make this fatal.
1067 # cros_build_lib.Die('Unable to resolve lib conflicts')
1068 continue
1069 basenamelibs.add(lib)
Mike Frysinger35247af2012-11-16 18:58:06 -05001070
1071 # Needed libs are the SONAME, but that is usually a symlink, not a
1072 # real file. So link in the target rather than the symlink itself.
1073 # We have to walk all the possible symlinks (SONAME could point to a
1074 # symlink which points to a symlink), and we have to handle absolute
1075 # ourselves (since we have a "root" argument).
1076 dst = os.path.join(libdir, os.path.basename(path))
1077 src = ReadlinkRoot(src, root)
1078
Mike Frysinger60a2f6c2019-12-04 04:18:58 -05001079 logging.debug('Linking lib %s -> %s', root + src, dst)
Mike Frysinger35247af2012-11-16 18:58:06 -05001080 os.link(root + src, dst)
1081
1082
1083def _EnvdGetVar(envd, var):
1084 """Given a Gentoo env.d file, extract a var from it
1085
1086 Args:
1087 envd: The env.d file to load (may be a glob path)
1088 var: The var to extract
Mike Frysinger1a736a82013-12-12 01:50:59 -05001089
Mike Frysinger35247af2012-11-16 18:58:06 -05001090 Returns:
1091 The value of |var|
1092 """
1093 envds = glob.glob(envd)
1094 assert len(envds) == 1, '%s: should have exactly 1 env.d file' % envd
1095 envd = envds[0]
Mike Frysingere652ba12019-09-08 00:57:43 -04001096 return key_value_store.LoadFile(envd)[var]
Mike Frysinger35247af2012-11-16 18:58:06 -05001097
1098
1099def _ProcessBinutilsConfig(target, output_dir):
1100 """Do what binutils-config would have done"""
1101 binpath = os.path.join('/bin', target + '-')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001102
1103 # Locate the bin dir holding the gold linker.
1104 binutils_bin_path = os.path.join(output_dir, 'usr', toolchain.GetHostTuple(),
1105 target, 'binutils-bin')
1106 globpath = os.path.join(binutils_bin_path, '*-gold')
Mike Frysinger35247af2012-11-16 18:58:06 -05001107 srcpath = glob.glob(globpath)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001108 if not srcpath:
1109 # Maybe this target doesn't support gold.
1110 globpath = os.path.join(binutils_bin_path, '*')
1111 srcpath = glob.glob(globpath)
1112 assert len(srcpath) == 1, ('%s: matched more than one path (but not *-gold)'
1113 % globpath)
1114 srcpath = srcpath[0]
1115 ld_path = os.path.join(srcpath, 'ld')
1116 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1117 ld_path = os.path.join(srcpath, 'ld.bfd')
1118 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1119 ld_path = os.path.join(srcpath, 'ld.gold')
1120 assert not os.path.exists(ld_path), ('%s: exists, but gold dir does not!'
1121 % ld_path)
1122
1123 # Nope, no gold support to be found.
1124 gold_supported = False
Ralph Nathan446aee92015-03-23 14:44:56 -07001125 logging.warning('%s: binutils lacks support for the gold linker', target)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001126 else:
1127 assert len(srcpath) == 1, '%s: did not match exactly 1 path' % globpath
Mike Frysinger78b7a812014-11-26 19:45:23 -05001128 srcpath = srcpath[0]
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001129
Rahul Chaudhry4891b4d2017-03-08 10:31:27 -08001130 # Package the binutils-bin directory without the '-gold' suffix
1131 # if gold is not enabled as the default linker for this target.
1132 gold_supported = CONFIG_TARGET_SUFFIXES['binutils'].get(target) == '-gold'
1133 if not gold_supported:
1134 srcpath = srcpath[:-len('-gold')]
1135 ld_path = os.path.join(srcpath, 'ld')
1136 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1137
Mike Frysinger78b7a812014-11-26 19:45:23 -05001138 srcpath = srcpath[len(output_dir):]
Mike Frysinger35247af2012-11-16 18:58:06 -05001139 gccpath = os.path.join('/usr', 'libexec', 'gcc')
1140 for prog in os.listdir(output_dir + srcpath):
1141 # Skip binaries already wrapped.
1142 if not prog.endswith('.real'):
1143 GeneratePathWrapper(output_dir, binpath + prog,
1144 os.path.join(srcpath, prog))
1145 GeneratePathWrapper(output_dir, os.path.join(gccpath, prog),
1146 os.path.join(srcpath, prog))
1147
David James27ac4ae2012-12-03 23:16:15 -08001148 libpath = os.path.join('/usr', toolchain.GetHostTuple(), target, 'lib')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001149 envd = os.path.join(output_dir, 'etc', 'env.d', 'binutils', '*')
1150 if gold_supported:
1151 envd += '-gold'
Rahul Chaudhry4891b4d2017-03-08 10:31:27 -08001152 else:
1153 # If gold is not enabled as the default linker and 2 env.d
1154 # files exist, pick the one without the '-gold' suffix.
1155 envds = sorted(glob.glob(envd))
1156 if len(envds) == 2 and envds[1] == envds[0] + '-gold':
1157 envd = envds[0]
Mike Frysinger35247af2012-11-16 18:58:06 -05001158 srcpath = _EnvdGetVar(envd, 'LIBPATH')
1159 os.symlink(os.path.relpath(srcpath, os.path.dirname(libpath)),
1160 output_dir + libpath)
1161
1162
1163def _ProcessGccConfig(target, output_dir):
1164 """Do what gcc-config would have done"""
1165 binpath = '/bin'
1166 envd = os.path.join(output_dir, 'etc', 'env.d', 'gcc', '*')
1167 srcpath = _EnvdGetVar(envd, 'GCC_PATH')
1168 for prog in os.listdir(output_dir + srcpath):
1169 # Skip binaries already wrapped.
1170 if (not prog.endswith('.real') and
1171 not prog.endswith('.elf') and
1172 prog.startswith(target)):
1173 GeneratePathWrapper(output_dir, os.path.join(binpath, prog),
1174 os.path.join(srcpath, prog))
1175 return srcpath
1176
1177
Frank Henigman179ec7c2015-02-06 03:01:09 -05001178def _ProcessSysrootWrappers(_target, output_dir, srcpath):
1179 """Remove chroot-specific things from our sysroot wrappers"""
Mike Frysinger35247af2012-11-16 18:58:06 -05001180 # Disable ccache since we know it won't work outside of chroot.
Tobias Boschddd16492019-08-14 09:29:54 -07001181
Tobias Boschddd16492019-08-14 09:29:54 -07001182 # Use the version of the wrapper that does not use ccache.
Frank Henigman179ec7c2015-02-06 03:01:09 -05001183 for sysroot_wrapper in glob.glob(os.path.join(
Tobias Boschddd16492019-08-14 09:29:54 -07001184 output_dir + srcpath, 'sysroot_wrapper*.ccache')):
1185 # Can't update the wrapper in place to not affect the chroot,
1186 # but only the extracted toolchain.
1187 os.unlink(sysroot_wrapper)
1188 shutil.copy(sysroot_wrapper[:-6] + 'noccache', sysroot_wrapper)
Tobias Bosch7bc907a2019-10-09 11:52:40 -07001189 shutil.copy(sysroot_wrapper[:-6] + 'noccache.elf', sysroot_wrapper + '.elf')
Mike Frysinger35247af2012-11-16 18:58:06 -05001190
1191
Yunlian Jiang5ad6b512017-09-20 09:27:45 -07001192def _CreateMainLibDir(target, output_dir):
1193 """Create some lib dirs so that compiler can get the right Gcc paths"""
1194 osutils.SafeMakedirs(os.path.join(output_dir, 'usr', target, 'lib'))
1195 osutils.SafeMakedirs(os.path.join(output_dir, 'usr', target, 'usr/lib'))
1196
1197
Mike Frysinger35247af2012-11-16 18:58:06 -05001198def _ProcessDistroCleanups(target, output_dir):
1199 """Clean up the tree and remove all distro-specific requirements
1200
1201 Args:
1202 target: The toolchain target name
1203 output_dir: The output directory to clean up
1204 """
1205 _ProcessBinutilsConfig(target, output_dir)
1206 gcc_path = _ProcessGccConfig(target, output_dir)
Frank Henigman179ec7c2015-02-06 03:01:09 -05001207 _ProcessSysrootWrappers(target, output_dir, gcc_path)
Yunlian Jiang5ad6b512017-09-20 09:27:45 -07001208 _CreateMainLibDir(target, output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001209
1210 osutils.RmDir(os.path.join(output_dir, 'etc'))
1211
1212
1213def CreatePackagableRoot(target, output_dir, ldpaths, root='/'):
1214 """Setup a tree from the packages for the specified target
1215
1216 This populates a path with all the files from toolchain packages so that
1217 a tarball can easily be generated from the result.
1218
1219 Args:
1220 target: The target to create a packagable root from
1221 output_dir: The output directory to place all the files
1222 ldpaths: A dict of static ldpath information
1223 root: The root path to pull all packages/files from
1224 """
1225 # Find all the files owned by the packages for this target.
1226 paths, elfs = _GetFilesForTarget(target, root=root)
1227
1228 # Link in all the package's files, any ELF dependencies, and wrap any
1229 # executable ELFs with helper scripts.
1230 def MoveUsrBinToBin(path):
Han Shen699ea192016-03-02 10:42:47 -08001231 """Move /usr/bin to /bin so people can just use that toplevel dir
1232
1233 Note we do not apply this to clang - there is correlation between clang's
1234 search path for libraries / inclusion and its installation path.
1235 """
1236 if path.startswith('/usr/bin/') and path.find('clang') == -1:
1237 return path[4:]
1238 return path
Mike Frysinger35247af2012-11-16 18:58:06 -05001239 _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
1240 path_rewrite_func=MoveUsrBinToBin, root=root)
1241
1242 # The packages, when part of the normal distro, have helper scripts
1243 # that setup paths and such. Since we are making this standalone, we
1244 # need to preprocess all that ourselves.
1245 _ProcessDistroCleanups(target, output_dir)
1246
1247
1248def CreatePackages(targets_wanted, output_dir, root='/'):
1249 """Create redistributable cross-compiler packages for the specified targets
1250
1251 This creates toolchain packages that should be usable in conjunction with
1252 a downloaded sysroot (created elsewhere).
1253
1254 Tarballs (one per target) will be created in $PWD.
1255
1256 Args:
Don Garrett25f309a2014-03-19 14:02:12 -07001257 targets_wanted: The targets to package up.
1258 output_dir: The directory to put the packages in.
1259 root: The root path to pull all packages/files from.
Mike Frysinger35247af2012-11-16 18:58:06 -05001260 """
Ralph Nathan03047282015-03-23 11:09:32 -07001261 logging.info('Writing tarballs to %s', output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001262 osutils.SafeMakedirs(output_dir)
1263 ldpaths = lddtree.LoadLdpaths(root)
1264 targets = ExpandTargets(targets_wanted)
1265
Mike Frysinger221bd822017-09-29 02:51:47 -04001266 with osutils.TempDir(prefix='create-packages') as tempdir:
1267 logging.debug('Using tempdir: %s', tempdir)
1268
Mike Frysinger35247af2012-11-16 18:58:06 -05001269 # We have to split the root generation from the compression stages. This is
1270 # because we hardlink in all the files (to avoid overhead of reading/writing
1271 # the copies multiple times). But tar gets angry if a file's hardlink count
1272 # changes from when it starts reading a file to when it finishes.
1273 with parallel.BackgroundTaskRunner(CreatePackagableRoot) as queue:
1274 for target in targets:
1275 output_target_dir = os.path.join(tempdir, target)
1276 queue.put([target, output_target_dir, ldpaths, root])
1277
1278 # Build the tarball.
1279 with parallel.BackgroundTaskRunner(cros_build_lib.CreateTarball) as queue:
1280 for target in targets:
1281 tar_file = os.path.join(output_dir, target + '.tar.xz')
1282 queue.put([tar_file, os.path.join(tempdir, target)])
1283
1284
Mike Frysinger07534cf2017-09-12 17:40:21 -04001285def GetParser():
1286 """Return a command line parser."""
Mike Frysinger0c808452014-11-06 17:30:23 -05001287 parser = commandline.ArgumentParser(description=__doc__)
1288 parser.add_argument('-u', '--nousepkg',
1289 action='store_false', dest='usepkg', default=True,
1290 help='Use prebuilt packages if possible')
1291 parser.add_argument('-d', '--deleteold',
1292 action='store_true', dest='deleteold', default=False,
1293 help='Unmerge deprecated packages')
1294 parser.add_argument('-t', '--targets',
1295 dest='targets', default='sdk',
Mike Frysinger80de5012019-08-01 14:10:53 -04001296 help='Comma separated list of tuples. Special keywords '
Don Garrettc0c74002015-10-09 12:58:19 -07001297 "'host', 'sdk', 'boards', and 'all' are "
Gilad Arnold8195b532015-04-07 10:56:30 +03001298 "allowed. Defaults to 'sdk'.")
1299 parser.add_argument('--include-boards', default='', metavar='BOARDS',
1300 help='Comma separated list of boards whose toolchains we '
1301 'will always include. Default: none')
Mike Frysinger0c808452014-11-06 17:30:23 -05001302 parser.add_argument('--hostonly',
1303 dest='hostonly', default=False, action='store_true',
1304 help='Only setup the host toolchain. '
1305 'Useful for bootstrapping chroot')
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001306 parser.add_argument('--show-board-cfg', '--show-cfg',
1307 dest='cfg_name', default=None,
Don Garrettc0c74002015-10-09 12:58:19 -07001308 help='Board to list toolchains tuples for')
Mike Frysinger91f52882017-09-13 00:16:58 -04001309 parser.add_argument('--show-packages', default=None,
1310 help='List all packages the specified target uses')
Mike Frysinger0c808452014-11-06 17:30:23 -05001311 parser.add_argument('--create-packages',
1312 action='store_true', default=False,
1313 help='Build redistributable packages')
1314 parser.add_argument('--output-dir', default=os.getcwd(), type='path',
1315 help='Output directory')
1316 parser.add_argument('--reconfig', default=False, action='store_true',
1317 help='Reload crossdev config and reselect toolchains')
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001318 parser.add_argument('--sysroot', type='path',
1319 help='The sysroot in which to install the toolchains')
Mike Frysinger07534cf2017-09-12 17:40:21 -04001320 return parser
Zdenek Behan508dcce2011-12-05 15:39:32 +01001321
Mike Frysinger07534cf2017-09-12 17:40:21 -04001322
1323def main(argv):
1324 parser = GetParser()
Mike Frysinger0c808452014-11-06 17:30:23 -05001325 options = parser.parse_args(argv)
1326 options.Freeze()
Zdenek Behan508dcce2011-12-05 15:39:32 +01001327
Mike Frysinger35247af2012-11-16 18:58:06 -05001328 # Figure out what we're supposed to do and reject conflicting options.
Mike Frysinger91f52882017-09-13 00:16:58 -04001329 conflicting_options = (
1330 options.cfg_name,
1331 options.show_packages,
1332 options.create_packages,
1333 )
1334 if sum(bool(x) for x in conflicting_options) > 1:
1335 parser.error('conflicting options: create-packages & show-packages & '
1336 'show-board-cfg')
Mike Frysinger984d0622012-06-01 16:08:44 -04001337
Gilad Arnold8195b532015-04-07 10:56:30 +03001338 targets_wanted = set(options.targets.split(','))
1339 boards_wanted = (set(options.include_boards.split(','))
1340 if options.include_boards else set())
Mike Frysinger35247af2012-11-16 18:58:06 -05001341
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001342 if options.cfg_name:
1343 ShowConfig(options.cfg_name)
Mike Frysinger91f52882017-09-13 00:16:58 -04001344 elif options.show_packages is not None:
1345 cros_build_lib.AssertInsideChroot()
1346 target = options.show_packages
1347 Crossdev.Load(False)
1348 for package in GetTargetPackages(target):
1349 print(GetPortagePackage(target, package))
Mike Frysinger35247af2012-11-16 18:58:06 -05001350 elif options.create_packages:
1351 cros_build_lib.AssertInsideChroot()
1352 Crossdev.Load(False)
Gilad Arnold8195b532015-04-07 10:56:30 +03001353 CreatePackages(targets_wanted, options.output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001354 else:
1355 cros_build_lib.AssertInsideChroot()
1356 # This has to be always run as root.
1357 if os.geteuid() != 0:
1358 cros_build_lib.Die('this script must be run as root')
1359
1360 Crossdev.Load(options.reconfig)
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001361 root = options.sysroot or '/'
Mike Frysinger35247af2012-11-16 18:58:06 -05001362 UpdateToolchains(options.usepkg, options.deleteold, options.hostonly,
Gilad Arnold8195b532015-04-07 10:56:30 +03001363 options.reconfig, targets_wanted, boards_wanted,
Don Garrettc0c74002015-10-09 12:58:19 -07001364 root=root)
Mike Frysinger35247af2012-11-16 18:58:06 -05001365 Crossdev.Save()
1366
1367 return 0